GCM: How to send heartbeat to GCM server - java

I want to send a heartbeat from my application to the GCM server, so the connection will stay alive.
How can I do that, and how can I know the URL of my GCM server??
Thanks in advance!!

How to send the heartbeat
This class can sent the proper intents
public class GcmKeepAlive {
protected CountDownTimer timer;
protected Context mContext;
protected Intent gTalkHeartBeatIntent;
protected Intent mcsHeartBeatIntent;
public GcmKeepAlive(Context context) {
mContext = context;
gTalkHeartBeatIntent = new Intent(
"com.google.android.intent.action.GTALK_HEARTBEAT");
mcsHeartBeatIntent = new Intent(
"com.google.android.intent.action.MCS_HEARTBEAT");
}
public void broadcastIntents() {
System.out.println("sending heart beat to keep gcm alive");
mContext.sendBroadcast(gTalkHeartBeatIntent);
mContext.sendBroadcast(mcsHeartBeatIntent);
}
}
if you just want to send the heartbeat you can do the following in an Activity
GcmKeepAlive gcmKeepAlive = new GcmKeepAlive(this);
gcmKeepAlive.broadcastIntents();
I don't think you need to set any additional permissions for this but here are the gcm related permissions I have in my manifest
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name=your_package_name.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="your_package_name.permission.C2D_MESSAGE" />
One way to send the heartbeats on a regular basis
If you want to send them on a regular basis, here is how I am doing that:
public class GcmKeepAliveBroadcastReceiver extends BroadcastReceiver {
private GcmKeepAlive gcmKeepAlive;
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("inside gcm keep alive receiver");
gcmKeepAlive = new GcmKeepAlive(context);
gcmKeepAlive.broadcastIntents();
}
}
I also have a service that has an Dagger injected alarmmanger and pendingintent
#Inject AlarmManager alarmManager;
#Inject PendingIntent gcmKeepAlivePendingIntent;
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 4*60*1000, gcmKeepAlivePendingIntent);
Here is the section of the Dagger module that provides the alarm manager and pending intent.
There are several ways to have an alarm manager periodically call a method, so assuming you don't use Dagger, you should still be able to pull out the relevant parts. Your question was how to send the heartbeat, not how to use an alarm manager. There are lots of answers to that already so search on that.
#Provides PendingIntent provideGcmKeepAlivePendingIntent() {
System.out.println("pending intent provider");
Intent gcmKeepAliveIntent = new Intent("com.gmail.npnster.first_project.gcmKeepAlive");
return PendingIntent.getBroadcast(mContext, 0, gcmKeepAliveIntent, PendingIntent.FLAG_CANCEL_CURRENT);
}
#Provides AlarmManager provideGcmKeepAliveAlarmManager() {
return (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}

Related

Why isn't this simple broadcast receiver working?

I have two apps each with an accessibility service. The accessibility service of one app sends a broadcast and the accessibility service of the other app receives it.
Here is the service sending the broadcast:
Intent intent = new Intent();
intent.setAction("com.corps.mypackage");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //this is needed if broadcast not being sent from activity
sendBroadcast(intent);
And here is the service that receives the broadcast:
IntentFilter intentFilter = new IntentFilter("com.corps.mypackage");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do some things
}
};
registerReceiver(receiver, intentFilter);
The broadcast is not being received. What could be the reason?
As per the Android documentation:
Context-registered receivers receive broadcasts as long as their registering context is valid. For example, if you register within an Activity context, you receive broadcasts as long as the activity is not destroyed. If you register with the Application context, you receive broadcasts as long as the app is running.
Your receiving app's context is likely not valid. Consider using a manifest-declared receiver instead.

BroadcastReceiver doesn't work for the second time

