I call my Service with alarm manager
like this:
alarmManage.setExact(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + getPoolingInterval(), pendingIntentPolling);
On my ServicePooling i reschedule it of the same way, and this ServicePooling call another service to send data on my service.
Intent serviceSocket = new Intent(this.context, SenderService.class);
this.context.startService(serviceSocket);
All works very well every minut i receive on my server a polling communication, but when my device are screen off and without USB plugged, this stop work.
This is a bad idea to use Service for AlarmManager nowadays. Use WakefulBroadcastReceiver instead. your device fall asleep then unplugged.
public class BRMine extends WakefulBroadcastReceiver {
public static final String INTENT_FILTER = "com.example.BRMine";
#Override
public void onReceive(Context ctx, Intent intent) {
// TODO Auto-generated method stub
OWakeLocker.acquire(ctx, _.indexNOTS);
ComponentName comp = new ComponentName(ctx.getPackageName(),
SMine.class.getName());
startWakefulService(ctx, intent.setComponent(comp));
}
}
where:
public class OWakeLocker {
private static PowerManager.WakeLock[] wakeLocks = new PowerManager.WakeLock[_.indexNOTS_MAX];//Services count
#SuppressWarnings("deprecation")
public static void acquire(Context ctx, int index) {
WakeLock wakeLock = wakeLocks[index];
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, _.APPNAME + Integer.toString(index));
if (wakeLock != null && wakeLock.isHeld()){
wakeLock.acquire();
}
}
public static void release(int index) {
WakeLock wakeLock = wakeLocks[index];
if (wakeLock != null)
wakeLock.release();
wakeLock = null;
}}
to start:
Intent intent = new Intent(BRMine.INTENT_FILTER);
PendingIntent pi = PendingIntent.getBroadcast(ctx, myintentalarm, intent, PendingIntent.FLAG_CANCEL_CURRENT):
am.setExact(AlarmManager.RTC_WAKEUP, nexttime, pi);
I solve my problem using a answer of Vyacheslav but wihtout AlarmManager because setExact didint work for me on idle and my android is a api lower then 23 (and don't have setExactAndAllowWhileIdle) i use a timertask on startapplication in my case works werry well, i just need this when my application are runnning.
Related
I'm using a BroadcastReceiver that receives a broadcast from an AlarmManager. In the receiver I am starting two activities. One activity is started from a URI like this and is a third-party app:
// Open spotify
Intent spotify = new Intent(Intent.ACTION_VIEW, Uri.parse(song));
spotify.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(spotify);
} catch (ActivityNotFoundException e) {
status = Status.SPOTIFY_NOT_INSTALLED;
}
After that I start another activity that belongs to the app with a 5 second delay using the AlarmManager again:
public static void setExact(
Context context, PendingIntent pendingIntent, long time
) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
am.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
else
am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
public static void setExactDelay(
Context context, PendingIntent pendingIntent, long delay
) {
setExact(context, pendingIntent, System.currentTimeMillis() + delay);
}
PendingIntent pendingIntent = AlarmPlayActivity.makePendingIntent(context, alarm, status, startTime);
AlarmSet.setExactDelay(context, pendingIntent, 5000);
The second activity starts in 5 seconds as expected. However the first activity only starts when the device is unlocked. If the device is locked it does not start on Android Nougat (7.0). This is the case even when the lock is not secured by password, pattern etc. This used to work on earlier Android versions, even with a secure lock.
Is there a method by which I can start the first activity without needing the screen to be on?
Edit: I've tried using the following IntentService. It works when the device is awake and unlocked but there is no luck when the device is locked:
public class AlarmService extends IntentService {
static final int NOTIFICATION_ID = 1;
public AlarmService() {
super("AlarmService");
}
public static Intent makeIntent(Context context, Alarm alarm, AlarmReceiver.Status status, long startTime) {
Intent intent = IntentFactory.alarmPlayIntent(alarm, status, startTime);
intent.setClass(context, AlarmService.class);
return intent;
}
private static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// Nothing
}
}
#Override
protected void onHandleIntent(Intent intent) {
// Acquire Wakelock immediately
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(
PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE,
"AlarmServiceWakeLock"
);
wakeLock.acquire();
KeyguardManager.KeyguardLock lock = ((KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE)).newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();
// Get intent data
final Alarm alarm = IntentFactory.getAlarm(intent);
AlarmReceiver.Status status = IntentFactory.getStatus(intent);
final long startTime = IntentFactory.getStartTime(intent, 0);
// Get a random song for this alarm
AlarmDatabase db = AlarmDatabase.getInstance(this);
Song song = db.getRandomSong(alarm);
String songName = song == null ? "backup sound" : song.getName();
// Start a foreground notification
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getText(R.string.alarm_starting_notification_title))
.setContentText(getString(
R.string.alarm_starting_notification_message, alarm.getName(), songName
))
.setSmallIcon(R.drawable.ic_launcher)
.setPriority(NotificationCompat.PRIORITY_MAX)
.build();
startForeground(NOTIFICATION_ID, notification);
// Potentially open Spotify if we can
if (song != null) {
// Open spotify
Intent spotify = new Intent(Intent.ACTION_VIEW, Uri.parse(song.getUri()));
spotify.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
try {
startActivity(spotify);
} catch (ActivityNotFoundException e) {
status = AlarmReceiver.Status.SPOTIFY_NOT_INSTALLED;
}
} else
status = AlarmReceiver.Status.NO_SONGS;
// Start play activity in 10 seconds, giving Spotify some chance to load up.
sleep(10);
startActivity(AlarmPlayActivity.makeIntent(this, alarm, status, startTime));
// Keep alive for 5 more seconds
sleep(5);
// Stop notification
stopForeground(true);
// Release wakelock
wakeLock.release();
}
}
I experienced the same issue and i think Intent.ACTION_VIEW don't work until you unlock the screen because of safety reasons.
Same issue discussed here also. You can also check this link
You have to use up-to-date methods:
either
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nexttime, pendingintent);
or
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nexttime, pendingintent);
Do not forget to set your i awake mode:
to start:
PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, A_.APPNAME + Integer.toString(index));
if (wakeLock != null && wakeLock.isHeld()){
wakeLock.acquire();
}
to release:
wakeLock.release();
you can set your activity as foreground (over lock screen)
described here:
https://stackoverflow.com/a/23611199/1979882
import android.view.Window;
import android.view.WindowManager.LayoutParams;
Window window = this.getWindow();
window.addFlags(LayoutParams.FLAG_DISMISS_KEYGUARD);
window.addFlags(LayoutParams.FLAG_SHOW_WHEN_LOCKED);
window.addFlags(LayoutParams.FLAG_TURN_SCREEN_ON);
You can start your activity as shown here too:
https://stackoverflow.com/a/6468575/1979882
#Override
public void onReceive(Context context, Intent intent) {
//start activity
Intent i = new Intent();
i.setClassName("com.test", "com.test.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
Instead of starting your Spotify activity directly from the receiver, have the receiver instead start a Service from your own app.
Inside of the service, acquire your wakelock and then start a Foreground notification (build notification with NotificationCompat.Builder then use startForeground(mId, notification);, this notification will keep the service alive in cases where Nougat would otherwise stop it.
Then fire your Spotify Intent from the service, afterwards of course kill the service, foreground notification, and wakelock. This has worked for me before to avoid pesky Nougat problems like you are facing. Hope this helps!
In my case, the second activity also could not open without wake your phone up.
Solution:
Start activity when screen is off
Bring app to front, turn on display and unlock from AlarmManager?
I apologies in advance if I'm not good in writing English.
I'm writing a simple task app that remind me with alarm in specific time.
Below I set alarm with AlarmManager :
private static void setAlarm(Context context, Calendar calendar,
PendingIntent pIntent) {
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), pIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), pIntent);
}
}
and then AlarmManagerHelper :
public class AlarmManagerHelper extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String title = intent.getStringExtra("Title");
int hour = intent.getIntExtra("Hour", 0);
int min = intent.getIntExtra("Minute", 0);
String alarmTone = intent.getStringExtra("AlarmTone");
Intent i = new Intent();
i.setClassName("com.example.tasks",
"com.example.tasks.AlarmScreenActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("Title", title);
i.putExtra("Hour", hour);
i.putExtra("Minute", min);
i.putExtra("AlarmTone", alarmTone);
context.startActivity(i);
}
}
and AlarmScreenActivity is:
public class AlarmScreenActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get intent
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
mPlayer = new MediaPlayer();
try {
if (task_Tone != null && !task_Tone.equals("")) {
android.net.Uri toneUri = android.net.Uri.parse(task_Tone);
if (toneUri != null) {
mPlayer.setDataSource(this, toneUri);
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mPlayer.setLooping(true);
mPlayer.prepare();
mPlayer.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// some code
public void onClickDissmis(View view) {
mPlayer.stop();
finish();
}
protected void onDestroy() {
super.onDestroy();
wl.release();
}
}
then with AlarmManagerHelper and AlarmScreenActivity displaying it.
my problem is:
in the specific time that should wake up and ringing not do int, so when I press power button an turn screen on that is work???!
(when is in debug mode and the device , connected to system work properly)
I hope that describe my problem perfectly.
I don't understand your problem, exactly. I can say, though, that Android only guarantees that it is holding a wakelock while it delivers the Broadcast. Your code leave considerable time between the reception of the Broadcast, by the Receiver, and the time you seize the wakelock. There is nothing to prevent the device from going back to sleep, in that interval.
While AlarmManagerHelper.onReceive runs the system holds a lock (because of the Alarm manager) that will not fail. But between the context.startActivity(i); and the starting of the activity the system falls asleep again. You need to either use a WakefulBroadcastReceiver (see BroadcastReceiver Vs WakefulBroadcastReceiver) or (that's what I use) a WakefulIntentService.
In any case you need to start a service and start your activity from there. For the WakefulIntentService pattern see my answer PowerManager.PARTIAL_WAKE_LOCK android and links there.
I have facing problem in getting notification message from GCM Server.Device will get notification correctly when it not idle or in running state but when device goes idle for 10-15 minutes at that time device not able to get notification and also all registered devices are not gets notification from GCM server.How to resolve this problem?
Normally, your app need to wake when it sleeps.
Put this into your manifest file to wake your device when the message is received
<uses-permission android:name="android.permission.WAKE_LOCK" />
Add java class name WakeLocker.java
public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context context) {
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "WakeLock");
wakeLock.acquire();
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
Call the above code in 'private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver()' that might be in your MainActivity.java
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message
* depending upon your app requirement
* For now i am just displaying it on the screen
* */
// Showing received message
lblMessage.append(newMessage + "\n");
Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
// Releasing wake lock
WakeLocker.release();
}
};
Thank This source
Hope this helps
im receiving an intent in broadcast receiver and then i start service to do more work. now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
does my service will stop running if the device goes to sleep without getting a wakelock.
now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
If the device is asleep to begin with, you will not be "receiving an intent in broadcast receiver", because the device is asleep.
do i have to get Wakelock (AlarmManger?), and why do i need it?
You don't "need it", unless you want to ensure the device stays running while you complete some work.
does my service will stop running if the device goes to sleep without getting a wakelock.
Yes.
Looks like the Android's native WakefulBroadcastReceiver would be a perfect solution for you. Need to extend this rather than the regular BroadcastReceiver and start the service in the onReceive() in the "wakeful" manner:
startWakefulService(context, service);
and signal your work is done in the service's onHandleIntent(), calling
MyWakefulReceiver.completeWakefulIntent(intent);
public class WakeLockManager extends BroadcastReceiver {
private static WakeLock mWakeLock;
private String LCLT;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Consts.WAKELOCK_INTENT)) {
Log.v("wakelock", "GOT THE wakelock INTENT");
boolean on = intent.getExtras().getBoolean("on");
if (mWakeLock == null) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"Breeze WakeLock");
}
if (on) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
Log.v("wakelock", "acquiring wakelock");
}
} else {
if (mWakeLock.isHeld()) {
Log.v("wakelock", "releasing wakelock");
mWakeLock.release();
}
mWakeLock = null;
}
}
}
}
look at the above code ..put it in a separate class file and and in your manifest define it for some custom intent .... now that this class will respond to a custom intent ...just broadcast that intent and you can turn the wakelock on or off in your entire app since the wakelock is static..like this :
public void setWakeup(boolean status) {
Intent wakelock_Intent = new Intent(CUSTOM_INTENT);
wakelock_Intent.putExtra("on", status);
this.sendBroadcast(wakelock_Intent);
}
the above would be defined in your alarmmanager code so it schedules a call
I m looking for the best practice to implement a service for logging gps- or other sensor-values periodically (every 10-60 sec). The service should deal with the standby mode, when the phone goes asleep.
Any help (pseudo-code or tutorials) is very much appreciated!
It looks like it is impossible to let the orientation sensors work constantly for hours even though the device may fall asleep (refer to http://code.google.com/p/android/issues/detail?id=3708#makechanges
As soon as the display goes off, the sensors will do alike... :(
I now implemented a wakelock (needs permission)
<uses-permission android:name="android.permission.WAKE_LOCK" />
in conjunction with a timer and a broadcastreciever that will turn the display back on again. This is of course crazy for battery life but I found no other way so far.
This is my onCreate method in the service:
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
CONTEXT = this;
PowerManager pm = (PowerManager) CONTEXT.getSystemService(Context.POWER_SERVICE);
this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "my tag");
mWakeLock.acquire();
Log.d(TAG, "Wakelock acquired");
// register receiver that handles screen on and screen off logic
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
this the onStart method of the service:
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onStart");
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if (!screenOn) {
Log.d(TAG, "Screen is on");
} else {
Log.d(TAG, "Screen is off");
Timer timer = new Timer("DigitalClock");
timer.schedule(new TimerTask() {
#Override
public void run() {
Log.d(TAG,"Waiting 1 sec for switching the screen back on again...");
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
"my tag");
mWakeLock.acquire();
}
}, 1000);
mWakeLock.acquire();
}
}
and this is the BroadcastReceiver class:
public class ScreenReceiver extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
Intent i = new Intent(context, MyService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
This workaround will also do with a device UN-plugged from the debugger via USB (I first had an issue with this).
Please let me know if you have a better solution, or if there is fix in 2.3. Thanx!
Here's a link to a tutorial on how to use Android Services. LINK
Here's a link to a tutorial on how to read data from sensors. LINK