You will find in this document
1. Basic research on Android AlarmManager API
2. Useful api references while working with AlarmManager
3. Not-so-intuitive truths about AlarmManager
4. Sample code
5. Downloadable Sample project
6. Finally what I call the AlarmManager Predicates
satya - Friday, June 11, 2010 11:02:32 PM
Alarm uses a broadcast to call the target functionality
This is done through an intent.
what about invoking an activity? or calling a service?
satya - Friday, June 11, 2010 11:05:07 PM
A key statement at the link above
If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched. To prevent this, your BroadcastReceiver and Service will need to implement a separate wake lock policy to ensure that the phone continues running until the service becomes available.
satya - Saturday, June 12, 2010 11:50:46 AM
Creating an intent to call your class when it goes off
Intent intent = new Intent(AlarmController.this,
YourBroadcastReceiver.class);
PendingIntent pi =
PendingIntent.getBroadcast(AlarmController.this,
0, intent, 0);
satya - Saturday, June 12, 2010 11:56:18 AM
showing a toast
// Tell the user about what we did.
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(<some-context>,
R.string.one_shot_scheduled,
Toast.LENGTH_LONG);
mToast.show();
satya - Saturday, June 12, 2010 12:03:20 PM
Possible toast durations
LENGTH_LONG
LENGTH_SHORT
satya - Saturday, June 12, 2010 12:05:38 PM
Figuring out 30 secs from now
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 30);
satya - Saturday, June 12, 2010 12:07:44 PM
Telling the alarm to go off once
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
satya - Saturday, June 12, 2010 12:47:12 PM
Cancelling the alarms
Intent intent = new Intent(AlarmController.this, RepeatingAlarm.class);
PendingIntent sender = PendingIntent.getBroadcast(AlarmController.this,
0, intent, 0);
// And cancel the alarm.
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.cancel(sender);
satya - Saturday, June 12, 2010 12:49:41 PM
alarm boot
alarm boot
Search Android Developers Group for: alarm boot
Search Android Beginers Group for: alarm boot
satya - Saturday, June 12, 2010 12:51:42 PM
alarm not set
alarm not set
Search Google for: alarm not set
Search Android Developers Group for: alarm not set
Search Android Beginers Group for: alarm not set
satya - Saturday, June 12, 2010 1:02:17 PM
alarm preferences
alarm preferences
Search Google for: alarm preferences
Search Android Developers Group for: alarm preferences
Search Android Beginers Group for: alarm preferences
satya - Saturday, June 12, 2010 1:03:35 PM
android saving alarm manager settings
android saving alarm manager settings
satya - Saturday, June 12, 2010 1:07:19 PM
alarms lost
alarms lost
Search Google for: alarms lost
Search Android Developers Group for: alarms lost
Search Android Beginers Group for: alarms lost
satya - Saturday, June 12, 2010 1:17:08 PM
Read this long thread on stopping an app and alarms
satya - Monday, June 14, 2010 9:34:10 PM
rtc_wakeup
rtc_wakeup
Search Android Developers Group for: rtc_wakeup
Search Android Beginers Group for: rtc_wakeup
satya - Monday, June 14, 2010 11:05:00 PM
Cancelling an alarm intent
For cancelling intents, two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.
satya - Monday, June 14, 2010 11:05:23 PM
This equivalence is defined by filterEquals
satya - Monday, June 14, 2010 11:10:15 PM
Sending alarm once
private void sendAlarmOnce()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Print to the debug view that we are
//scheduling at a specific time
String s = Utils.getDateTimeString(cal);
appendText("Schdeduling alarm at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
PendingIntent pi =
PendingIntent.getBroadcast(
this, //context
0, //request id - not used
intent, //intent to be delivered
0); //pending intent flags
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
}
satya - Monday, June 14, 2010 11:13:08 PM
work with a repeating alarm
private void sendRepeatingAlarm()
{
Calendar cal = Utils.getTimeAfterInSecs(30);
//Calendar cal = Utils.getTodayAt(11);
String s = Utils.getDateTimeString(cal);
appendText("Schdeduling alarm at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi =
PendingIntent.getBroadcast(
this, //context
0, //request id - not used
intent, //intent to be delivered
0); //pending intent flags
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 5*1000, pi);
//am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
}
Start the first alarm 30 secs from now. Then repeat it every 5 secs.
The code also inclues a commented out section to start the alarm at 11:00 hrs today and you can then repeat it at the interval you would like. Notice however that when you use he wake option you will be waking the device.
satya - Monday, June 14, 2010 11:18:23 PM
AlarmManager partial wakeup?
AlarmManager partial wakeup?
Search Google for: AlarmManager partial wakeup?
Search Android Developers Group for: AlarmManager partial wakeup?
Search Android Beginers Group for: AlarmManager partial wakeup?
Search Google Code for: AlarmManager partial wakeup?
Search Android Issues Database for: AlarmManager partial wakeup?
satya - Monday, June 14, 2010 11:20:38 PM
Cancelling the alarm based on intent equivalence
private void cancelRepeatingAlarm()
{
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi =
PendingIntent.getBroadcast(
this, //context
0, //request id - not used
intent, //intent to be delivered
0); //pending intent flags
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.cancel(pi);
}
satya - Tuesday, June 15, 2010 4:31:39 PM
flag_one_shot
flag_one_shot
Search Google for: flag_one_shot
Search Android Developers Group for: flag_one_shot
Search Android Beginers Group for: flag_one_shot
satya - Tuesday, June 15, 2010 4:42:44 PM
As per Dianne from one of the threads
You need to have something unique in the intent action, type, data, or categories to get different pending intent objects.
Having data (action, type, Uri, categories, component) that is unique within the intent is the way to do this. You can also use the request code to disambiguate them.
request id is ignored as far as delivering the pending intent goes, because broadcasts don't (currently) have requests codes. It is not ignored for intent matching, but taken as another identifying part of the pending intent. And none of this has anything specifically to do with the alarm manager, which just gets pending intents, and calls equals() and send() on them.
This is actually just a general Intent thing -- if you make a subclass of Intent and pass it to pretty much any system API, your subclass is going to be lost as it moves across processes. One could argue that Intent itself should be final, but I am loath to make things final when they don't absolutely have to be, and end up in annoying situations like String. (And anyway, the SDK is published, so it is too late to make any of these APIs final anyway.)
satya - Tuesday, June 15, 2010 4:43:46 PM
The above is taken from the following topic
satya - Tuesday, June 15, 2010 4:46:47 PM
pendingintent requestid
pendingintent requestid
Search Google for: pendingintent requestid
Search Android Developers Group for: pendingintent requestid
Search Android Beginers Group for: pendingintent requestid
satya - Tuesday, June 15, 2010 5:08:46 PM
Cancel Alarms
Cancel Alarms
Search Google for: Cancel Alarms
Search Android Developers Group for: Cancel Alarms
Search Android Beginers Group for: Cancel Alarms
satya - Monday, June 21, 2010 10:24:25 PM
A simple utility for creatinga pending intent for an alarm manager
private PendingIntent
getDistinctPendingIntent(Intent intent, int requestId)
{
PendingIntent pi =
PendingIntent.getBroadcast(
mContext, //context
requestId, //request id
intent, //intent to be delivered
0);
//pending intent flags
//PendingIntent.FLAG_ONE_SHOT);
return pi;
}
satya - Monday, June 21, 2010 10:27:20 PM
On FLAG_ONE_SHOT
I would have thought, when I am scheduling an intent for a single shot alarm, that I could use flag_one_shot. The idea is that the scheduled intent will be taken off after that.
however it seem to work fine even for a repeating alarm. Not sure what gives. but again I haven't done lot of testing.
satya - Monday, June 21, 2010 10:32:08 PM
Here is a single shot alarm that uses the request id
/*
* An alarm can invoke a broadcast request
* at a specified time.
* The name of the broadcast receiver is explicitly
* specified in the intent.
*/
public void sendAlarmOnce()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Print to the debug view that we are
//scheduling at a specific time
String s = Utils.getDateTimeString(cal);
mReportTo.reportBack(tag, "Schdeduling alarm at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
PendingIntent pi =
PendingIntent.getBroadcast(
mContext, //context
1, //request id, used for disambiguating this intent
intent, //intent to be delivered
PendingIntent.FLAG_ONE_SHOT); //pending intent flags
// Schedule the alarm!
AlarmManager am =
(AlarmManager)
mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
pi);
}
satya - Monday, June 21, 2010 10:35:14 PM
Here is the code for the test receiver
public class TestReceiver extends BroadcastReceiver
{
private static final String tag = "TestReceiver";
@Override
public void onReceive(Context context, Intent intent)
{
Utils.logThreadSignature();
Log.d("TestReceiver", "intent=" + intent);
String message = intent.getStringExtra("message");
Log.d(tag, message);
}
}
satya - Monday, June 21, 2010 10:37:26 PM
Ofcourse you will have to define the receiver in the manifest
<receiver android:name=".TestReceiver"/>
satya - Monday, June 21, 2010 10:39:47 PM
Here is how to schedule a repeat alarm
/*
* An alarm can invoke a broadcast request
* starting at a specified time and at
* regular intervals.
*
* Uses the same intent as above
* but a distinct request id to avoid conflicts
* with the single shot alarm above.
*
* Uses getDistinctPendingIntent() utility.
*/
public void sendRepeatingAlarm()
{
Calendar cal = Utils.getTimeAfterInSecs(30);
//Calendar testcal = Utils.getTodayAt(11);
String s = Utils.getDateTimeString(cal);
this.mReportTo.reportBack(tag,
"Schdeduling Repeating alarm in 5 sec interval starting at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this.mContext, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am =
(AlarmManager)
this.mContext.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
5*1000, //5 secs
pi);
}
satya - Monday, June 21, 2010 10:44:07 PM
here is how you cancel the repeating alarm
/*
* An alarm can be stopped by canceling the intent.
* You will need to have a copy of the intent
* to cancel it.
*
* The intent needs to have the same signature
* and request id.
*/
public void cancelRepeatingAlarm()
{
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this.mContext, TestReceiver.class);
//To cancel, extra is not necessary to be filled in
//intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 2);
// Schedule the alarm!
AlarmManager am =
(AlarmManager)
this.mContext.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
this.mReportTo.reportBack(tag,"You shouldn't see alarms again");
}
satya - Monday, June 21, 2010 10:47:41 PM
Whats up with scheduling the same intent for multiple alarms
/*
* Same intent cannot be scheduled multiple times.
* If you do, only the last one will take affect.
*
* Notice you are using the same request id.
*/
public void scheduleSameIntentMultipleTimes()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
Calendar cal2 = Utils.getTimeAfterInSecs(35);
Calendar cal3 = Utils.getTimeAfterInSecs(40);
Calendar cal4 = Utils.getTimeAfterInSecs(45);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Print to the debug view that we are
//scheduling at a specific time
String s = Utils.getDateTimeString(cal);
mReportTo.reportBack(tag, "Schdeduling alarm at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
PendingIntent pi = this.getDistinctPendingIntent(intent, 1);
// Schedule the alarm!
AlarmManager am =
(AlarmManager)
mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
pi);
am.set(AlarmManager.RTC_WAKEUP,
cal2.getTimeInMillis(),
pi);
am.set(AlarmManager.RTC_WAKEUP,
cal3.getTimeInMillis(),
pi);
am.set(AlarmManager.RTC_WAKEUP,
cal4.getTimeInMillis(),
pi);
}
satya - Monday, June 21, 2010 10:51:54 PM
Using request id to distinguish intents
/*
* Same intent can be scheduled multiple times
* if you change the request id on the pending intent.
* Request id identifies an intent as a unique intent.
*/
public void scheduleDistinctIntents()
{
//Get the instance in time that is
//30 secs from now.
Calendar cal = Utils.getTimeAfterInSecs(30);
Calendar cal2 = Utils.getTimeAfterInSecs(35);
Calendar cal3 = Utils.getTimeAfterInSecs(40);
Calendar cal4 = Utils.getTimeAfterInSecs(45);
//If you want to point to 11:00 hours today.
//Calendar cal = Utils.getTodayAt(11);
//Print to the debug view that we are
//scheduling at a specific time
String s = Utils.getDateTimeString(cal);
mReportTo.reportBack(tag, "Schdeduling alarm at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(mContext, TestReceiver.class);
intent.putExtra("message", "Single Shot Alarm");
// Schedule the alarms!
AlarmManager am =
(AlarmManager)
mContext.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
getDistinctPendingIntent(intent,1));
am.set(AlarmManager.RTC_WAKEUP,
cal2.getTimeInMillis(),
getDistinctPendingIntent(intent,2));
am.set(AlarmManager.RTC_WAKEUP,
cal3.getTimeInMillis(),
getDistinctPendingIntent(intent,3));
am.set(AlarmManager.RTC_WAKEUP,
cal4.getTimeInMillis(),
getDistinctPendingIntent(intent,4));
}
satya - Monday, June 21, 2010 10:56:42 PM
Testing the primacy of "alarm" and "intent"
/*
* It is not the alarm that matters
* but the pending intent.
* Even with a repeating alarm for an intent,
* if you schedule the same intent again
* for one time, the later one takes affect.
*
* It is as if you are setting the
* alarm on an existing intent multiple
* times and not the other way around.
*/
public void alarmIntentPrimacy()
{
Calendar cal = Utils.getTimeAfterInSecs(30);
String s = Utils.getDateTimeString(cal);
this.mReportTo.reportBack(tag,
"Schdeduling Repeating alarm in 5 sec interval starting at: " + s);
//Get an intent to invoke
//TestReceiver class
Intent intent =
new Intent(this.mContext, TestReceiver.class);
intent.putExtra("message", "Repeating Alarm");
PendingIntent pi = getDistinctPendingIntent(intent,0);
AlarmManager am =
(AlarmManager)
this.mContext.getSystemService(Context.ALARM_SERVICE);
this.mReportTo.reportBack(tag,"Setting a repeat alarm 5 secs duration");
am.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
5*1000, //5 secs
pi);
this.mReportTo.reportBack(tag,"Setting a onetime alarm on the same intent");
am.set(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
pi);
this.mReportTo.reportBack(tag,"The later alarm, one time one, takes precedence");
}
satya - Monday, June 21, 2010 10:59:29 PM
Here are some date/time utility functions used
public static Calendar getTimeAfterInSecs(int secs)
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND,secs);
return cal;
}
public static Calendar getCurrentTime()
{
Calendar cal = Calendar.getInstance();
return cal;
}
public static Calendar getTodayAt(int hours)
{
Calendar today = Calendar.getInstance();
Calendar cal = Calendar.getInstance();
cal.clear();
int year = today.get(Calendar.YEAR);
int month = today.get(Calendar.MONTH);
//represents the day of the month
int day = today.get(Calendar.DATE);
cal.set(year,month,day,hours,0,0);
return cal;
}
public static String getDateTimeString(Calendar cal)
{
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");
df.setLenient(false);
String s = df.format(cal.getTime());
return s;
}
satya - Tuesday, June 22, 2010 11:01:12 AM
You can download a sample project here (zip file link)
You can download a sample project here (zip file link)
This zip file has all of the code above and also a driver (a set of menus) to invoke each of the functions mentioned above.
You can see the logcat to see how it behaves.
The project also includes the test receiver.
satya - Tuesday, June 22, 2010 11:27:56 AM
AlarmManager Predicates
satya - Tuesday, July 13, 2010 6:21:17 PM
flag_one_shot
flag_one_shot
Search Google for: flag_one_shot
Search Android Developers Group for: flag_one_shot
Search Android Beginers Group for: flag_one_shot
satya - Tuesday, July 13, 2010 6:33:08 PM
Nature of pending intent
If I create a pending intent twice with the same equality (which doesnt include the extras) then as I understand I get back a reference to the same "token" or a pending intent. This will let me cancel it!!!
Am I then to understand that I am really "fetching" an intent and not creating it??
satya - Tuesday, July 13, 2010 6:39:43 PM
flag_cancel_current
The docs say that this will cancel the current pending intent. When you dont do this probably the extra data in the new intent will not make it to the previous intent and you get back a reference to the previous pending intent.
the doc advises that you will do this so that you prevent previous intents from firing because in your mind that firing is invalid because you want to do somethign different with the newly acquired extras.
If you dont mind firing the old ones, then we are advised, to use the flag_update_current
satya - Tuesday, July 13, 2010 6:40:58 PM
flag_no_create
This will return null if the intent doesnt exist. Perhaps one will use this to locate a previous pending intent and cancel it.
satya - Tuesday, July 13, 2010 6:47:47 PM
flag_update_current
The docs say
if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.
This again shows that we are fundamentally locating an event when we issue a pending event. And in this case we are overloading with the new extras.
Significantly it seem to be wrong to think of a PendingIntent as a message!!
However when you attach a requestid to it, it seem to behave like a message
satya - Tuesday, July 13, 2010 6:55:53 PM
Pending Intent Dianne
Pending Intent Dianne
Search Google for: Pending Intent Dianne
Search Android Developers Group for: Pending Intent Dianne
Search Android Beginers Group for: Pending Intent Dianne
satya - Tuesday, July 13, 2010 7:02:44 PM
An interesting thread to look at on pending intents
satya - Tuesday, July 13, 2010 7:13:02 PM
Here is another recommendation from Dianne
No, I mean setting the explicit component to your broadcast receiver component on the Intent class. I strongly strongly recommend this for this kind of situation where you want someone to deliver some specific thing to a component in your app. Please read the Intent java doc for more info.
satya - Tuesday, July 13, 2010 7:14:55 PM
More on it ...
Different request codes is a perfectly fine way to do it.
That said... I would be -very- suspicious about the code you posted where you are effectively creating random identities for your pending intents. In most of the places where one uses a pending intent, you give it to something that holds on to it indefinitely, so you need to be able to recover the previous pending intent so you can give it back to have it unregistered. That is why the API works the way it does. This API is really not intended to generate tons of pending intents whose lifetime is not being managed.
satya - Tuesday, July 13, 2010 7:28:04 PM
flag_one_shot
As per the docs this seem to set it once and the cancel it right after sending it one time. This is a property of the pending intent and not the intent.
what happens if there is a pending intent already? will the new flags override those old flags??
satya - Tuesday, July 13, 2010 9:33:42 PM
Here is an implementation of the AlarmManagerService.java
Here is an implementation of the AlarmManagerService.java
It is available as
com/android/server/AlarmManagerService.java
satya - Tuesday, July 13, 2010 9:56:54 PM
Here is a link to various other implementations of services
satya - Tuesday, July 13, 2010 10:56:59 PM
set removelocked alarm
set removelocked alarm
Search Google for: set removelocked alarm
Search Android Developers Group for: set removelocked alarm
Search Android Beginers Group for: set removelocked alarm
satya - Tuesday, July 13, 2010 11:31:47 PM
Here is the remove as part of a set
160 public void setRepeating(int type, long triggerAtTime, long interval,
161 PendingIntent operation) {
162 if (operation == null) {
163 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
164 return;
165 }
166 synchronized (mLock) {
167 Alarm alarm = new Alarm();
168 alarm.type = type;
169 alarm.when = triggerAtTime;
170 alarm.repeatInterval = interval;
171 alarm.operation = operation;
172
173 // Remove this alarm if already scheduled.
174 removeLocked(operation);
175
176 if (localLOGV) Slog.v(TAG, "set: " + alarm);
177
178 int index = addAlarmLocked(alarm);
179 if (index == 0) {
180 setLocked(alarm);
181 }
182 }
183 }
satya - Monday, July 19, 2010 9:48:42 AM
I should have guessed it: Just look at Cancel to see why "set" behaves the way it does
As it turned out I was looking at the wrong method to understand the alarm manager behavior. I was overly focused on the "set" methods to understand it.
There is no indication in the set method that the "pendingintent" is a key on which the alarming timing is set.
However if we look at "cancel" method this becomes quite clear. A cancel operation takes a pendingintent and cancels the alarm. If we were allowed "multiple" alarms for a given pendign intent, what would be the meaning of cancelling an alarm based on a "pendingintent"?? Will it cancel all the alarms?? So in short for "cancel" to work to cancel an "alarm" the "alarm" and the corresponding "pending intent" must be "one to one".
Had I focused on "cancel" this would have become apparent lot more sooner. Well there it is.
satya - 3/8/2014 8:00:49 PM
See the updates to Android Alarm manager as of 2014 here