In Power to the People we learned that it's very bad for your app to use the CPU unnecessarily. In Power to the Developers part 1 we learned a few easy ways to make your code stop burning CPU cycles. Now we're going to learn a more complicated mechanism for the same thing. You'll use this technique if, for various reasons, the previous techniques won't work for you (a prime example being that you're writing a home screen plug in). This entry assumes that you have a basic understanding of Power Manager, which you can get by reading Power to the System.
Wouldn't it be nice if?
The previous techniques were to not burn CPU cycles (i.e. animate something) if your app wasn't in the foreground, and to only animate for so long after your app received input. But what if your code is hosted in some other app and you don't really know if you're in the foreground? And what if you don't really ever receive input? Wouldn't it be nice if there was some component in the system that kept track of all of this? And wouldn't it be even better if that component could tell us when it's time for us to clamp down and stop burning cycles?
In fact, that component does exist, and it can tell you what's going on in the system. The component is Power Manager and it has a mechanism for signaling you whenever a System Power State transition happens. (If you're asking, "What's a System Power State transition?" go back and read Power to the System again.)
That's a lot of states
So, what's the best way to deal with the fact that there are seven different System Power States, some used only on Pocket PC, some used only on Smartphone, and some overlapping? Easy answer: "Don't." You only need to worry about one state. If the system is in the "On" state, you can animate. If it's not, don't. This is nice and clean and safe. If in the next version we add some bizarre new state that happens in weird circumstances, your code will continue to work (because it's unlikely you'll want to be animating while in that state).
Note that you do want to stop animating every time the system tells you that it's no longer in the On state. But you do not want to start animating whenever it tells you that it has switched back to the On state. What if your app isn't in the foreground? There may be cases where you have to do this, but, by default you should think of this as a way to turn animations off, not to turn them on.
Sounds great. Where do I sign up?
Hold on. Things aren't quite as rosy as they may seem. I'll bet you're thinking you can use this mechanism for stopping your animations when the backlight goes off. Unfortunately, there is no ideal way to do that. First, the BacklightOff state didn't get added until WM5. So you won't even hear about a state transition when the backlight goes off in WM 2003 SE and previous versions.
Second, in the safe way to use this method, the "BacklightOff" state is represented as "On." There are documented flags for the different states, and, since they're documented, you can rely on them. And On and BacklightOff use the same flags.
Now, if you like to live on the edge, there is also a string that gives the state's name. If you read that string, you can tell the difference between On and BacklightOff. Trouble is, the definition of those strings is not documented. That means that they could be changed in the future. And that means that, if you rely on them, your code could break. Yes, this sucks.
However, if you use this technique, you will know if the screen goes off on SP and if the system goes to sleep on PPC. And those are very good times to turn your animation off.
Damn the torpedoes, we're going multithreaded!
So, let's talk about the real reason I'm describing this technique in "part 2: the hard way." In the end, getting notified that a state transition happens requires that you wait on an event. And that pretty much requires that you spin up a thread to do it.
Writing multithreaded code is hard. If you've never done it before, I suggest against your first attempt being the code that you're relying on to not annihilate your user's battery life. Yes, it would have been great if we'd made Power Manager send windows messages. Yes, it would have been fantastic if we'd written a managed wrapper for it. We didn't.
Also, I'm a system/drivers developer. I write managed code in my spare time. The pInvokes required to do this in managed code are just beyond my capabilities. I can show you how to do it in Native, but Managed is out for this technique. At least for now.
I've updated the AnimateSample to show how to do this. In the Native directory you'll find an "Animate3" alongside the existing Animate2. I made 3 by copying 2 and then adding in the PowerManager stuff. So you should be able to Windiff the two .cpp files and see just what's changed. I'm pretty sure I wrote more lines of comments than I did lines of code, so hopefully it's understandable.
This is the end...
This is the last of my power entries. I hope you found them informative. Of course, if they generate enough questions to justify a new entry (as apposed to just answering them in comments) I'll do an answers one.