I'm trying to put a device into sleep mode for a certain amount of time, say x, by calling..
powerManager.goToSleep(xNumberOfMilliseconds);
However, the api never seems to work consistently, and never for any amount of time greater than 1000 milliseconds. I'm stumped. I have the appropriate permissions, my application has its sharedUserId set to "android.uid.system" in the manifest, and the application is signed with the same key the firmware itself is signed with (platform key).
It is a pretty simple API call, so I don't really know what on earth is going wrong. I've been able to get this problem on both a device running android 2.3 and a device running android 3.2.
Any ideas?
I have done this but it works at random on several android 4.0.x plaforms.
powerManager.goToSleep(SystemClock.uptimeMillis() + timeMs)
Did anyone managed to use the method the way he has intended to?
Edit:
It seems the right answer was what figure in the code below:
public void sleepFor(long time, Context context) {
//Create a new PendingIntent, to wake-up at the specified time, and add it to the AlarmManager
Intent intent = new Intent(context, this.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent wakeupIntent = PendingIntent.getActivity(context, CODE_WAKE_UP_DEVICE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// CODE_WAKE_UP_DEVICE is a dummy request code.
AlarmManager am = getAlarmManager();
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + time, wakeupIntent);
powerService.goToSleep(SystemClock.uptimeMillis() + 1);
}
ContentResolver cr= getContentResolver();
android.provider.Settings.System.putInt(cr,android.provider.Settings.System.SCREEN_OFF_TIMEOUT
,1000);
According to the documentation, current system time would be more appropriate parameter for goToSleep() than the desired sleep duration:
powerManager.goToSleep(SystemClock.uptimeMillis())
Related
I have an app that should show a notification every 2 hours and should stop if user has already acted upon the notif. Since background services are history now, I thought of using WorkManager ("android.arch.work:work-runtime:1.0.0-beta01") for the same.
My problem is that although the work manager is successfully showing the notifications when app is running, but it won't show notification consistently in the following cases(I reduced the time span from 2 hours to 2 minutes to check the consistency):
when app is killed from the background.
device is in screen off.
state device is in unplugged state(i.e not charging).
By consistency , i mean that the notifications show at least once in the given time span. for 2 minutes time span, the freq of notifications went from once every 4 minutes to completely not show any notification at all. for 2 hours timespan( the timespan that i actually want), its been 4 hours and i haven't got a single notification. Here is the Code i am using for calling WorkManger:
public class CurrentStreakActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
setDailyNotifier();
...
}
private void setDailyNotifier() {
Constraints.Builder constraintsBuilder = new Constraints.Builder();
constraintsBuilder.setRequiresBatteryNotLow(false);
constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
constraintsBuilder.setRequiresCharging(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
constraintsBuilder.setRequiresDeviceIdle(false);
}
Constraints constraints =constraintsBuilder.build();
PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
.Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);
builder.setConstraints(constraints);
WorkRequest request = builder.build();
WorkManager.getInstance().enqueue(request);
}
....
}
Here is the worker class(i can post showNotif(..) and setNotificationChannel(...) too if they might be erroronous):
public class PeriodicNotifyWorker extends Worker {
private static final String TAG = "PeriodicNotifyWorker";
public PeriodicNotifyWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.e(TAG, "PeriodicNotifyWorker: constructor called" );
}
#NonNull
#Override
public Result doWork() {
// Log.e(TAG, "doWork: called" );
SharedPreferences sp =
getApplicationContext().getSharedPreferences(Statics.SP_FILENAME, Context.MODE_PRIVATE);
String lastcheckin = sp.getString(Statics.LAST_CHECKIN_DATE_str, Statics.getToday());
// Log.e(TAG, "doWork: checking shared preferences for last checkin:"+lastcheckin );
if (Statics.compareDateStrings(lastcheckin, Statics.getToday()) == -1) {
Log.e(TAG, "doWork: last checkin is smaller than today's date, so calling creating notification" );
return createNotificationWithButtons(sp);
}
else {
Log.e(TAG, "doWork: last checkin is bigger than today's date, so no need for notif" );
return Result.success();
}
}
private Result createNotificationWithButtons(SharedPreferences sp) {
NotificationManager manager =
(NotificationManager) getApplicationContext().getSystemService((NOTIFICATION_SERVICE));
String channel_ID = "100DaysOfCode_ID";
if (manager != null) {
setNotificationChannel(manager,channel_ID);
showNotif(manager, channel_ID, sp);
return Result.success();
}
else {
return Result.failure();
}
I am using a xiaomi miA2 androidOne device with Android Pie(SDK 28). There are a few other things that are troubling me:
What can i possibly do to know if my WorkManager is running? Other that just wait for 2 hours and hope for a notification. I actually tried something like that, keeping my phone connected to pc and checking android studio's logcat every now and then. It DOES run all the logs when the worker is actually called, but i don't think that's a correct way to test it, or is it?
In the above Code, the setDailyNotifier() is called from the onCreate() every time the app is opened. Isn't it Wrong? shouldn't there be some unique id for every WorkRequest and a check function like WorkManger.isRequestRunning(request.getID) which could let us check if a worker is already on the given task??If this was a case of AsyncTask, then boy we would have a mess.
I have also checked #commonsware's answer here about wakelock when screen is off, but i remember that work manager does use alarm manager in the inside when available. So what am I missing here?
Few comments:
WorkManager has a minimum periodic interval of 15minutes and does not guarantee to execute your task at a precise time. You can read more about this on this blog.
All the usual background limitation you've on newer Android releases are still relevant when you use WorkManager to schedule your tasks. WorkManager guarantees that the task are executed even if the app is killed or the device is restated, but it cannot guarantee the exact execution.
There's one note about the tasks being rescheduled when your app is killed. Some OEM have done modification to the OS and the Launcher app that prevents WorkManager to be able to accomplish these functionality.
Here's the issuetracker discussion:
Yes, it's true even when the phone is a Chinese phone.
The only issue that we have come across is the case where some Chinese OEMs treat swipe to dismiss from Recents as a force stop. When that happens, WorkManager will reschedule all pending jobs, next time the app starts up. Given that this is a CDD violation, there is not much more that WorkManager can do given its a client library.
To add to this, if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched.
As of now , i have this app installed for last 8 days and i can confirm that the code is correct and app is working fine. as said by pfmaggi , the minimum time interval for work manager to schedule the work is 15 minutes, so there is a less chance that the WorkManager would have worked as expected in my testing conditions( of 2 minutes ) . Here are some of my other observations:
Like I said in the question that i was unable to recieve a notification for 4 hours even though i have passed the repeat interval as 2 hours. This was because of Flex Time. I passed in the flex time of 15 minutes and now it shows notifications between correct time interval. so i will be marking pfmaggi's answer as correct.
The problem of repeated work request can be solved by replacing WorkManager.getInstance().enqueue(request) with WorkManager.getInstance().enqueueUniqueWork(request,..)
I was still unable to find a way to test the work manager in the way i have described.
Is there a way to delete all stock alarm clock alarms in Android?
I am not talking about alarmservice intent, I am talking about the actual alarm clock. (Frustratingly both have the same name)
Here is the code I used to set the alarm :
Intent i = new Intent(AlarmClock.ACTION_SET_ALARM);
int hour = 6;
int min = 0 ;
i.putExtra(AlarmClock.EXTRA_HOUR, hour);
i.putExtra(AlarmClock.EXTRA_MINUTES, min);
So, is there a way to remove/delete the alarm, through code?
(PS, I'd really appreciate suggestions as to how to improve my questions, rather than receiving a downvote for no reason at all. I'm finding it really hard to understand the Stackoverflow community, no offence)
After a lot of research, I figured out there is no way to do so with one click of a button. (Android security issues). However, there is one way- open the AppInfo page for the Stock Alarm clock on every phone. This is the code I used:
Intent i = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + packageName));
startActivity(i);
Where package name is the package name of the default clock apps.
Here is a list that I could find online:
String clockImpls[] = {
"com.android.deskclock.ALARM_ALERT",
"com.google.android.deskclock",
"com.android.deskclock.ALARM_DISMISS",
"com.htc.android.worldclock.WorldClockTabControl",
"com.sonyericsson.organizer.Organizer_WorldClock",
"com.htc.android.worldclock.AlarmAlert",
"com.htc.android.worldclock.TimerAlert",
"com.sec.android.app.clockpackage.ClockPackage",
"com.motorola.blur.alarmclock.AlarmClock",
"com.android.deskclock.ALARM_DONE",
"com.android.deskclock.ALARM_SNOOZE",
"com.android.deskclock.DeskClock",
"com.android.deskclock.AlarmClock",
"com.motorola.blur.alarmclock.AlarmAlert",
"com.motorola.blur.alarmclock.AlarmClock",
"com.motorola.blur.alarmclock.AlarmTimerAlert",
"com.android.alarmclock.AlarmClock",
"com.android.deskclock.DeskClock",
"com.sec.android.app.clockpackage.alarm.AlarmAlert",
"com.android.alarmclock.ALARM_ALERT",
"com.sec.android.app.clockpackage.ClockPackage",
"com.samsung.sec.android.clockpackage.alarm.ALARM_ALERT",
"com.htc.android.worldclock.ALARM_ALERT",
"com.sonyericsson.alarm.ALARM_ALERT",
"zte.com.cn.alarmclock.ALARM_ALERT",
"com.motorola.blur.alarmclock.ALARM_ALERT",
"com.mobitobi.android.gentlealarm.ALARM_INFO",
"com.urbandroid.sleep.alarmclock.ALARM_ALERT",
"com.splunchy.android.alarmclock.ALARM_ALERT"
};
PS:
Sadly, I haven't yet figured out a way to get questions answered from the community at StackOverflow. I'd really love people to help me out, in pointing where I'm going wrong.
I was linked to your library (once again, THANKS and excellent work).
I've been trying for the past two hours what the problem is but I've failed.
Here's the AlarmManager in my Login screen code:
Intent i = new Intent(con, LocationPoller.class);
i.putExtra(LocationPoller.EXTRA_INTENT, new Intent(con,
LocationReceiver.class));
i.putExtra(LocationPoller.EXTRA_PROVIDER,
LocationManager.NETWORK_PROVIDER);
gps = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(con, 0, i, PendingIntent.FLAG_NO_CREATE);
gps.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),
10 * 1000, pi);
Log.d("Service: ",
"GPS Service started and scheduled with AlarmManager");
Here is the class I created myself (not the one from your demo, though similar):
public class LocationReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle b = intent.getExtras();
Location loc = (Location) b.get(LocationPoller.EXTRA_LOCATION);
String msg;
if (loc == null)
{
loc = (Location) b.get(LocationPoller.EXTRA_LASTKNOWN);
if (loc == null)
{
msg = intent.getStringExtra(LocationPoller.EXTRA_ERROR);
}
else
{
msg = "TIMEOUT, lastKnown=" + loc.toString();
}
}
else
{
msg = loc.toString();
}
if (msg == null)
{
msg = "Invalid broadcast received!";
}
Log.d("GPS Broadcast: ", "Location: " + msg);
}
}
Nothing's happening. I assume this because I'm not seeing any info in my logcat, at all. Plus the PollerThread (if that's the right term) keeps piling up when I look at the debug view, as if they're all waiting for something but not sending any broadcasts.
What am I doing wrong? Ascertaining location via Network shouldn't take much time should it? Even if that was the issue, I should have gotten SOME feedback..
Here are the entries in my manifest's application tag:
<receiver android:name="com.commonsware.cwac.locpoll.LocationPoller" />
<receiver android:name=".LocationReceiver" />
<service android:name="com.commonsware.cwac.locpoll.LocationPollerService" />
LocationPoller is designed for much longer polling periods: an hour, not 10 seconds. I have never tested LocationPoller with that frequent of a polling period, nor do I ever intend to support LocationPoller with a polling period shorter than the DEFAULT_TIMEOUT of two minutes.
Hence, the first thing you should do is figure out why you are bothering with LocationPoller in the first place. The point behind LocationPoller is to be able to occasionally figure out where the device is, without your code necessarily already running (e.g., you want to automatically check into Foursquare every hour). If you need to find out where the device is every 10 seconds, you need to use LocationManager yourself from a foreground activity.
Assuming you are convinced that LocationPoller is still the right solution, the next thing you should do is extend your polling period to something more reasonable, like 5 minutes, and see if that helps.
If that does not help, then try running the demo/ project without modification. If that does not work, then there's some bug in LocationPoller, or some incompatibility in your device that LocationPoller is tripping over, and I'd need to do some investigation.
If the demo/ project does work, make a copy, confirm the copy works, and then slowly modify the copy to look more like what your production code has, until it stops working -- at that point, your last set of changes represent what broke LocationPoller, and we can figure out if that represents a bug in LocationPoller or a bug in your use of it.
I want to run some task (i.e. get my web site news page) periodically (once a week/ a day), even if my application is closed. Is it possible?
Yes it is, you need to look at the AlarmManager to setup a reoccurring "Alarm". This is better for battery life on the device, as unlike a service it does not run constantly in the background. The Alarm triggers a broadcast receiver which will execute your custom code.
As a final note - there are enum values for the timing of the Alarm including daily, half daily and many more although you can just set an actual value.
A good example can be found in the follow SO post:
Alarm Manager Example
Update
Newer features have been added to Android. If you are reading this then I would advise you now look into GcmNetworkManager. This optimises battery life and works pre-lollipop. For Lollipop onwards you can use JobScheduler. I would advise using these classes over the AlarmManager.
I think the best fit is GcmNetworkManager. Basically it has everything you need from AlarmManager plus persistence, so job can proceed executing after reboot.
Example:
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(5L)
.build();
mGcmNetworkManager.schedule(task);
As an alternative I'm comparing the current week:
Calendar cal = Calendar.getInstance();
int currentWeekOfYear = cal.get(Calendar.WEEK_OF_YEAR);
SharedPreferences sharedPreferences= this.getSharedPreferences("appInfo", 0);
int weekOfYear = sharedPreferences.getInt("weekOfYear", 0);
if(weekOfYear != currentWeekOfYear){
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("weekOfYear", currentWeekOfYear);
editor.commit();
// Your once a week code here
}
I'm not advocating this is better than the Alarm solution. I'm just showing a different approach.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Intent to launch the clock application on android
I have a widget that displays the time and if one taps on it, it launches the com.android.alarmclock/.AlarmClock activity with an PendingIntent. This works great before-Froyo, but with Froyo, I have to launch the com.android.deskclock/.AlarmClock. So I want to put in code that checks for the class existence and launch the appropriate activity/intent. Here is what I tried, but it does not work.
Intent alarmIntent = new Intent();
try {
if (Class.forName("com.android.deskclock.AlarmClock") != null) {
Log.i(TAG, "setting deskclock alarm -- must be Froyo!");
alarmIntent.setClassName("com.android.deskclock",
"com.android.deskclock.AlarmClock");
}
} catch (ClassNotFoundException e) {
Log.i(TAG, "setting alarmclock alarm -- must be Eclair!");
alarmIntent.setClassName("com.android.alarmclock",
"com.android.alarmclock.AlarmClock");
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_UPDATE_TIME_NOW,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.text_timeofday, pendingIntent);
It always thinks it is "Eclair" and therefore fails on Froyo. Is this the best approach, or should I check the application-level? I prefer to work with the class existence.
if (Class.forName("com.android.deskclock.AlarmClock") != null)
That won't work, because that class is not in your project. At most, it might be in some other project on the device.
There is no documented supported Intent for launching an alarm clock in the Android SDK. Your approach of hard-wiring in package and class names is fragile, as you're discovering. It won't work on some devices, if they do not have that application (e.g., replaced by one from the device manufacturer). Plus, as you've seen, it may change in future versions of Android. I am having a rough enough time trying to convince device manufacturers not to break the SDK; having third-party developers do it weakens my case.
That being said, the general way to see if something will respond to an Intent is to use PackageManager (e.g., queryIntentActivities()).