My app has a widget that shows today's date and need to be updated on midnight. The widget is defined in the manifest as
<manifest>
...
<application>
...
<receiver
android:name=".MyWidgetProviderClass"
android:label="MyLabel" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_icon_info" />
</receiver>
</application>
</manifest>
And the widget info file is
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/my_layout"
android:minHeight="40dp"
android:minWidth="294dp"
android:updatePeriodMillis="3600000" >
</appwidget-provider>
This causes the widget to get updated anytime between midnight and 1pm but I want to to get updated closer to midnight so I added to the app an intent receiver
<receiver
android:name=".MyWidgetUpdaterClass"
android:enabled="true" >
<intent-filter>
<action android:name="MyAction" />
</intent-filter>
</receiver>
and a static method
public static void setMidngintAlarms(Context context) {
Intent intent = new Intent("MyAction");
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, 0, intent, 0);
long interval = 24*60*60*1000;
long firstTime = SystemClock.elapsedRealtime() +
millisecondsToNextMidnight();
AlarmManager am = (AlarmManager)context.getSystemService(
Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, interval, pendingIntent);
}
(since alarm manager requests with the same intent overwriting each other there is not harm in calling setMidngintAlarms multiple times).
I tried calling setMidnightAlarms() from few places (from the app's main activity, from the AppWidgetProvider's onUpdate(), etc). Everything works well and the alarm manager intents are received and the widget is updated but only as long as the app runs. If I killed the app, the widgets stops updating on midnight.
Any idea how to cause the widgets to update on midnight? Do I need to add a service? If so how? Any example?
I am a little bit surprised how non trivial it is to get this basic functionality to work.
I resolve this problem by:
Start a service to listen to Intent.ACTION_TIME_TICK message.
Then send a broadcast to widget if Time TICKED. (At every minute).
Receive the broadcast in widget and judge weather it is the midnight by:
Code:
if (MyWidget.BROADCAST_TIME_TICK.equals(action)) {
//If it's midnight, then update.
int hour = Calendar.getInstance().get(Calendar.HOUR);
int minute = Calendar.getInstance().get(Calendar.MINUTE);
Utils.log(TAG, "time is : " + hour+":" + minute);
if (!(hour == 0 && minute == 0)) { //Only update at midnight's time tick.
return;
} else {
//Do the midnight stuff.
}
}
ad this to your manifest widget receiver
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="android.intent.action.DATE_CHANGED" />...
the change in date will trigger your onReceive() to fire up with the "android.intent.action.DATE_CHANGED" action
Related
In my code I have a broadcast reciever
<receiver
android:name=".alarm.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
<intent-filter>
<action android:name="com.BalDroid.YekNegah.alarm.dailyAction"
/>
</intent-filter>
</receiver>
I schedule alarm in this receiver in onReceive method
PendingIntent pi = PendingIntent.getBroadcast(context, AlarmRow.getId(mycursor), i, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= 21) {
AlarmManager.AlarmClockInfo alarmInfo = new AlarmManager.AlarmClockInfo(
mycal.getTimeInMillis(),pi);
mgr.setAlarmClock(alarmInfo,pi);
// Create a Pending intent to show Alarm Details
}
although receiver run but alarm not trigger with mgr.setAlarmClock. But when I use
mgr.setExactAndAllowWhileIdle alarm trigger
(because of setAlarmClock accuracy I have to use setAlarmClock in my code)
And when I schedule mgr.setAlarmClock from MainActivity (when start application manually) it works.
I cant find the solution!!.
(I don't know why is not work from receiver).
My app also called setAlarmClock on AlarmManager, however the event didn't trigger. The reason for me was the default restriction of background processes by the manufacturer(my phone is Xiaomi).
Go to Settings -> Your application and find background restriction options. Turn the restrictions off and setAlarmClock must work.
As a conclusion, the result depends on manufacturer's default settings.
Long time = prefs.getLong("dailynoti", 0);
Intent intent = new Intent(cn, NotificationReceiver.class);
intent.putExtra("Desc", "Description...");
PendingIntent pendingIntent = PendingIntent.getBroadcast(cn, 1055, intent,0);
AlarmManager alarmManager = (AlarmManager) cn.getSystemService(cn.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,time, AlarmManager.INTERVAL_DAY, pendingIntent);
and my mainifest file
<receiver
android:name="com.mypackage.NotificationReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
And this same code is use in same project but now in same project another module it will not work Broadcast Receiver isn't call at given time
my notification code is in Receiver file but Receiver class isn't call.
I checked all things like time is also get properly. so what is the problem . please help...
I used many solution like
PendingIntent pendingIntent = PendingIntent.getBroadcast(cn, 1055, intent, PendingIntent.FLAG_CANCEL_CURRENT
//FLAG_NO_CREATE
//FLAG_UPDATE_CURRENT
One approach that I think that will work is instead of alarmManager.setRepeating() use alarmManager.set() and when the alarm triggers then set the next alarm. This will give you almost accurate results. Why almost? Because due to Doze mode introduced in Android M. So this will give you between 0 to +5 min delay.
I am using alarm manger to set broadcast on 2am every day. Alarm manager working fine in normal scenarios but it failing in below scenario.
I am scheduling alarm manager #1am, change the time to 1.58am and switch off the device and switch on the phone after 5mins(i.e 2.03am). In this scenario my alarm is not triggering for same day and every other days.
Can some one help me with this scenario
//Alarm manager
//timeToTwoAm is calculate time to 2AM from current time
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,timeToTwoAm,
AlarmManager.INTERVAL_DAY, alarmIntent);
Your alarms will not be persisted. After a reboot all your registered alarms are removed.
2 solutions would be helpful:
1. Register a BOOT_COMPLETED broadcast receiver:
AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".notification.alarm.OnBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
And in your OnBootReceiver simply register your alarms at AlarmManager again.
2. Use JobScheduler-API (>= API 21) or GcmNetworkManager (PlayServices)
Depending on your use case it would also be possible to use the new GcmNetworkMaanger, which allows persisting a Job during reboot.
Add Service to your Manifest:
<service
android:name=".LoadWeatherService"
android:exported="true" android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
In your service declare the things to do:
public class LoadWeatherService extends GcmTaskService {
public void onInitializeTasks() {
super.onInitializeTasks();
// Reregister your Job after update of Google Play Services
}
#Override
public int onRunTask(TaskParams taskParams) {
// Do your stuff
return GcmNetworkManager.RESULT_SUCCESS;
}
}
Subscribe your Job
String tag = "myperiodicTask";
PeriodicTask periodicTask = new PeriodicTask.Builder().setService(LoadWeatherService.class)
.setRequiredNetwork(Task.NETWORK_STATE_CONNECTED).setPeriod(60L).setFlex(10L)
.setTag(tag).setPersisted(true).build();
GcmNetworkManager.getInstance(this).schedule(periodicTask);
Please notice: This is only a sample from my app, you have to adjust this regarding your needs.
Further Reading about GcmNetworkManager: https://developers.google.com/cloud-messaging/network-manager
I am trying to implement an alarm, and therefore my app has 2 activities: main one (where the user sets an alarm) and the 'ringing' one which is displayed when the alarm is actually triggered. Here is how I send an intent for AlarmManager to call the 'ringing' window:
public void scheduleAlarm(View view) {
Intent intent = new Intent(this, WakeUp.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent wakeUp = PendingIntent.getActivity(this, 123, intent, 0);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(this.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calculateMillis(), wakeUp); // setExact is pretty much made for setting alarms anyway
}
private long calculateMillis() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, 0);
return cal.getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
}
In my manifest I have the following:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".WakeUpWithMath"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".WakeUp"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/title_activity_wake_up"
android:theme="#style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
</application>
I have tested it multiple times and with different values for the calculateMillis (even mocked to return 30000) yet the result is always the same: right after calling alarmManager.setExactit displayes the 'ringing' activity and does not wait for the time to pass at first.
What have I missed? Is the manifest configured wrong? do I need to use a <receiver> tag? if so, how should I configure it?
setExact uses absolute time, not relative time. Use the time returned by cal.getTimeInMillis() without subtracting current time.
I use Broadcast Receiver, WidgetProvider and Configure Activity. Activity starts during the creation of a widget. Widgets are updated every 20 seconds.
private PendingIntent service = null;
Intent intent = new Intent(context, AlarmReceiver.class);
if (service == null) {
service = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), 1000 * 20,
service);
I whant to update widgets when I change time or timezone on my phone. Widgets are updated when I change the time ahead. But when I change the time back, nothing happens.
I've already added to the manifest
<receiver android:name=".AlarmReceiver" >
<intent-filter>
<action android:name="android.intent.ACTION_TIMEZONE_CHANGED" />
<action android:name="android.intent.ACTION_TIME" />
</intent-filter>
</receiver>
In the Broadcast Receiver I'm updating widgets.
Please refer to
http://developer.android.com/reference/android/content/Intent.html#ACTION_TIMEZONE_CHANGED
They should be
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />