Merge "Add the clipToOutline by just using the clipPathOp"
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4879be6..345ff82 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -551,9 +551,9 @@
         public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
         public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
         public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
+        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
         // These are on the lower bits used for the command; if they change
         // we need to write another int of data.
-        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
         public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
         public static final int STATE_AUDIO_ON_FLAG = 1<<22;
         public static final int STATE_VIDEO_ON_FLAG = 1<<21;
@@ -572,9 +572,26 @@
         // The wake lock that was acquired at this point.
         public HistoryTag wakelockTag;
 
-        public static final int EVENT_NONE = 0;
-        public static final int EVENT_PROC_STARTED = 1;
-        public static final int EVENT_PROC_FINISHED = 2;
+        public static final int EVENT_FLAG_START = 0x8000;
+        public static final int EVENT_FLAG_FINISH = 0x4000;
+
+        // No event in this item.
+        public static final int EVENT_NONE = 0x0000;
+        // Event is about a process that is running.
+        public static final int EVENT_PROC = 0x0001;
+        // Event is about an application package that is in the foreground.
+        public static final int EVENT_FOREGROUND = 0x0002;
+        // Event is about an application package that is at the top of the screen.
+        public static final int EVENT_TOP = 0x0003;
+        // Number of event types.
+        public static final int EVENT_COUNT = 0x0004;
+
+        public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
+        public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
+        public static final int EVENT_FOREGROUND_START = EVENT_FOREGROUND | EVENT_FLAG_START;
+        public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH;
+        public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START;
+        public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
@@ -942,6 +959,14 @@
                 SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
     };
 
+    public static final String[] HISTORY_EVENT_NAMES = new String[] {
+            "null", "proc", "fg", "top"
+    };
+
+    public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
+            "Nl", "Pr", "Fg", "Tp"
+    };
+
     /**
      * Returns the time in microseconds that wifi has been on while the device was
      * running on battery.
@@ -2497,6 +2522,9 @@
                         case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
                             pw.print(checkin ? "f" : "failure");
                             break;
+                        case BatteryManager.BATTERY_HEALTH_COLD:
+                            pw.print(checkin ? "c" : "cold");
+                            break;
                         default:
                             pw.print(oldHealth);
                             break;
@@ -2536,25 +2564,23 @@
                 printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
                         HISTORY_STATE_DESCRIPTIONS, !checkin);
                 if (rec.eventCode != HistoryItem.EVENT_NONE) {
-                    switch (rec.eventCode) {
-                        case HistoryItem.EVENT_PROC_STARTED:
-                            pw.print(checkin ? ",PrSt=" : " procstart=");
-                            break;
-                        case HistoryItem.EVENT_PROC_FINISHED:
-                            pw.print(checkin ? ",PrFn=" : " procfin=");
-                            break;
-                        default:
-                            if (checkin) {
-                                pw.print(",?cmd_");
-                                pw.print(rec.eventCode);
-                                pw.print("=");
-                            } else {
-                                pw.print(" cmd_");
-                                pw.print(rec.eventCode);
-                                pw.print("=");
-                            }
-                            break;
+                    pw.print(checkin ? "," : " ");
+                    if ((rec.eventCode&HistoryItem.EVENT_FLAG_START) != 0) {
+                        pw.print("+");
+                    } else if ((rec.eventCode&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+                        pw.print("-");
                     }
+                    String[] eventNames = checkin ? HISTORY_EVENT_CHECKIN_NAMES
+                            : HISTORY_EVENT_NAMES;
+                    int idx = rec.eventCode & ~(HistoryItem.EVENT_FLAG_START
+                            | HistoryItem.EVENT_FLAG_FINISH);
+                    if (idx >= 0 && idx < eventNames.length) {
+                        pw.print(eventNames[idx]);
+                    } else {
+                        pw.print(checkin ? "Ev" : "event");
+                        pw.print(idx);
+                    }
+                    pw.print("=");
                     if (checkin) {
                         pw.print(rec.eventTag.poolIdx);
                     } else {
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 905dcb0..f59ef0f6d 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -115,6 +115,13 @@
         }
     }
 
+    /** @hide */
+    public void removeAt(int index) {
+        System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+        System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
+        mSize--;
+    }
+
     /**
      * Adds a mapping from the specified key to the specified value,
      * replacing the previous mapping from the specified key if there
@@ -191,6 +198,11 @@
         return mValues[index];
     }
 
+    /** @hide */
+    public void setValueAt(int index, boolean value) {
+        mValues[index] = value;
+    }
+
     /**
      * Returns the index for which {@link #keyAt} would return the
      * specified key, or a negative number if the specified
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index e7e8006f..c22a5e9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -54,7 +54,7 @@
  */
 public class BatteryStatsHelper {
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String TAG = BatteryStatsHelper.class.getSimpleName();
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 21d2e52..82dcbdb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -45,6 +45,7 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 
@@ -77,7 +78,7 @@
  */
 public final class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -87,7 +88,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 77 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 79 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -178,6 +179,9 @@
 
     boolean mShuttingDown;
 
+    HashMap<String, SparseBooleanArray>[] mActiveEvents
+            = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
     long mHistoryBaseTime;
     boolean mHaveBatteryLevel = false;
     boolean mRecordingHistory = true;
@@ -1521,15 +1525,25 @@
     static final int DELTA_TIME_INT = 0xffffe;    // The delta is a following int
     static final int DELTA_TIME_ABS = 0xffffd;    // Following is an entire abs update.
     // Flag in delta int: a new battery level int follows.
-    static final int DELTA_BATTERY_LEVEL_FLAG   = 0x00400000;
+    static final int DELTA_BATTERY_LEVEL_FLAG   = 0x00100000;
     // Flag in delta int: a new full state and battery status int follows.
-    static final int DELTA_STATE_FLAG           = 0x00800000;
+    static final int DELTA_STATE_FLAG           = 0x00200000;
     // Flag in delta int: contains a wakelock tag.
-    static final int DELTA_WAKELOCK_FLAG        = 0x01000000;
+    static final int DELTA_WAKELOCK_FLAG        = 0x00400000;
     // Flag in delta int: contains an event description.
-    static final int DELTA_EVENT_FLAG           = 0x02000000;
+    static final int DELTA_EVENT_FLAG           = 0x00800000;
     // These upper bits are the frequently changing state bits.
-    static final int DELTA_STATE_MASK           = 0xfc000000;
+    static final int DELTA_STATE_MASK           = 0xff000000;
+
+    // These are the pieces of battery state that are packed in to the upper bits of
+    // the state int that have been packed in to the first delta int.  They must fit
+    // in DELTA_STATE_MASK.
+    static final int STATE_BATTERY_STATUS_MASK  = 0x00000007;
+    static final int STATE_BATTERY_STATUS_SHIFT = 29;
+    static final int STATE_BATTERY_HEALTH_MASK  = 0x00000007;
+    static final int STATE_BATTERY_HEALTH_SHIFT = 26;
+    static final int STATE_BATTERY_PLUG_MASK    = 0x00000003;
+    static final int STATE_BATTERY_PLUG_SHIFT   = 24;
 
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
@@ -1620,9 +1634,17 @@
     }
 
     private int buildStateInt(HistoryItem h) {
-        return ((((int)h.batteryStatus)<<28)&0xf0000000)
-                | ((((int)h.batteryHealth)<<24)&0x0f000000)
-                | ((((int)h.batteryPlugType)<<22)&0x00c00000)
+        int plugType = 0;
+        if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) {
+            plugType = 1;
+        } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) {
+            plugType = 2;
+        } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
+            plugType = 3;
+        }
+        return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<<STATE_BATTERY_STATUS_SHIFT)
+                | ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT)
+                | ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT)
                 | (h.states&(~DELTA_STATE_MASK));
     }
 
@@ -1670,9 +1692,23 @@
         if ((firstToken&DELTA_STATE_FLAG) != 0) {
             int stateInt = src.readInt();
             cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
-            cur.batteryStatus = (byte)((stateInt>>28)&0xf);
-            cur.batteryHealth = (byte)((stateInt>>24)&0xf);
-            cur.batteryPlugType = (byte)((stateInt>>22)&0x3);
+            cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
+                    & STATE_BATTERY_STATUS_MASK);
+            cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
+                    & STATE_BATTERY_HEALTH_MASK);
+            cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
+                    & STATE_BATTERY_PLUG_MASK);
+            switch (cur.batteryPlugType) {
+                case 1:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
+                    break;
+                case 2:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+                    break;
+                case 3:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+                    break;
+            }
             cur.numReadInts += 1;
             if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
                     + Integer.toHexString(stateInt)
