setAlarmClock BroadcastReceiver does not reach onResume sometimes - android

I have created an alarm clock app using setAlarmClock. For some people the alarm does not start properly. I know you must disable all kind of energy saving modes on devices otherwise it could by that the alarm does not fire. But I have some rare cases where the alarm starts on time but it has time gaps until it finishes alls steps of onCreate and onPostCreate of my activity.
It could be related with the fact that my wakelock is activated very late. When the Broadcastreceiver is called with an alarm event it starts my main activity. The activity starts a thread which must run at least once. It checks if the alarm should fire. If yes then it creates a wakelock to keep the device awake.
I could try to create the wakelock ealier but I have seen log files where onResume has not been even called, only onStart. There is a gap of 5 minutes between onStart and onResume. So there is no chance to make it early enough.
Is there something wrong with my alarm and wakelock concept?
Is it possible/wise to start the wakelock in the BroadcastReceiver and stop it in the Activity?
public class AlarmManagement extends BroadcastReceiver implements Serializable
{
#Override
public void onReceive (Context context, Intent intent)
{
Intent i = new Intent(context, FullscreenActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(i);
}
public void scheduleSystemAlarmApi21(Context context,long alarmTime, PendingIntent pi) {
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i2=new Intent(context, FullscreenActivity.class);
PendingIntent pi2=PendingIntent.getActivity(context, 0, i2, 0);
am.setAlarmClock(new AlarmManager.AlarmClockInfo(alarmTime,pi2),pi);
}
public void scheduleSystemAlarm(Context context,int id, long alarmTime) {
Intent i = new Intent(context, AlarmManagement.class);
PendingIntent pi = PendingIntent.getBroadcast(context, id, i, 0);
scheduleSystemAlarmApi21(context,alarmTime,pi);
}
}
public class FullscreenActivity extends AppCompatActivity {
Thread thread;
#Override
protected void onResume() {
super.onResume();
if (threadStopped)
alarmServiceThread();
}
void alarmServiceThread() {
thread = new Thread() {
#Override
public void run() {
...
if (needToStartWakeup(currentTime))
startWakeup();
...
}
}
thread.start();
}
PowerManager powerManager;
PowerManager.WakeLock wake;
public void startWakeup() {
powerManager = ((PowerManager) getSystemService(Context.POWER_SERVICE));
int levelAndFlags=PowerManager.ACQUIRE_CAUSES_WAKEUP;
levelAndFlags |= PowerManager.SCREEN_BRIGHT_WAKE_LOCK;
wake = powerManager.newWakeLock( levelAndFlags , WAKE_LOCK_TAG);
wake.acquire();
}
}

You are trying to start an activity from the receiver in the onReceive method, that is problematic if your app is in the background.
Please read the following documentation on the subject:
https://developer.android.com/guide/components/activities/background-starts
You should present a notification for the user and open the activity on user action.

Related

Repetitive service design Android

I have following design in my app: I have a one activity that sets repeating alarm that launches receiver that starts my service. Every minute. In my service, I set Start Sticky but once Android decides to kill my service, I can't get it to restart. It's Android 4.4.2. Here is my code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i1 = new Intent(MainActivity.this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this, 0, i1, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, 0, 60 * 1000, pi);
}
here is the receiver
public void onReceive(Context arg0, Intent arg1) {
// For our recurring task, we'll just display a message
Log.d(Constants.TAG, "Starting Service");
Intent intent = new Intent(arg0, MyLocationService.class);
arg0.startService(intent);
}
and service:
private static PowerManager.WakeLock wl;
private static OkHttpClient client;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(Constants.TAG, "Service onStartCommand");
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
wl.acquire();
client = new OkHttpClient();
new GetLocation(MyLocationService.this).execute();
return START_STICKY;
}
You're most likely seeing an interaction with power management and alarms. Starting with API 19 all alarms are inexact by default, so they will be collated with other alarms. Further, once the device has entered into a lower power state, alarms are delivered to BroadcastReceivers and the device guaranteed to stay awake as long as the receiver is executing its onReceive() method. Once it returns from that method (and any other BroadcastReceiver associated with the alarm runs), the device will immediately go to a low power state again. Since your app had previously been killed, the Service is no longer running and will not get CPU time.
The way to resolve this is to use a WakefulReceiver which takes a wakelock when it runs onReceive(), starts your Service for processing. The Service will then release the wakelock when it is done processing. This article will give you a good explanation of this: http://po.st/7UpipA
Note that waking up every minute is going to seriously degrade the battery life of the device, so you should consider backing this off.

