Be smarter about determining when we can stop idle maintenance.

The device idle service now knows when the system is actively
doing significant things (syncs, jobs, alarms, downloads).  It
uses this, when in an idle maintenance window, to determine when
it can end that window early -- when such work is no longer
happening.

For now this just allows us to shorten the windows.  In the future
we should use this to allow us to expand the windows to a longer
potential time, adjusting future windows to shorter durations if
earlier ones use more time.  This will allow us to batch occasional
long operations (such as downloads) into one window, making up
for that with much shorter later windows.

Change-Id: Ie482abd50bc43be9a8917a769a5175851eee4ec4
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a5ddc12..f9d9950 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -115,6 +115,7 @@
     final LocalLog mLog = new LocalLog(TAG);
 
     AppOpsManager mAppOps;
+    DeviceIdleController.LocalService mLocalDeviceIdleController;
 
     final Object mLock = new Object();
 
@@ -897,6 +898,8 @@
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             mConstants.start(getContext().getContentResolver());
             mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+            mLocalDeviceIdleController
+                    = LocalServices.getService(DeviceIdleController.LocalService.class);
         }
     }
 
@@ -2468,10 +2471,9 @@
 
     private class AlarmHandler extends Handler {
         public static final int ALARM_EVENT = 1;
-        public static final int MINUTE_CHANGE_EVENT = 2;
-        public static final int DATE_CHANGE_EVENT = 3;
-        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
-        public static final int LISTENER_TIMEOUT = 5;
+        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
+        public static final int LISTENER_TIMEOUT = 3;
+        public static final int REPORT_ALARMS_ACTIVE = 4;
         
         public AlarmHandler() {
         }
@@ -2511,6 +2513,12 @@
                     mDeliveryTracker.alarmTimedOut((IBinder) msg.obj);
                     break;
 
+                case REPORT_ALARMS_ACTIVE:
+                    if (mLocalDeviceIdleController != null) {
+                        mLocalDeviceIdleController.setAlarmsActive(msg.arg1 != 0);
+                    }
+                    break;
+
                 default:
                     // nope, just ignore it
                     break;
@@ -2740,6 +2748,7 @@
             }
             mBroadcastRefCount--;
             if (mBroadcastRefCount == 0) {
+                mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 0).sendToTarget();
                 mWakeLock.release();
                 if (mInFlight.size() > 0) {
                     mLog.w("Finished all dispatches with " + mInFlight.size()
@@ -2873,6 +2882,7 @@
                         alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1,
                         true);
                 mWakeLock.acquire();
+                mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1).sendToTarget();
             }
             final InFlight inflight = new InFlight(AlarmManagerService.this,
                     alarm.operation, alarm.listener, alarm.workSource, alarm.uid,