@@ -1968,6 +2004,45 @@
 
     public void noteEventLocked(int code, String name, int uid) {
         uid = mapUid(uid);
+        if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+            int idx = code&~HistoryItem.EVENT_FLAG_START;
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+            if (active == null) {
+                active = new HashMap<String, SparseBooleanArray>();
+                mActiveEvents[idx] = active;
+            }
+            SparseBooleanArray uids = active.get(name);
+            if (uids == null) {
+                uids = new SparseBooleanArray();
+                active.put(name, uids);
+            }
+            if (uids.get(uid)) {
+                // Already set, nothing to do!
+                return;
+            }
+            uids.put(uid, true);
+        } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+            int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+            if (active == null) {
+                // not currently active, nothing to do.
+                return;
+            }
+            SparseBooleanArray uids = active.get(name);
+            if (uids == null) {
+                // not currently active, nothing to do.
+                return;
+            }
+            idx = uids.indexOfKey(uid);
+            if (idx < 0 || !uids.valueAt(idx)) {
+                // not currently active, nothing to do.
+                return;
+            }
+            uids.removeAt(idx);
+            if (uids.size() <= 0) {
+                active.remove(name);
+            }
+        }
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
@@ -5125,6 +5200,7 @@
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenOff = 0;
         }
+        initActiveHistoryEventsLocked(mSecRealtime);
     }
 
     private void resetAllStatsLocked() {
@@ -5172,6 +5248,23 @@
         clearHistoryLocked();
     }
 
+    private void initActiveHistoryEventsLocked(long nowRealtime) {
+        for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+            HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+            if (active == null) {
+                continue;
+            }
+            for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
+                SparseBooleanArray uids = ent.getValue();
+                for (int j=0; j<uids.size(); j++) {
+                    if (uids.valueAt(j)) {
+                        addHistoryEventLocked(nowRealtime, i, ent.getKey(), uids.keyAt(j));
+                    }
+                }
+            }
+        }
+    }
+
     void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
         if (oldScreenOn) {
             int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
@@ -5221,12 +5314,14 @@
             // battery was last full, or the level is at 100, or
             // we have gone through a significant charge (from a very low
             // level to a now very high level).
+            boolean reset = false;
             if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
                     || (mDischargeCurrentLevel < 20 && level >= 80)) {
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
+                reset = true;
             }
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
@@ -5249,6 +5344,9 @@
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenOff = 0;
             doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+            if (reset) {
+                initActiveHistoryEventsLocked(mSecRealtime);
+            }
         } else {
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 17bb3e0..be2df04 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -28,6 +28,7 @@
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
+import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
@@ -595,12 +596,7 @@
                 break;
             }
         }
-        if (anyForeground != proc.foregroundServices) {
-            proc.foregroundServices = anyForeground;
-            if (oomAdj) {
-                mAm.updateOomAdjLocked();
-            }
-        }
+        mAm.updateProcessForegroundLocked(proc, anyForeground, oomAdj);
     }
 
     private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a0de8d8..8975d12 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -921,11 +921,25 @@
     long mLowRamTimeSinceLastIdle = 0;
 
     /**
-     * If RAM is currently low, when that horrible situatin started.
+     * If RAM is currently low, when that horrible situation started.
      */
     long mLowRamStartTime = 0;
 
     /**
+     * For reporting to battery stats the current top application.
+     */
+    private String mCurResumedPackage = null;
+    private int mCurResumedUid = -1;
+
+    /**
+     * For reporting to battery stats the apps currently running foreground
+     * service.  The ProcessMap is package/uid tuples; each of these contain
+     * an array of the currently foreground processes.
+     */
+    final ProcessMap<ArrayList<ProcessRecord>> mForegroundPackages
+            = new ProcessMap<ArrayList<ProcessRecord>>();
+
+    /**
      * This is set if we had to do a delayed dexopt of an app before launching
      * it, to increasing the ANR timeouts in that case.
      */
@@ -2767,7 +2781,7 @@
                 mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                         ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_STARTED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_START,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
