For testing purposes i have made a service that beeps
every 1 minute. (No client-server interface yet). It beeps okay when
the screen in on, but when it goes to sleep the beeping stops.
I am making an application that has to periodically poll the a server
for something.
For this, I am trying to create a service that'll constantly be
running in the background, poll the server every 1 min and then based
on the reply from server it shall generate a task bar notification.
I have a test activity with two buttons, 1 to start and the other to
stop the service. And one service class named S_PS_PollService
The setOnClickListener of 'Start Activity' button contains:
Thread pollServiceThread = new Thread() {
public void run() {
startService(new Intent(MM_MainMenu.this,
S_PS_PollService.class));
}
};
pollServiceThread.start();
The 'Stop Activity' button simply has:
stopService(new Intent(MM_MainMenu.this, S_PS_PollService.class));
Following are the methods from S_PS_PollService class:
public void onCreate() {
pollSound = MediaPlayer.create(this, R.raw.chirp);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(this, S_PS_PollService.class);
pendingIntent = PendingIntent.getService(this, 0, myIntent, 0);
// for wake lock
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag")
// for calendar
calendar = Calendar.getInstance();
}
Onstart:
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
wl.acquire();
pollSound.start();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MILLISECOND, 60000);
alarmManager.set(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), pendingIntent);
wl.release();
}
Whenever the alarm kicks off onStart() method is executed, making the
beep and setting new alarm. But it works only as long as screen is on.
I have tried for https://github.com/commonsguy/cwac-wakeful but didnt
get it. Relatively new to android ...
Please help me, im very desperate :) Thanks, !
You have to use the AlarmManager, there are plenty of posts here on stackoverflow.
You want to acquire a partial wake lock (leaving the CPU running whenever sleep is entered on the device) as suggested by your code.
The issue is your presumably overriden on start releases the wake lock. You want to release your wakeLock in onDestroy .. once your service is finished running.
This finally worked for me.
Download the CWAC-WakefulIntentService.jar from https://github.com/commonsguy/cwac-wakeful
add a class in your project
import com.commonsware.cwac.wakeful.WakefulIntentService;
public class WakeService extends WakefulIntentService {
public WakeService(String name) {
super(name);
}
#Override
protected void doWakefulWork(Intent intent) {
}
}
now add the following line in your code where ever you want to repeat the loop and wake the device up
WakefulIntentService.sendWakefulWork(this, S_WS_WakeService.class);
Related
We are trying to implement timer for native code in android .The timer should work precisely during wake and sleep mode .When timer expires then our native code will send DPD(Dead peer detection) messages to the network
We tried following approaches .
Using android framework API's for alarm manager in userspace code and below are the results:
This doesn't give the accurate results even during wake state for small timers like 2s,3s,5s.
Does not work precisely for sleep mode also.
We tried to use kernel timer in kernel space code and below are the results:
Works perfectly for wake state.
But for sleep state timers do not expire at all.When we wake the device up manually then the timers get expire .So,in conclusion kernel timers do not work during sleep state.
3.Using wake lock
*We are trying to avoid use of wake lock as it may cause significant performance issues
P.S - Open source Ipsec implementation strongswan sends the DPD messages precise time even during sleep mode .But it seems that strongswan does not use wake lock ,so we are still trying to figure out how it works during sleep mode.Anybody searching for answer to this question might want to look into that code.
Can anyone please suggest something to resolve this issue.
When Android goes to sleep it will have several states, the last one is freezing all the processes and turning off the CPU.
In that case your times are not going to fire. You must create an event that will wake up the kernel and set a wake lock so the cpu will not turn off again. This can be done using android alarms.
The only way to have the timer work precisely in sleep mode is to keep device partially awake using Wakelock. But make sure your application really need the timer to work all the time, because the document says,
Device battery life will be significantly affected by the use of this API. Do not acquire PowerManager.WakeLocks unless you really need them, use the minimum levels possible, and be sure to release them as soon as possible.
Go through PowerManager Class, use the below code to acquire partial wake lock
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
..cpu will stay on during this section..
wl.release();
Initiate timer and when app goes background then start alarmManager. Again if app comes foreground and timer is not expired then it will re trigger the timer and will remove the alarm manager.
private int timeToStart;
private TimerState timerState;
private static final int MAX_TIME = 60; //Time length is 60 seconds
private enum TimerState {
STOPPED,
RUNNING
}
private void initTimer() {
Log.e(TAG,"initTimer called");
long startTime = mPrefs.getStartedTime(); //here mprefs is your shared preference manager
if (startTime > 0) {
timeToStart = (int) (MAX_TIME - (getNow() - startTime));
if (timeToStart <= 0) {
// TIMER EXPIRED
onTimerFinish();
} else {
startTimer();
timerState = TimerState.RUNNING;
}
} else {
timeToStart = MAX_TIME;
timerState = TimerState.STOPPED;
}
}
private long getNow() {
Calendar rightNow = Calendar.getInstance();
return rightNow.getTimeInMillis() / 1000;
}
private void onTimerFinish() {
Log.e(TAG,"onTimerFinish() called");
timerState = TimerState.STOPPED;
mPrefs.setStartedTime(0);
timeToStart = MAX_TIME;
}
private void startTimer() {
Log.e(TAG,"startTimer() called");
countDownTimer = new CountDownTimer(timeToStart * 1000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timeToStart -= 1;
}
#Override
public void onFinish() {
onTimerFinish();
}
}.start();
}
public void setAlarmManager() {
int wakeUpTime = (mPrefs.getStartedTime() + MAX_TIME) * 1000;
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, TimeReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
am.setAlarmClock(new AlarmManager.AlarmClockInfo(wakeUpTime, sender), sender);
} else {
am.set(AlarmManager.RTC_WAKEUP, wakeUpTime, sender);
}
}
public void removeAlarmManager() {
Intent intent = new Intent(this, TimeReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
}
#Override
protected void onResume() {
super.onResume();
initTimer();
removeAlarmManager();
}
I have a problem on my app and I want to report this bug.
I develope the app which can crawls notifications using NotificationListenerService.
It works well.
But NotificationListenerService class has the problem I think.
Because, If the app is crashed, app can't crawl the notification at all,
UNTIL the phone reboots.
Is anyone who can solve this problem??
Please help me.
The bug is very clear!! But It is not easy to find the solution ....
If do you have already permissions then:
In your service class or another service/activity you can switch the "component hability" to listen notifications:
public void tryReconnectService() {
toggleNotificationListenerService();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ComponentName componentName =
new ComponentName(getApplicationContext(), NotificationReaderV2Service.class);
//It say to Notification Manager RE-BIND your service to listen notifications again inmediatelly!
requestRebind(componentName);
}
}
/**
* Try deactivate/activate your component service
*/
private void toggleNotificationListenerService() {
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(this, NotificationReaderV2Service.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(new ComponentName(this, NotificationReaderV2Service.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
Your notification listener, is a SERVICE, it can be killed by System, you can do your service as FOREGROUND to drastically decrease the probability that the system will kill your service.
#Override
public void onListenerConnected() {
super.onListenerConnected();
Log.d(TAG, "Service Reader Connected");
Notification not = createNotification();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.notify(NOTIFICATION_ID, not);
}
startForeground(NOTIFICATION_ID, not);
//Alarm to auto - send Intents to Service to reconnect, you can ommit next line.
alarmIt();
}
If do you like so more "safe", you can to programming not-friendly battery alarms, try to use inexact alarms please, the user's battery will be happy:
private void alarmIt() {
Log.d(TAG, "ALARM PROGRAMMATED at"+HotUtils.formatDate(new Date()));
Calendar now = Calendar.getInstance();
now.setTimeInMillis(System.currentTimeMillis());
now.set(Calendar.MINUTE, now.get(Calendar.MINUTE) + 1);
Intent intent = new Intent(this, NotificationReaderV2Service.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setAction(REBIND_ACTION);
PendingIntent pendingIntent = PendingIntent.getService(this, 0,
intent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//The alarms that are repeated are inaccurate by default, use RTC_WAKE_UP at your convenience.
//Alarm will fire every minute, CHANGE THIS iF DO YOU CAN, you can't use less than 1 minute to repeating alarms.
manager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTimeInMillis(), 1000 * 60 * 1, pendingIntent);
}
and next read the Intent to reconnect service binding:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Notification service onStartCommandCalled");
if (intent!=null && !HotUtils.isNullOrEmpty(intent.getAction()) && intent.getAction().equals(REBIND_ACTION)){
Log.d(TAG, "TRYING REBIND SERVICE at "+HotUtils.formatDate(new Date()));
tryReconnectService();//switch on/off component and rebind
}
//START_STICKY to order the system to restart your service as soon as possible when it was killed.
return START_STICKY;
}
Keep in mind that doing all these steps you can sure that your service will be killed anyway by the system but this code will restart the service and make it harder to kill it.
Maybe, you should consider using PARTIAL_WAKE_LOCK with your service and execute it in a process independently (:remote) if you want even more certainty (Maybe this is useless)
I would like to add a common error that is often followed, NEVER override the onBind and onUnbind method or overwrite the INTENT ACTION.
This will cause your service to not be connected and never run onListenerConnected
Keep the Intent as it is, in most cases you do not need to edit it.
I see exactly the same on this. The only "solution" I've found was to have the notification listener running in a separate process. Then if the rest of the app crashes it doesn't stop the listener. So it's only then specifically notification listener service crashes that require the reboot.
Seems a terrible and over complicated solution though.
I had the same problem. Here are few things that I did and now it works wonderfully for me.
Override onStartCommand, call super and return START_STICKY;
Override onNotificationRemoved, call super and add a toast so that you know in android itself that you service has not died yet whenever you swipe a notification.
Exclude your app from Battery saving list (Settings-> Battery-> Power Saving Exclusion)
Post this the service never dies even after the main app's crash. I dont need to reboot now to restart it.
So I have a Service that I want to be able to listen for Alarms and temporarily shut itself down/pause whilst the alarm rings, and then resume itself afterwards. What my Service does is that it inflates a view using WindowManager on top of the screen - it's a lock screen app.. But as such, it's always on top of everything else..
This was easy enough to implement for incoming calls using a PhoneStateListener but I haven't seen anything as handy for alarms - I guess I could implement an AlarmManager.onAlarmListener that shuts my service down once the alarm rings, but I'm not sure of how I would turn it back on again afterwards.
Thankful for any help!
Finally figured it out!
You can get the time of the next alarm like so:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.getNextAlarmClock().getTriggerTime()
So just add this to your service onCreate method:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
if (alarmManager.getNextAlarmClock() != null) {
UIHandler.postAtTime(new Runnable() {
#Override
public void run() {
stopSelf();
}
}, alarmManager.getNextAlarmClock().getTriggerTime());
}
Essentially what it does is to get the time of your next alarm in milliseconds, then post a runnable at the time of the next alarm.
I believe it will only work on API 21+
Maybe, you can try to implement AudioManager.OnAudioFocusChangeListener
https://developer.android.com/reference/android/media/AudioManager.OnAudioFocusChangeListener.html
#Override
public void onAudioFocusChange(int i) {
if (i <= 0 && i != -3) {
// pause
} else if (i > 0) {
// resume
}
}
}
I'm trying to get a process timer to run and keep it running in the background on android (starts with a button click).
The timer must be on 30 seconds and should even continue growing application in the background (with home button and power / screen off).
How can I do this? I tried with service and handler but not working ...
EDIT
My service tracking (process with 30 sec)
public class TrackingService extends IntentService {
private Handler mHandler;
private Runnable mRunnable;
public TrackingService() {
super("TrackingService");
}
public TrackingService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
long timer = 30000;
mHandler = new Handler();
mRunnable = new Runnable() {
#Override
public void run() {
//TODO - process with update timer for new 30 sec
mHandler.postDelayed(this, timer);
}
};
mHandler.postDelayed(mRunnable, timer);
}
}
My click button:
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO - start first time and it continued every 30 seconds and continue in the background
startService(Intent intent = new Intent(this, TrackingService.class));
}
});
Ok, first of all, I really don't know if I got your question quite right.
But I think you want a timer that's being executed every 30 seconds ,if i'm not mistaken.
If so, do as following:
AlarmManager
Note: This class provides access to the system alarm services. These allow you to schedule your application to be run at some point in the future. When an alarm goes off, the Intent that had been registered for it is broadcast by the system, automatically starting the target application if it is not already running. Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
Example:
in your onClick() register your timer:
int repeatTime = 30; //Repeat alarm time in seconds
AlarmManager processTimer = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, processTimerReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//Repeat alarm every second
processTimer.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),repeatTime*1000, pendingIntent);
And your processTimerReceiver class:
//This is called every second (depends on repeatTime)
public class processTimerReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Do something every 30 seconds
}
}
Don't forget to register your receiver in your Manifest.XML
<receiver android:name="processTimer" >
<intent-filter>
<action android:name="processTimerReceiver" >
</action>
</intent-filter>
</receiver>
If you ever want to cancel the alarm:
use this to do so:
//Cancel the alarm
Intent intent = new Intent(this, processTimerReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
Hope this helps you out.
PS: if this is not exactly what u want, please leave it in the comments, or if someone wants to edit this, please do so.
Oh god, don't ever use AlarmManager for 30s timers. It's kind of an overkill and also put a significant drain on device resources (battery, CPU...).
Perhaps you could try using a real background Service instead of IntentService as IntentService tends to shut itself down when it runs out of work. Not sure if this is the case here, but it's worth a try.
I'm trying to create a reminder app for tablets.
My problem is that if the tablet is in sleep mode the alarm isn't getting called.
i tried a lot off project on github none of them wase working when my tablet wase in sleep mode.
My code is the following:
The code to set the alarm:
Intent intent = new Intent(getApplicationContext(),RingAlarmReceiver.class);
Intent intent = new Intent("kidsplaylist.info.waketest.MyWakefulReceiver");
PendingIntent pIntent = PendingIntent.getBroadcast(getApplicationContext(),0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarm = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 30);
alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pIntent);
The code of the receiver:
public class MyWakefulReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
WakeLocker.acquire(context);
// Start the service, keeping the device awake while the service is
// launching. This is the Intent to deliver to the service.
Intent service = new Intent(context, MyIntentService.class);
startWakefulService(context, service);
}
}
The code for the service that is supposed to ring the alarm:
public class MyIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
// Do the work that requires your app to keep the CPU running.
String song = Settings.System.DEFAULT_RINGTONE_URI.toString();
MediaPlayer mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(song));
mediaPlayer.prepare();
mediaPlayer.setLooping(false);
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
MyWakefulReceiver.completeWakefulIntent(intent);
}
}
Can anyone with experience in such thick advice me how to fix it
Thank's a lot
Avi
P.B: When the device is connected to the charger or when the screen is on it works OK
The problem is when the device screen is off.
Note that on Android 6.0+, Doze mode and app standby will affect AlarmManager events.
Beyond that, using an IntentService to directly play media will not work well. Once onHandleIntent() returns, the IntentService is destroyed, and your process will typically be terminated shortly thereafter.
I strongly recommend that you raise a Notification that uses this media as a ringtone. That would eliminate the need for the service entirely (you could raise the Notification in onReceive(), since that should be fairly quick to execute). It gives the user more control over whether the music plays (via Notification controls on Android 5.0+), and it gives the user a straightforward way to shut it up (swipe away the Notification).
If you insist upon playing the media yourself, you will need to use a regular Service and manage your own WakeLock, so that you can keep all that outstanding while the media is playing. Use an OnCompletionListener to stopSelf() the service and release() the WakeLock when the media is done.