How to stop my service after passing fixed amount of time?

At point A in my application I start my service and expect the service get closed from point B. However, there might be few scenarios that point B doesn't ask service to get closed. In this case I want the service close itself after fixed amount of time.
I have written following code into my Service class and expect the service gets closed after 10 seconds from launch time (It will be 45min in the future but I don't want to stay that long for test).
public class ChatService extends Service implements ITCPConnection
{
private static final int SERVICE_LIFE_TIME = 10 * 1000; // In millis
private AlarmReceiver mAlarmReceiver;
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
#Override
public void onCreate()
{
super.onCreate();
//
mAlarmReceiver = new AlarmReceiver();
registerReceiver(mAlarmReceiver, new IntentFilter());
//
Intent intent = new Intent(this, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + SERVICE_LIFE_TIME, alarmIntent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e(TAG, "onDestroy()");
// Unregister receiver
if (mAlarmReceiver != null)
{
unregisterReceiver(mAlarmReceiver);
}
disconnect();
}
public void disconnect()
{
// If the alarm has been set, cancel it.
if (alarmMgr!= null)
{
alarmMgr.cancel(alarmIntent);
}
...
Log.e(TAG, "disconnect()");
}
/*****************
* Alarm Receiver
*****************/
private static class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.e(TAG, "Stop service from AlarmReceiver");
context.stopService(intent);
}
}
}
My problem is AlarmReceiver.onReceive() never gets called and therefore my service will be alive indefinitely.
What you are trying to do is to targeting a broadcast receiver explicitly.
According to this, it cannot be done over a dinamically created (i.e. not declared into the manifest) broadcast receiver, because the os would not know how to resolve it.
To check if this is the root of the problem, you can go with the implicit way and set an action inside the intent and by filtering it in the IntentFilter.
Anyway, using the post delayed can be seen as a valid alternative, since you expect the service to be shut down naturally or still be around to intercept the delayed event.
Another (unrelated) thing is that you are calling
context.stopService(intent);
by using the broadcast intent and not the intent that started the service. You could simply call stopSelf().

How to schedule intent service correctly in Android

I'm working on app in which I want to schedule service in a interval of 6 hours. I'm calling this method from main activity. When this activity open then it call this method and hits the service. I don't want to execute it whenever this method executes. After first exceution of this service it should execute after 6 hours or so not app open. Is there any flag or something I need to do set to do that.
public static void scheduleHeartBeat(Context mContext) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
Intent myIntent = new Intent(mContext, HearBeatService.class);
PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() , 6*60*60*1000, pendingIntent);
}
public class HearBeatService extends IntentService {
public HearBeatService() {
super("HearBeatService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("HeartBeat", "Hey Testing!!!");
}
}
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.....
scheduleHeartBeat(this);
...
}
Thanks in advance.
User broadcastreceiver.
Create class that extends Intent service class
Create class that broadcastreceiver class and call the Intent service (from step1)
Create pending intent for the broadcastreciever(from step2)
Register the pending intent with alarm manager of 6 hours delay
Dont Forget to register your service and receiver in the android manifest.

want to run and stop service with activity android