I'm trying to schedule notifications with AlarmManager It works perfectly when I schedule one notification but when I schedule two notification, the first notification is okay but the second one not works.
I figured out opening the app after few minutes will notify the second notification. I think something is wrong with my BroadcastReceiver
MainActivity.java
Intent intent = new Intent(context,NotificationClass.class);
intent.putExtra("notification_id", id);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,id,intent,PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),pendingIntent);
Notification.java
public class NotificationClass extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra("notification_id",0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,"1")
.setContentTitle("Notification")
.setContentText("Content")
.setSmallIcon(R.drawable.notif_ic);
Notification notification = builder.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("1","test", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(id,notification);
}
AndroidManifest.xml
<receiver android:name=".NotificationClass" ></receiver>
I don't know what is wrong with my code. Can anybody help me with this?
Broadcast receiver to receive the data:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String alertMessage = intent.getStringExtra("type");
doNotificationAlertWorkHere(alertMessage);
}
};
Register & Unregister your broadcast to avoid static leaks.
via the Android manifest file. (Statically)
<receiver android:name="YourBroadcastReceiverName"> </receiver>
via the Context.registerReceiver() and Context.unregisterReceiver() methods. (Dynamically)
#Override
protected void onPause() {
super.onPause();
// unregister broadcast
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
#Override
protected void onResume() {
super.onResume();
// register broadcast
IntentFilter filter = new IntentFilter(Constants.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
}
Send Broadcast like:
// public static final String ACTION = "ALERT";
Intent intent = new Intent(Constants.ACTION);
intent.putExtra("type", "SUP BRO. Stay Inside");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Knowledge Note :- Broadcast receiver is like a Cannon-fire to score a hit, you have to determine what to fire (eg. msg), where to fire (eg. activity). Load & unload the cannon to score another hit. (eg. Register & Unregister)
I have tried it and it is working. Add your notification code inside onReceive.
Broadcast Receiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
/*
Your implementation
*/
}
}
Mainfest
<receiver
android:name=".AlarmReceiver"
android:exported="true"
android:enabled="true" />
Creating pending intents
val alarmManager = activity.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(activity.applicationContext, AlarmReceiver::class.java) // AlarmReceiver1 = broadcast receiver
val calendar = Calendar.getInstance()
calendar.timeInMillis = timeInMilliSeconds
val pendingIntent = PendingIntent.getBroadcast(activity, timeInMilliSeconds.toInt(), alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
First, make sure your notification Id is difference every single time you create a notification
Second, you miss tag intent-filter inside tag receive in manifest. pls check this https://developer.android.com/guide/components/broadcasts.
Hope this help!

How to ensure alarm fires even if app killed by system

I have application whose major functionality depend on alarm but alarm sometimes fired sometimes not, i red about it its says because system kills your app before alarm fires, how can i ensure alarm should fire even after application killed, here is how I'm setting alarm
public static void setEndAlarm(){
AlarmManager alarmManager = (AlarmManager) MyApplication.getContext().getSystemService(Context.ALARM_SERVICE);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.set(Calendar.HOUR_OF_DAY, SharedPrefUtils.getEndHour(MyApplication.getContext()));
time.set(Calendar.MINUTE, SharedPrefUtils.getEndMin(MyApplication.getContext()));
time.set(Calendar.SECOND, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), endPendingIntent(MyApplication.getContext()));
}
private static PendingIntent endPendingIntent(Context context){
Intent intent = new Intent(context, ClsEndBroadcastReciever.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 02, intent, PendingIntent.FLAG_ONE_SHOT);
return pendingIntent;
}
and the getting context like this:
public class MyApplication extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getContext() {
return mContext;
}
}
Broadcast Receiver:
public class ClsEndBroadcastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
FirebaseJobDispatcher dispatcher = new
FirebaseJobDispatcher(new GooglePlayDriver(context));
dispatcher.cancel("notification");
Toast.makeText(context, "End Time", Toast.LENGTH_SHORT).show();
}
}
I don't think you can reliably do this without system permissions.
Trying using IntentService and START_STICKY (https://developer.android.com/reference/android/app/Service.html) to ensure that the app does not get killed.
If you specify your BroadcastReceiver in Manifest then it will be called even if your app is not active write now.
Manifest
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<!-- Activities and Services -->
<receiver android:name=".AlarmBroadcastReceiver"/>
</application>
AlarmBroadcastReceiver
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// do what you want to do here.
// if the work load is heavy then launch service for it here
}
}

Starting service in android to read message after fixed interval

I am able to read message of user when the application gets installed. But what I want is that even after the application is closed, I should be able to read user message after a fixed interval of time. For example, application like Walnut that reads specific message and gives alerts automatically if any new message has come. How can I do the same.
Use Alarm manager and Pending Intent
Initiate Alarm manager here.
AlarmManager alarmMgr = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(this, AlarmReceiver_update.class),
PendingIntent.FLAG_CANCEL_CURRENT);
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
0, yourTimeInterval, pendingIntent);
And in AlarmReceiver_update class:
public class AlarmReceiver_update extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// Do whatever you want
}
}
And in Your AndroidManifest file register your receiver:
<receiver android:name="com.x.y.AlarmReceiver_update" >
<intent-filter>
<action android:name="android.test.BROADCAST" />
</intent-filter>
</receiver>
This is not complete just sample you have any doubt just comment.
You shuold use an alarm manager to set a repeating alarm.
Then you should setup a BroadcastReceiver Service that read the user messages onRecieve.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Run the task to read the user messages
}
}
This is a good tutorial
Have a look at the below links to learn how to notify the user if you found new message.
http://javatechig.com/android/repeat-alarm-example-in-android#3-defining-alarm-broadcastreceiver
http://developer.android.com/training/notify-user/build-notification.html

