Based on a checkbox preference I enable a bunch of receivers and I broadcast to them so they schedule a bunch of alarms for themselves. EDIT : The receivers both set up the alarms and wait for the Broadcast from the AlarmManager (as is clear from the onReceive posted).
SettingsActivity
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue instanceof Boolean) {
boolean enable = (Boolean) newValue;
Monitor.enableMonitoring(getApplicationContext(), enable);
return true;
}
return false;
}
Monitor.enableMonitoring
public static void enableMonitoring(Context ctx, boolean enable) {
Resources resources = ctx.getResources();
CharSequence ac_setup_alarm = resources
.getText(R.string.intent_action_setup_alarm);
CharSequence ac_cancel_alarm = resources
.getText(R.string.intent_action_cancel_alarm);
// if only I could do the above in a static way someclass once and for all
Intent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm));
if (enable) {
Log.d(_tag, "enable receivers / setup alarms int : " + i);
_enableDisableReceivers(ctx, enable); // enable == true
ctx.sendBroadcast(i);
} else {
Log.d(_tag, "cancel alarms / disable receivers int : " + i);
ctx.sendBroadcast(i);
_enableDisableReceivers(ctx, enable); // enable != true (will disable)
}
}
questions
Why
Intent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm));won't get received whileIntent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm), Uri.EMPTY, ctx, BatteryMonitoringReceiver.class);will get received as expected ?
Manifest :<receiver android:name="di.k23b.hw3.receivers.BatteryMonitoringReceiver" android:enabled="false" > <intent-filter> <action android:name="@string/intent_action_setup_alarm" /> <action android:name="@string/intent_action_cancel_alarm" /> <action android:name="@string/intent_action_monitor" /> </intent-filter> </receiver>I would expect implicit intents to propagate to a registered receiver - why do I have to make those implicit intents explicit ? I expect this to be easy to answer - I just overlooked/didn't quite get something in the docs :)
Do I need to make sure that the call to
_enableDisableReceivers(ctx, true);will actually enable the receivers before I broadcast the Intent ? Similarly do I have to wait till the intent is received before I call_enableDisableReceivers(ctx, false);to disable the receivers ? If yes how should I go about that ?(Bonus off the first answer I got) It is not possible to use LocalBroadcastManager with the AlarmaManager - With a boot receiver ? (I guess no)
For completeness :
private static void _enableDisableReceivers(Context ctx, boolean enable) {
Log.d(_tag, "enable/disable receivers");
for (Class<? extends BaseReceiver> receiver : RECEIVERS)
BaseReceiver.enable(ctx, enable, receiver);
}
where :
public static void enable(Context context, boolean enable,
Class<? extends BaseReceiver> receiver) {
PackageManager pacman = context.getPackageManager();
final ComponentName componentName = new ComponentName(context, receiver);
Log.d(_tag, componentName.toString());
final int state = (enable) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
pacman.setComponentEnabledSetting(componentName, state,
PackageManager.DONT_KILL_APP);
Log.d(_tag,
"pacman :" + pacman.getComponentEnabledSetting(componentName));
}
And for mind boggling completeness (BaseMonitoringReceiver) :
@Override
final public void onReceive(Context context, Intent intent) {
// FIXME : possible NPE below ?
final String action = intent.getAction(); // can intent==null ?
Log.w(TAG, "" + action);
resources = context.getResources();
ac_setup_alarm = resources.getText(R.string.intent_action_setup_alarm);
ac_cancel_alarm = resources
.getText(R.string.intent_action_cancel_alarm);
ac_monitor = resources.getText(R.string.intent_action_monitor);
if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setPackage(RECEIVERS_PACKAGE_NAME);// TODO: needed?
final boolean enable = ac_setup_alarm.equals(action);
setupAlarm(context, enable);
} else if (ac_monitor.equals(action)) {
// monitoring - got broadcast from ALARM
Class<? extends WakefulIntentService> serviceClass = getService();
WakefulIntentService.sendWakefulWork(context, serviceClass);
} else {
Log.w(TAG, "Received bogus intent : " + intent);
return;
}
}
Subclasses (like the BatteryMonitoringReceiver in the manifest) just override getService() - neat no ? Notice onReceive is final.