@@ -4727,7 +4741,7 @@
                 mPidsSelfLocked.remove(pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4772,7 +4786,7 @@
                         mHeavyWeightProcess.userId, 0));
                 mHeavyWeightProcess = null;
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4861,7 +4875,7 @@
         app.curAdj = app.setAdj = -100;
         app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
         app.forcingToForeground = null;
-        app.foregroundServices = false;
+        updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
         app.debugging = false;
         app.cached = false;
@@ -5564,7 +5578,7 @@
                     return;
                 }
                 pr.forcingToForeground = null;
-                pr.foregroundServices = false;
+                updateProcessForegroundLocked(pr, false, false);
             }
             updateOomAdjLocked();
         }
@@ -12115,7 +12129,25 @@
             if (!brief) {
                 if (!isCompact) {
                     pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
-                    pw.println(" kB");
+                    pw.print(" kB (status ");
+                    switch (mLastMemoryLevel) {
+                        case ProcessStats.ADJ_MEM_FACTOR_NORMAL:
+                            pw.println("normal)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                            pw.println("moderate)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                            pw.println("low)");
+                            break;
+                        case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                            pw.println("critical)");
+                            break;
+                        default:
+                            pw.print(mLastMemoryLevel);
+                            pw.println(")");
+                            break;
+                    }
                     pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
                             + memInfo.getFreeSizeKb()); pw.print(" kB (");
                             pw.print(cachedPss); pw.print(" cached pss + ");
@@ -12330,7 +12362,7 @@
         app.unlinkDeathRecipient();
         app.makeInactive(mProcessStats);
         app.forcingToForeground = null;
-        app.foregroundServices = false;
+        updateProcessForegroundLocked(app, false, false);
         app.foregroundActivities = false;
         app.hasShownUi = false;
         app.hasAboveClient = false;
@@ -12464,7 +12496,7 @@
                 mPidsSelfLocked.remove(app.pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
                     app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -15285,8 +15317,66 @@
                 reportingProcessState, now);
     }
 
+    final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
+            boolean oomAdj) {
+        if (isForeground != proc.foregroundServices) {
+            proc.foregroundServices = isForeground;
+            ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
+                    proc.info.uid);
+            if (isForeground) {
+                if (curProcs == null) {
+                    curProcs = new ArrayList<ProcessRecord>();
+                    mForegroundPackages.put(proc.info.packageName, proc.info.uid, curProcs);
+                }
+                if (!curProcs.contains(proc)) {
+                    curProcs.add(proc);
+                    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_FOREGROUND_START,
+                            proc.info.packageName, proc.info.uid);
+                }
+            } else {
+                if (curProcs != null) {
+                    if (curProcs.remove(proc)) {
+                        mBatteryStatsService.noteEvent(
+                                BatteryStats.HistoryItem.EVENT_FOREGROUND_FINISH,
+                                proc.info.packageName, proc.info.uid);
+                        if (curProcs.size() <= 0) {
+                            mForegroundPackages.remove(proc.info.packageName, proc.info.uid);
+                        }
+                    }
+                }
+            }
+            if (oomAdj) {
+                updateOomAdjLocked();
+            }
+        }
+    }
+
     private final ActivityRecord resumedAppLocked() {
-        return mStackSupervisor.resumedAppLocked();
+        ActivityRecord act = mStackSupervisor.resumedAppLocked();
+        String pkg;
+        int uid;
+        if (act != null) {
+            pkg = act.packageName;
+            uid = act.info.applicationInfo.uid;
+        } else {
+            pkg = null;
+            uid = -1;
+        }
+        // Has the UID or resumed package name changed?
+        if (uid != mCurResumedUid || (pkg != mCurResumedPackage
+                && (pkg == null || !pkg.equals(mCurResumedPackage)))) {
+            if (mCurResumedPackage != null) {
+                mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_FINISH,
+                        mCurResumedPackage, mCurResumedUid);
+            }
+            mCurResumedPackage = pkg;
+            mCurResumedUid = uid;
+            if (mCurResumedPackage != null) {
+                mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_START,
+                        mCurResumedPackage, mCurResumedUid);
+            }
+        }
+        return act;
     }
 
     final boolean updateOomAdjLocked(ProcessRecord app) {