Trouble keeping Google Cloud Message alive

I am trying to work around the gcm time out issue, there are many threads on this subject, here is one for reference.
A proposed workaround is to broadcast a pair of intents at an interval shorter than the tcp timeout.
My implementation is to create a class that extends the CountDownTimer class and hold an instance of that class in an existing service. This derived class restarts itself when it is finished and the service is marked as STICKY_START, so once started, I would think it should just keep broadcasting the intents every 4 minutes, but for some reason there are gaps, when the counter does not broadcast the intents and I still loose contact with the GCM server.
The two relevant classes are below. Can anyone explain and offer a solution as to why this strategy does not work?
I created a class that extends CounDownTimer that should broadcast the intents every 4 minutes.
public class GcmKeepAlive extends CountDownTimer {
protected CountDownTimer timer;
protected Context mContext;
protected Intent gTalkHeartBeatIntent;
protected Intent mcsHeartBeatIntent;
public GcmKeepAlive(Context context) {
super(4*60* 1000,4*60*1000);
mContext = context;
gTalkHeartBeatIntent = new Intent("com.google.android.intent.action.GTALK_HEARTBEAT");
mcsHeartBeatIntent = new Intent("com.google.android.intent.action.MCS_HEARTBEAT");
System.out.println("stariing heartbeat countdown timer");
this.start();
}
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
System.out.println("sending heart beat to keep gcm alive");
mContext.sendBroadcast(gTalkHeartBeatIntent);
mContext.sendBroadcast(mcsHeartBeatIntent);
this.start();
}
}
here is the service in my app that holds an instance of the GcmKeepAlive class
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class LocationMonitorService extends Service {
private DeviceLocationClient deviceLocationClient;
private GcmKeepAlive gcmKeepAlive;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
System.out.println("creating the LocationMonitorService");
deviceLocationClient = new DeviceLocationClient(this);
gcmKeepAlive = new GcmKeepAlive(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
System.out.println("inside service making request for location updates");
deviceLocationClient.requestLLocationUpdates();
gcmKeepAlive.start();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Here is an example of a gap as seen in logcat.
07-13 14:59:05.583 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:03:05.640 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:07:05.776 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:11:05.922 I/System.out(21651): sending heart beat to keep gcm alive
07-13 15:27:31.994 I/System.out(21651): sending heart beat to keep gcm alive
I actually solved this some time ago, Erik Z's recent comment remained me to post my solution.
I solved this by creating a recurring alarm that triggers a broadcast, which creates and broadcasts the intents. The gaps were caused by the original service being killed and then restarted as a result of the START_STICKY flag.
Here are the various parts (pulled from various files)
This was needed pre-kitkat at the very least, I don't know if it is still needed, I assume it is. I have not turned it off to confirm however.
The alarm manager, intent , and pending intent.
AlarmManager alarmManager = (AlarmManager) Context.getSystemService(Context.ALARM_SERVICE);
Intent gcmKeepAliveIntent = new Intent("com.gmail.npnster.ourlatitude.gcmKeepAlive");
PendingIntent gcmKeepAlivePendingIntent = PendingIntent.getBroadcast(mContext, 0, gcmKeepAliveIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 4*60*1000, gcmKeepAlivePendingIntent);
The broadcast receiver:
public class GcmKeepAliveBroadcastReceiver extends BroadcastReceiver {
private GcmKeepAlive gcmKeepAlive;
#Override
public void onReceive(Context context, Intent intent) {
MyLog.p(this,"inside gcm keep alive receiver");
gcmKeepAlive = new GcmKeepAlive(context);
gcmKeepAlive.broadcastIntents();
}
}
The keep alive class that sends the keep alive broadcasts.
public class GcmKeepAlive {
protected Context mContext;
protected Intent gTalkHeartBeatIntent;
protected Intent mcsHeartBeatIntent;
public GcmKeepAlive(Context context) {
mContext = context;
gTalkHeartBeatIntent = new Intent(
"com.google.android.intent.action.GTALK_HEARTBEAT");
mcsHeartBeatIntent = new Intent(
"com.google.android.intent.action.MCS_HEARTBEAT");
}
public void broadcastIntents() {
MyLog.p(this,"sending heart beat to keep gcm alive");
mContext.sendBroadcast(gTalkHeartBeatIntent);
mContext.sendBroadcast(mcsHeartBeatIntent);
}
}

Categories

Resources