I am wondering if i can do this, i want to implement a service that will be called when activity launches and should run at regular intervals, and when i stop the activity by closing or pressing back the service should stop and alarm manager should not invoke service before the activity relaunches.
One more thing i want to send some data on which service can operate and give results back to activity.
currently i am doing like this.....
class MyService extends Service{
}
class MyScheduler extends BroadCastReceiver{
//Here alarm manager and pending intent is initialized to repeat after regular intervals.
}
class MyActivity extends Activity{
onCreate(){
//here i am binding the service
}
}
MyBrodcastReceiver is added into manifest
please help and suggest how to do it?
for starting:
this.startService(new Intent(this, MyService.class));
for stoping:
this.stopService(new Intent(this, MyService.class));
for having intervals create a service that calls a BrodcastReceiver periodically like the following sample:
in your service:
// An alarm for rising in special times to fire the pendingIntentPositioning
private AlarmManager alarmManagerPositioning;
// A PendingIntent for calling a receiver in special times
public PendingIntent pendingIntentPositioning;
#Override
public void onCreate() {
super.onCreate();
alarmManagerPositioning = (AlarmManager) getSystemService
(Context.ALARM_SERVICE);
Intent intentToFire = new Intent(
ReceiverPositioningAlarm.ACTION_REFRESH_SCHEDULE_ALARM);
pendingIntentPositioning = PendingIntent.getBroadcast(
this, 0, intentToFire, 0);
};
#Override
public void onStart(Intent intent, int startId) {
long interval = 10 * 60 * 1000;
int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long timetoRefresh = SystemClock.elapsedRealtime();
alarmManagerPositioning.setRepeating(alarmType,
timetoRefresh, interval, pendingIntentPositioning);
}

Android-Broadcast Receiver

I am new to android. I what to know the difference between Intent and BroadcastReceiver. I am more confused with BroadcastReceiver than Intent.
Please help me out. Simple code will be helpful.
Ok, I will explain it with an example.
Let's suppose I want to create an app to check subway status from it's webpage. I also want a system notification if the subway is not working ok.
I will have:
An Activity to show results.
A Service to check if the subway is working and show a notification if it's not working.
A Broadcast Receiver called Alarm Receiver to call the service every 15 minutes.
Let me show you some code:
/* AlarmReceiver.java */
public class AlarmReceiver extends BroadcastReceiver {
public static final String ACTION_REFRESH_SUBWAY_ALARM =
"com.x.ACTION_REFRESH_SUBWAY_ALARM";
#Override
public void onReceive(Context context, Intent intent) {
Intent startIntent = new Intent(context, StatusService.class);
context.startService(startIntent);
}
}
Explanation:
As you can see you can set an alarm. and when the alarm is received we use an intent to start the service. Basically the intent is a msg which can have actions, an serialized stuff.
public class StatusService extends Service {
#Override
public void onCreate() {
super.onCreate();
mAlarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentToFire = new Intent(AlarmReceiver.ACTION_REFRESH_ALARM);
mAlarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0);
}
#Override
public void onStart(Intent intent, int arg1) {
super.onStart(intent, arg1);
Log.d(TAG, "SERVICE STARTED");
setAlarm();
Log.d(TAG, "Performing update!");
new SubwayAsyncTask().execute();
stopSelf();
}
private void setAlarm() {
int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
mAlarms.setInexactRepeating(alarmType, SystemClock.elapsedRealtime() + timeToRefresh(),
AlarmManager.INTERVAL_HALF_DAY, mAlarmIntent);
}
}
Explanation:
The service starts and:
Set the alarm for the next call. (Check the intent it's used. Just a msg)
Calls an AsyncTask which takes care of updating an notifying the Activity
It doesn't make sense to paste the AsyncTask but when it finished it calls:
private void sendSubwayUpdates(LinkedList<Subway> subways) {
Intent intent = new Intent(NEW_SUBWAYS_STATUS);
intent.putExtra("subways", subways);
sendBroadcast(intent);
}
This creates a new Intent with a certain NEW_SUBWAYS_STATUS action, put inside the intent the subways and sendBroadcast. If someone is interested in getting that info, it will have a receiver.
I hope I made myself clear.
PS: Some days ago someone explained broadcast and intents in a very cool way.
Someone wants to share his beer, so he sends a broadcast
with an intent having action:"FREE_BEER" and with an extra: "A glass of beer".
The API states:
A BroadcastReceiver is a base class for code that will receive intents sent by sendBroadcast().
An intent is an abstract description of an operation to be performed.
So, a BroadcastReceiver is just an Activity that responds to Intents. You can send your own broadcasts or even the Android Device can send these system wide broadcasts including things like the battery is low, or the device just booted-up.

Categories

Resources