Merge change 360 into donut

* changes:
  location: Location Manager wakelock cleanup, phase 1
diff --git a/Android.mk b/Android.mk
index 4bd1220..de5f5f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -297,12 +297,6 @@
 
 framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework)
 
-web_docs_sample_code_flags := \
-		-hdf android.hasSamples 1 \
-		-samplecode samples/ApiDemos guide/samples/ApiDemos "API Demos" \
-		-samplecode samples/LunarLander guide/samples/LunarLander "Lunar Lander" \
-		-samplecode samples/NotePad guide/samples/NotePad "Note Pad"
-
 sample_dir := development/samples
 
 web_docs_sample_code_flags := \
@@ -314,6 +308,19 @@
 		-samplecode $(sample_dir)/NotePad \
 		            guide/samples/NotePad "Note Pad"
 
+# SDK version identifiers used in the published docs. 
+
+# major[.minor] version for SDK. Typically identical to the 
+# most current Android platform version included in the SDK package. 
+framework_docs_SDK_VERSION :=  1.5
+# release version for SDK (ie "Release x")
+framework_docs_SDK_REL_ID :=   1
+framework_docs_SDK_CURRENT_DIR := $(framework_docs_SDK_VERSION)_r$(framework_docs_SDK_REL_ID)
+
+framework_docs_LOCAL_DROIDDOC_OPTIONS += \
+		-hdf sdk.version $(framework_docs_SDK_VERSION) \
+		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
+		-hdf sdk.current $(framework_docs_SDK_CURRENT_DIR)
 
 # ====  static html in the sdk ==================================
 include $(CLEAR_VARS)
@@ -346,7 +353,7 @@
 
 static_doc_index_redirect := $(out_dir)/index.html
 $(static_doc_index_redirect): \
-		$(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP)
+	$(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP)
 	$(hide) mkdir -p $(dir $@)
 	$(hide) $(ACP) $< $@
 
@@ -371,10 +378,10 @@
 LOCAL_MODULE := online-sdk
 
 LOCAL_DROIDDOC_OPTIONS:= \
-	$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-	$(web_docs_sample_code_flags) \
-	-toroot / \
-    -hdf android.whichdoc online
+		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		$(web_docs_sample_code_flags) \
+		-toroot / \
+		-hdf android.whichdoc online
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 0e9102f..39d36de 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -89,7 +89,7 @@
     /**
      * Bump the version on this if the checkin format changes.
      */
-    private static final int BATTERY_STATS_CHECKIN_VERSION = 4;
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 5;
     
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -100,6 +100,7 @@
     private static final String PROCESS_DATA = "pr";
     private static final String SENSOR_DATA = "sr";
     private static final String WAKELOCK_DATA = "wl";
+    private static final String KERNEL_WAKELOCK_DATA = "kwl";
     private static final String NETWORK_DATA = "nt";
     private static final String USER_ACTIVITY_DATA = "ua";
     private static final String BATTERY_DATA = "bt";
@@ -126,7 +127,7 @@
          *
          * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
          */
-        public abstract int getCount(int which);
+        public abstract int getCountLocked(int which);
 
         /**
          * Temporary for debugging.
@@ -145,7 +146,7 @@
          *
          * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
          */
-        public abstract int getCount(int which);
+        public abstract int getCountLocked(int which);
 
         /**
          * Returns the total time in microseconds associated with this Timer for the
@@ -155,7 +156,7 @@
          * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
          * @return a time in microseconds
          */
-        public abstract long getTotalTime(long batteryRealtime, int which);
+        public abstract long getTotalTimeLocked(long batteryRealtime, int which);
         
         /**
          * Temporary for debugging.
@@ -518,6 +519,8 @@
      * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
      */
     public abstract long computeRealtime(long curTime, int which);
+    
+    public abstract Map<String, ? extends Timer> getKernelWakelockStats();
 
     private final static void formatTime(StringBuilder out, long seconds) {
         long days = seconds / (60 * 60 * 24);
@@ -607,14 +610,14 @@
         
         if (timer != null) {
             // Convert from microseconds to milliseconds with rounding
-            long totalTimeMicros = timer.getTotalTime(batteryRealtime, which);
+            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
             long totalTimeMillis = (totalTimeMicros + 500) / 1000;
             
-            int count = timer.getCount(which);
+            int count = timer.getCountLocked(which);
             if (totalTimeMillis != 0) {
                 sb.append(linePrefix);
                 sb.append(formatTimeMs(totalTimeMillis));
-                sb.append(name);
+                sb.append(name != null ? name : "");
                 sb.append(' ');
                 sb.append('(');
                 sb.append(count);
@@ -637,18 +640,17 @@
      * @return the line prefix
      */
     private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
-        String name, int which, String linePrefix) {
+            String name, int which, String linePrefix) {
         long totalTimeMicros = 0;
         int count = 0;
         if (timer != null) {
-            totalTimeMicros = timer.getTotalTime(now, which);
-            count = timer.getCount(which); 
+            totalTimeMicros = timer.getTotalTimeLocked(now, which);
+            count = timer.getCountLocked(which); 
         }
         sb.append(linePrefix);
         sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
         sb.append(',');
-        sb.append(name);
-        sb.append(',');
+        sb.append(name != null ? name + "," : "");
         sb.append(count);
         return ",";
     }
@@ -730,12 +732,12 @@
                     
                     Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
                     if (fullWakeTimer != null) {
-                        fullWakeLockTimeTotal += fullWakeTimer.getTotalTime(batteryRealtime, which);
+                        fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(batteryRealtime, which);
                     }
 
                     Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
                     if (partialWakeTimer != null) {
-                        partialWakeLockTimeTotal += partialWakeTimer.getTotalTime(
+                        partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
                             batteryRealtime, which);
                     }
                 }
@@ -783,6 +785,17 @@
                     getDischargeCurrentLevel());
         }
         
+        Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+        if (kernelWakelocks.size() > 0) {
+            for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
+                sb.setLength(0);
+                printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, "");
+
+                dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), 
+                        sb.toString());
+            }
+        }
+        
         for (int iu = 0; iu < NU; iu++) {
             final int uid = uidStats.keyAt(iu);
             Uid u = uidStats.valueAt(iu);
@@ -821,12 +834,12 @@
                     Uid.Wakelock wl = ent.getValue();
                     String linePrefix = "";
                     sb.setLength(0);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
-                            "f", which, linePrefix);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
-                            "p", which, linePrefix);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
-                            "w", which, linePrefix);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), 
+                            batteryRealtime, "f", which, linePrefix);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), 
+                            batteryRealtime, "p", which, linePrefix);
+                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), 
+                            batteryRealtime, "w", which, linePrefix);
                     
                     // Only log if we had at lease one wakelock...
                     if (sb.length() > 0) {
@@ -844,8 +857,8 @@
                     Timer timer = se.getSensorTime();
                     if (timer != null) {
                         // Convert from microseconds to milliseconds with rounding
-                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
-                        int count = timer.getCount(which);
+                        long totalTime = (timer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                        int count = timer.getCountLocked(which);
                         if (totalTime != 0) {
                             dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
                         }
@@ -971,6 +984,26 @@
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
         
+        Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+        if (kernelWakelocks.size() > 0) {
+            for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
+                
+                String linePrefix = ": ";
+                sb.setLength(0);
+                sb.append(prefix);
+                sb.append("  Kernel Wake lock ");
+                sb.append(ent.getKey());
+                linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, 
+                        linePrefix);
+                if (!linePrefix.equals(": ")) {
+                    sb.append(" realtime");
+                } else {
+                    sb.append(": (nothing executed)");
+                }
+                pw.println(sb.toString());
+            }
+        }
+    
         for (int iu = 0; iu < NU; iu++) {
             Uid u = uidStats.valueAt(iu);
             rxTotal += u.getTcpBytesReceived(which);
@@ -984,13 +1017,13 @@
                     
                     Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
                     if (fullWakeTimer != null) {
-                        fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTime(
+                        fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
                                 batteryRealtime, which);
                     }
 
                     Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
                     if (partialWakeTimer != null) {
-                        partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTime(
+                        partialWakeLockTimeTotalMicros += partialWakeTimer.getTotalTimeLocked(
                                 batteryRealtime, which);
                     }
                 }
@@ -1179,8 +1212,9 @@
                     Timer timer = se.getSensorTime();
                     if (timer != null) {
                         // Convert from microseconds to milliseconds with rounding
-                        long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
-                        int count = timer.getCount(which);
+                        long totalTime = (timer.getTotalTimeLocked(
+                                batteryRealtime, which) + 500) / 1000;
+                        int count = timer.getCountLocked(which);
                         //timer.logState();
                         if (totalTime != 0) {
                             sb.append(formatTimeMs(totalTime));
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index cd86fbe..e4412a3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -680,6 +680,8 @@
     /** @hide */
     public static final int PROC_SPACE_TERM = (int)' ';
     /** @hide */
+    public static final int PROC_TAB_TERM = (int)'\t';
+    /** @hide */
     public static final int PROC_COMBINE = 0x100;
     /** @hide */
     public static final int PROC_PARENS = 0x200;
@@ -693,6 +695,10 @@
     /** @hide */
     public static final native boolean readProcFile(String file, int[] format,
             String[] outStrings, long[] outLongs, float[] outFloats);
+    
+    /** @hide */
+    public static final native boolean parseProcLine(byte[] buffer, int startIndex, 
+            int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
 
     /**
      * Gets the total Pss value for a given process, in bytes.
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index b162a0e..0c9d980 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -444,27 +444,55 @@
         updatePausePlay();
     }
 
+    // There are two scenarios that can trigger the seekbar listener to trigger:
+    //
+    // The first is the user using the touchpad to adjust the posititon of the
+    // seekbar's thumb. In this case onStartTrackingTouch is called followed by
+    // a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
+    // We're setting the field "mDragging" to true for the duration of the dragging
+    // session to avoid jumps in the position in case of ongoing playback.
+    //
+    // The second scenario involves the user operating the scroll ball, in this
+    // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
+    // we will simply apply the updated position without suspending regular updates.
     private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
-        long duration;
         public void onStartTrackingTouch(SeekBar bar) {
             show(3600000);
-            duration = mPlayer.getDuration();
+
+            mDragging = true;
+
+            // By removing these pending progress messages we make sure
+            // that a) we won't update the progress while the user adjusts
+            // the seekbar and b) once the user is done dragging the thumb
+            // we will post one of these messages to the queue again and
+            // this ensures that there will be exactly one message queued up.
+            mHandler.removeMessages(SHOW_PROGRESS);
         }
-        public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) {
-            if (fromtouch) {
-                mDragging = true;
-                duration = mPlayer.getDuration();
-                long newposition = (duration * progress) / 1000L;
-                mPlayer.seekTo( (int) newposition);
-                if (mCurrentTime != null)
-                    mCurrentTime.setText(stringForTime( (int) newposition));
+
+        public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
+            if (!fromuser) {
+                // We're not interested in programmatically generated changes to
+                // the progress bar's position.
+                return;
             }
+
+            long duration = mPlayer.getDuration();
+            long newposition = (duration * progress) / 1000L;
+            mPlayer.seekTo( (int) newposition);
+            if (mCurrentTime != null)
+                mCurrentTime.setText(stringForTime( (int) newposition));
         }
+
         public void onStopTrackingTouch(SeekBar bar) {
             mDragging = false;
             setProgress();
             updatePausePlay();
             show(sDefaultTimeout);
+
+            // Ensure that progress is properly updated in the future,
+            // the call to show() does not guarantee this because it is a
+            // no-op if we are already showing.
+            mHandler.sendEmptyMessage(SHOW_PROGRESS);
         }
     };
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f492ad1..58a9be85 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -21,6 +21,7 @@
 import android.os.Parcel;
 import android.os.ParcelFormatException;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.SystemClock;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -33,7 +34,10 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * All information we are collecting about things that can happen that impact
@@ -48,7 +52,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 32;
+    private static final int VERSION = 34;
 
     private final File mFile;
     private final File mBackupFile;
@@ -63,11 +67,11 @@
     // elapsed time by the number of active timers to arrive at that timer's share of the time.
     // In order to do this, we must refresh each timer whenever the number of active timers
     // changes.
-    final ArrayList<Timer> mPartialTimers = new ArrayList<Timer>();
-    final ArrayList<Timer> mFullTimers = new ArrayList<Timer>();
-    final ArrayList<Timer> mWindowTimers = new ArrayList<Timer>();
-    final SparseArray<ArrayList<Timer>> mSensorTimers
-            = new SparseArray<ArrayList<Timer>>();
+    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
+    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
+            = new SparseArray<ArrayList<StopwatchTimer>>();
 
     // These are the objects that will want to do something when the device
     // is unplugged from power.
@@ -88,31 +92,33 @@
     long mLastRealtime;
     
     boolean mScreenOn;
-    Timer mScreenOnTimer;
+    StopwatchTimer mScreenOnTimer;
     
     int mScreenBrightnessBin = -1;
-    final Timer[] mScreenBrightnessTimer = new Timer[NUM_SCREEN_BRIGHTNESS_BINS];
+    final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
     
     Counter mInputEventCounter;
     
     boolean mPhoneOn;
-    Timer mPhoneOnTimer;
+    StopwatchTimer mPhoneOnTimer;
     
     int mPhoneSignalStrengthBin = -1;
-    final Timer[] mPhoneSignalStrengthsTimer = new Timer[NUM_SIGNAL_STRENGTH_BINS];
+    final StopwatchTimer[] mPhoneSignalStrengthsTimer = 
+            new StopwatchTimer[NUM_SIGNAL_STRENGTH_BINS];
     
     int mPhoneDataConnectionType = -1;
-    final Timer[] mPhoneDataConnectionsTimer = new Timer[NUM_DATA_CONNECTION_TYPES];
+    final StopwatchTimer[] mPhoneDataConnectionsTimer = 
+            new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
     
     boolean mWifiOn;
-    Timer mWifiOnTimer;
+    StopwatchTimer mWifiOnTimer;
     int mWifiOnUid = -1;
 
     boolean mWifiRunning;
-    Timer mWifiRunningTimer;
+    StopwatchTimer mWifiRunningTimer;
     
     boolean mBluetoothOn;
-    Timer mBluetoothOnTimer;
+    StopwatchTimer mBluetoothOnTimer;
     
     /**
      * These provide time bases that discount the time the device is plugged
@@ -135,6 +141,37 @@
     int mDischargeCurrentLevel;
     
     long mLastWriteTime = 0; // Milliseconds
+    
+    /*
+     * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
+     */
+    private final HashMap<String, SamplingTimer> mKernelWakelockStats = 
+            new HashMap<String, SamplingTimer>();
+    
+    public Map<String, ? extends SamplingTimer> getKernelWakelockStats() {
+        return mKernelWakelockStats;
+    }
+    
+    private static int sKernelWakelockUpdateVersion = 0;
+    
+    private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
+        Process.PROC_TAB_TERM|Process.PROC_OUT_STRING,                // 0: name
+        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 1: count
+        Process.PROC_TAB_TERM,
+        Process.PROC_TAB_TERM,
+        Process.PROC_TAB_TERM,
+        Process.PROC_TAB_TERM|Process.PROC_OUT_LONG,                  // 5: totalTime
+    };
+    
+    private final String[] mProcWakelocksName = new String[3];
+    private final long[] mProcWakelocksData = new long[3];
+    
+    /*
+     * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
+     * to mKernelWakelockStats.
+     */
+    private final Map<String, KernelWakelockStats> mProcWakelockFileStats = 
+            new HashMap<String, KernelWakelockStats>();
 
     // For debugging
     public BatteryStatsImpl() {
@@ -200,7 +237,7 @@
         }
 
         @Override
-        public int getCount(int which) {
+        public int getCountLocked(int which) {
             int val;
             if (which == STATS_LAST) {
                 val = mLastCount;
@@ -242,11 +279,9 @@
     /**
      * State for keeping track of timing information.
      */
-    public static final class Timer extends BatteryStats.Timer implements Unpluggable {
+    public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
         final int mType;
-        final ArrayList<Timer> mTimerPool;
-        
-        int mNesting;
+
         
         int mCount;
         int mLoadedCount;
@@ -281,24 +316,10 @@
          * power.
          */
         long mUnpluggedTime;
-
-        /**
-         * The last time at which we updated the timer.  If mNesting is > 0,
-         * subtract this from the current battery time to find the amount of
-         * time we have been running since we last computed an update.
-         */
-        long mUpdateTime;
         
-        /**
-         * The total time at which the timer was acquired, to determine if
-         * was actually held for an interesting duration.
-         */
-        long mAcquireTime;
-        
-        Timer(int type, ArrayList<Timer> timerPool,
-                ArrayList<Unpluggable> unpluggables, Parcel in) {
+        Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
             mType = type;
-            mTimerPool = timerPool;
+            
             mCount = in.readInt();
             mLoadedCount = in.readInt();
             mLastCount = in.readInt();
@@ -306,17 +327,19 @@
             mTotalTime = in.readLong();
             mLoadedTime = in.readLong();
             mLastTime = in.readLong();
-            mUpdateTime = in.readLong();
             mUnpluggedTime = in.readLong();
             unpluggables.add(this);
         }
 
-        Timer(int type, ArrayList<Timer> timerPool,
-                ArrayList<Unpluggable> unpluggables) {
+        Timer(int type, ArrayList<Unpluggable> unpluggables) {
             mType = type;
-            mTimerPool = timerPool;
             unpluggables.add(this);
         }
+
+        protected abstract long computeRunTimeLocked(long curBatteryRealtime);
+        
+        protected abstract int computeCurrentCountLocked();
+        
         
         public void writeToParcel(Parcel out, long batteryRealtime) {
             out.writeInt(mCount);
@@ -326,7 +349,6 @@
             out.writeLong(computeRunTimeLocked(batteryRealtime));
             out.writeLong(mLoadedTime);
             out.writeLong(mLastTime);
-            out.writeLong(mUpdateTime);
             out.writeLong(mUnpluggedTime);
         }
 
@@ -346,19 +368,15 @@
         }
 
         public void plug(long batteryUptime, long batteryRealtime) {
-            if (mNesting > 0) {
-                if (DEBUG && mType < 0) {
-                    Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
-                            + " old mTotalTime=" + mTotalTime
-                            + " old mUpdateTime=" + mUpdateTime);
-                }
-                mTotalTime = computeRunTimeLocked(batteryRealtime);
-                mUpdateTime = batteryRealtime;
-                if (DEBUG && mType < 0) {
-                    Log.v(TAG, "plug #" + mType
-                            + ": new mTotalTime=" + mTotalTime
-                            + " old mUpdateTime=" + mUpdateTime);
-                }
+            if (DEBUG && mType < 0) {
+                Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
+                        + " old mTotalTime=" + mTotalTime);
+            }
+            mTotalTime = computeRunTimeLocked(batteryRealtime);
+            mCount = computeCurrentCountLocked();
+            if (DEBUG && mType < 0) {
+                Log.v(TAG, "plug #" + mType
+                        + ": new mTotalTime=" + mTotalTime);
             }
         }
         
@@ -380,7 +398,7 @@
         }
 
         @Override
-        public long getTotalTime(long batteryRealtime, int which) {
+        public long getTotalTimeLocked(long batteryRealtime, int which) {
             long val;
             if (which == STATS_LAST) {
                 val = mLastTime;
@@ -397,12 +415,12 @@
         }
 
         @Override
-        public int getCount(int which) {
+        public int getCountLocked(int which) {
             int val;
             if (which == STATS_LAST) {
                 val = mLastCount;
             } else {
-                val = mCount;
+                val = computeCurrentCountLocked();
                 if (which == STATS_UNPLUGGED) {
                     val -= mUnpluggedCount;
                 } else if (which != STATS_TOTAL) {
@@ -414,14 +432,239 @@
         }
 
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + "mNesting=" + mNesting + " mCount=" + mCount
+            pw.println(prefix + " mCount=" + mCount
                     + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
                     + " mUnpluggedCount=" + mUnpluggedCount);
             pw.println(prefix + "mTotalTime=" + mTotalTime
                     + " mLoadedTime=" + mLoadedTime);
             pw.println(prefix + "mLastTime=" + mLastTime
                     + " mUnpluggedTime=" + mUnpluggedTime);
-            pw.println(prefix + "mUpdateTime=" + mUpdateTime
+        }
+        
+        
+        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+            long runTime = computeRunTimeLocked(batteryRealtime);
+            // Divide by 1000 for backwards compatibility
+            out.writeLong((runTime + 500) / 1000);
+            out.writeLong(((runTime - mLoadedTime) + 500) / 1000);
+            out.writeInt(mCount);
+            out.writeInt(mCount - mLoadedCount);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            // Multiply by 1000 for backwards compatibility
+            mTotalTime = mLoadedTime = in.readLong() * 1000;
+            mLastTime = in.readLong() * 1000;
+            mUnpluggedTime = mTotalTime;
+            mCount = mLoadedCount = in.readInt();
+            mLastCount = in.readInt();
+            mUnpluggedCount = mCount;
+        }
+    }
+    
+    public static final class SamplingTimer extends Timer {
+        
+        /**
+         * The most recent reported count from /proc/wakelocks.
+         */
+        int mCurrentReportedCount;
+
+        /**
+         * The reported count from /proc/wakelocks when unplug() was last
+         * called.
+         */
+        int mUnpluggedReportedCount;
+
+        /**
+         * The most recent reported total_time from /proc/wakelocks.
+         */ 
+        long mCurrentReportedTotalTime;
+
+
+        /**
+         * The reported total_time from /proc/wakelocks when unplug() was last
+         * called.
+         */
+        long mUnpluggedReportedTotalTime;
+
+        /**
+         * Whether we are currently in a discharge cycle.
+         */
+        boolean mInDischarge;
+
+        /**
+         * Whether we are currently recording reported values.
+         */
+        boolean mTrackingReportedValues;
+        
+        /*
+         * A sequnce counter, incremented once for each update of the stats.
+         */
+        int mUpdateVersion;
+        
+        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
+            super(0, unpluggables, in);
+            mCurrentReportedCount = in.readInt();
+            mUnpluggedReportedCount = in.readInt();
+            mCurrentReportedTotalTime = in.readLong();
+            mUnpluggedReportedTotalTime = in.readLong();
+            mTrackingReportedValues = in.readInt() == 1;
+            mInDischarge = inDischarge;
+        }
+        
+        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, 
+                boolean trackReportedValues) {
+            super(0, unpluggables);
+            mTrackingReportedValues = trackReportedValues;
+            mInDischarge = inDischarge;
+        }
+        
+        public void setStale() {
+            mTrackingReportedValues = false;
+            mUnpluggedReportedTotalTime = 0;
+            mUnpluggedReportedCount = 0;
+        }
+        
+        public void setUpdateVersion(int version) {
+            mUpdateVersion = version;
+        }
+        
+        public int getUpdateVersion() {
+            return mUpdateVersion;
+        }
+        
+        public void updateCurrentReportedCount(int count) {
+            if (mInDischarge && mUnpluggedReportedCount == 0) {
+                // Updating the reported value for the first time.
+                mUnpluggedReportedCount = count;
+                // If we are receiving an update update mTrackingReportedValues;
+                mTrackingReportedValues = true;
+            }
+            mCurrentReportedCount = count;
+        }
+        
+        public void updateCurrentReportedTotalTime(long totalTime) {
+            if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
+                // Updating the reported value for the first time.
+                mUnpluggedReportedTotalTime = totalTime;
+                // If we are receiving an update update mTrackingReportedValues;
+                mTrackingReportedValues = true;
+            }
+            mCurrentReportedTotalTime = totalTime;
+        }
+        
+        public void unplug(long batteryUptime, long batteryRealtime) {
+            super.unplug(batteryUptime, batteryRealtime);
+            if (mTrackingReportedValues) {
+                mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
+                mUnpluggedReportedCount = mCurrentReportedCount;
+            }
+            mInDischarge = true;
+        }
+
+        public void plug(long batteryUptime, long batteryRealtime) {
+            super.plug(batteryUptime, batteryRealtime);
+            mInDischarge = false;
+        }
+        
+        public void logState(Printer pw, String prefix) {
+            super.logState(pw, prefix);
+            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount 
+                    + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
+                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
+                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
+        }
+        
+        protected long computeRunTimeLocked(long curBatteryRealtime) {
+            return mTotalTime + (mInDischarge && mTrackingReportedValues 
+                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
+        }
+        
+        protected int computeCurrentCountLocked() {
+            return mCount + (mInDischarge && mTrackingReportedValues
+                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
+        }
+        
+        public void writeToParcel(Parcel out, long batteryRealtime) {
+            super.writeToParcel(out, batteryRealtime);
+            out.writeInt(mCurrentReportedCount);
+            out.writeInt(mUnpluggedReportedCount);
+            out.writeLong(mCurrentReportedTotalTime);
+            out.writeLong(mUnpluggedReportedTotalTime);
+            out.writeInt(mTrackingReportedValues ? 1 : 0);
+        }
+        
+        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+            super.writeSummaryFromParcelLocked(out, batteryRealtime);
+            out.writeLong(mCurrentReportedTotalTime);
+            out.writeInt(mCurrentReportedCount);
+            out.writeInt(mTrackingReportedValues ? 1 : 0);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            super.readSummaryFromParcelLocked(in);
+            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
+            mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
+            mTrackingReportedValues = in.readInt() == 1;
+        }
+    }
+    
+    /**
+     * State for keeping track of timing information.
+     */
+    public static final class StopwatchTimer extends Timer {
+        final ArrayList<StopwatchTimer> mTimerPool;
+        int mNesting;
+
+
+        /**
+         * The last time at which we updated the timer.  If mNesting is > 0,
+         * subtract this from the current battery time to find the amount of
+         * time we have been running since we last computed an update.
+         */
+        long mUpdateTime;
+        
+        /**
+         * The total time at which the timer was acquired, to determine if
+         * was actually held for an interesting duration.
+         */
+        long mAcquireTime;
+        
+
+        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
+                ArrayList<Unpluggable> unpluggables, Parcel in) {
+            super(type, unpluggables, in);
+            mTimerPool = timerPool;
+            mUpdateTime = in.readLong();
+        }
+
+        StopwatchTimer(int type, ArrayList<StopwatchTimer> timerPool,
+                ArrayList<Unpluggable> unpluggables) {
+            super(type, unpluggables);
+            mTimerPool = timerPool;
+        }
+        
+        public void writeToParcel(Parcel out, long batteryRealtime) {
+            super.writeToParcel(out, batteryRealtime);
+            out.writeLong(mUpdateTime);
+        }
+
+        public void plug(long batteryUptime, long batteryRealtime) {
+            if (mNesting > 0) {
+                if (DEBUG && mType < 0) {
+                    Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
+                }
+                super.plug(batteryUptime, batteryRealtime);
+                mUpdateTime = batteryRealtime;
+                if (DEBUG && mType < 0) {
+                    Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
+                }
+            }
+        }
+
+        public void logState(Printer pw, String prefix) {
+            super.logState(pw, prefix);
+            pw.println(prefix + "mNesting=" + mNesting + "mUpdateTime=" + mUpdateTime
                     + " mAcquireTime=" + mAcquireTime);
         }
         
@@ -484,12 +727,12 @@
         // Update the total time for all other running Timers with the same type as this Timer
         // due to a change in timer count
         private static void refreshTimersLocked(final BatteryStatsImpl stats,
-                final ArrayList<Timer> pool) {
+                final ArrayList<StopwatchTimer> pool) {
             final long realtime = SystemClock.elapsedRealtime() * 1000; 
             final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
             final int N = pool.size();
             for (int i=N-1; i>= 0; i--) {
-                final Timer t = pool.get(i);
+                final StopwatchTimer t = pool.get(i);
                 long heldTime = batteryRealtime - t.mUpdateTime;
                 if (heldTime > 0) {
                     t.mTotalTime += heldTime / N;
@@ -498,34 +741,146 @@
             }
         }
 
-        private long computeRunTimeLocked(long curBatteryRealtime) {
+        @Override
+        protected long computeRunTimeLocked(long curBatteryRealtime) {
             return mTotalTime + (mNesting > 0
                     ? (curBatteryRealtime - mUpdateTime)
                             / (mTimerPool != null ? mTimerPool.size() : 1)
                     : 0);
         }
 
-        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
-            long runTime = computeRunTimeLocked(batteryRealtime);
-            // Divide by 1000 for backwards compatibility
-            out.writeLong((runTime + 500) / 1000);
-            out.writeLong(((runTime - mLoadedTime) + 500) / 1000);
-            out.writeInt(mCount);
-            out.writeInt(mCount - mLoadedCount);
+        @Override
+        protected int computeCurrentCountLocked() {
+            return mCount;
         }
 
         void readSummaryFromParcelLocked(Parcel in) {
-            // Multiply by 1000 for backwards compatibility
-            mTotalTime = mLoadedTime = in.readLong() * 1000;
-            mLastTime = in.readLong() * 1000;
-            mUnpluggedTime = mTotalTime;
-            mCount = mLoadedCount = in.readInt();
-            mLastCount = in.readInt();
-            mUnpluggedCount = mCount;
+            super.readSummaryFromParcelLocked(in);
             mNesting = 0;
         }
     }
     
+    private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
+        
+        byte[] buffer = new byte[4096];
+        int len;
+        
+        try {
+            FileInputStream is = new FileInputStream("/proc/wakelocks");
+            len = is.read(buffer);
+            is.close();
+
+            if (len > 0) {
+                int i;
+                for (i=0; i<len; i++) {
+                    if (buffer[i] == '\0') {
+                        len = i;
+                        break;
+                    }
+                }
+            }
+        } catch (java.io.FileNotFoundException e) {
+            return null;
+        } catch (java.io.IOException e) {
+            return null;
+        }
+        
+        return parseProcWakelocks(buffer, len);
+    }
+    
+    private final Map<String, KernelWakelockStats> parseProcWakelocks(
+            byte[] wlBuffer, int len) {
+        String name;
+        int count;
+        long totalTime;
+        int startIndex, endIndex;
+        int numUpdatedWlNames = 0;
+
+        // Advance past the first line.
+        int i;
+        for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
+        startIndex = endIndex = i + 1;
+
+        synchronized(this) {
+            Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
+            
+            sKernelWakelockUpdateVersion++;
+            while (endIndex < len) {
+                for (endIndex=startIndex; 
+                        endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; 
+                        endIndex++);
+                endIndex++; // endIndex is an exclusive upper bound.
+
+                String[] nameStringArray = mProcWakelocksName;
+                long[] wlData = mProcWakelocksData;
+                Process.parseProcLine(wlBuffer, startIndex, endIndex, PROC_WAKELOCKS_FORMAT, 
+                        nameStringArray, wlData, null);
+                
+                name = nameStringArray[0];
+                count = (int) wlData[1];
+                // convert nanoseconds to microseconds with rounding.
+                totalTime = (wlData[2] + 500) / 1000;
+
+                if (name.length() > 0) {
+                    if (!m.containsKey(name)) {
+                        m.put(name, new KernelWakelockStats(count, totalTime, 
+                                sKernelWakelockUpdateVersion));
+                        numUpdatedWlNames++;
+                    } else {
+                        KernelWakelockStats kwlStats = m.get(name);
+                        if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
+                            kwlStats.mCount += count;
+                            kwlStats.mTotalTime += totalTime;
+                        } else {
+                            kwlStats.mCount = count;
+                            kwlStats.mTotalTime = totalTime;
+                            kwlStats.mVersion = sKernelWakelockUpdateVersion;
+                            numUpdatedWlNames++;
+                        }
+                    }
+                }              
+                startIndex = endIndex;
+            }
+
+            if (m.size() != numUpdatedWlNames) {
+                // Don't report old data.
+                Iterator<KernelWakelockStats> itr = m.values().iterator();
+                while (itr.hasNext()) {
+                    if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
+                        itr.remove();
+                    }
+                }
+            }
+            return m;
+        }
+    }
+    
+    private class KernelWakelockStats {
+        public int mCount;
+        public long mTotalTime;
+        public int mVersion;
+        
+        KernelWakelockStats(int count, long totalTime, int version) {
+            mCount = count;
+            mTotalTime = totalTime;
+            mVersion = version;
+        }
+    }
+    
+    /*
+     * Get the KernelWakelockTimer associated with name, and create a new one if one 
+     * doesn't already exist.
+     */
+    public SamplingTimer getKernelWakelockTimerLocked(String name) {
+        SamplingTimer kwlt = mKernelWakelockStats.get(name);
+        if (kwlt == null) {
+            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, 
+                    true /* track reported values */);
+            mKernelWakelockStats.put(name, kwlt);
+        }
+        return kwlt;
+    }
+    
     public void doUnplug(long batteryUptime, long batteryRealtime) {
         for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
             Uid u = mUidStats.valueAt(iu);
@@ -760,53 +1115,53 @@
     }
     
     @Override public long getScreenOnTime(long batteryRealtime, int which) {
-        return mScreenOnTimer.getTotalTime(batteryRealtime, which);
+        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
     
     @Override public long getScreenBrightnessTime(int brightnessBin,
             long batteryRealtime, int which) {
-        return mScreenBrightnessTimer[brightnessBin].getTotalTime(
+        return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
                 batteryRealtime, which);
     }
     
     @Override public int getInputEventCount(int which) {
-        return mInputEventCounter.getCount(which);
+        return mInputEventCounter.getCountLocked(which);
     }
     
     @Override public long getPhoneOnTime(long batteryRealtime, int which) {
-        return mPhoneOnTimer.getTotalTime(batteryRealtime, which);
+        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
     
     @Override public long getPhoneSignalStrengthTime(int strengthBin,
             long batteryRealtime, int which) {
-        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTime(
+        return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
                 batteryRealtime, which);
     }
     
     @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
-        return mPhoneDataConnectionsTimer[dataType].getCount(which);
+        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
     }
     
     @Override public long getPhoneDataConnectionTime(int dataType,
             long batteryRealtime, int which) {
-        return mPhoneDataConnectionsTimer[dataType].getTotalTime(
+        return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
                 batteryRealtime, which);
     }
     
     @Override public int getPhoneDataConnectionCount(int dataType, int which) {
-        return mPhoneDataConnectionsTimer[dataType].getCount(which);
+        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
     }
     
     @Override public long getWifiOnTime(long batteryRealtime, int which) {
-        return mWifiOnTimer.getTotalTime(batteryRealtime, which);
+        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
     
     @Override public long getWifiRunningTime(long batteryRealtime, int which) {
-        return mWifiRunningTimer.getTotalTime(batteryRealtime, which);
+        return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
     @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
-        return mBluetoothOnTimer.getTotalTime(batteryRealtime, which);
+        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
     
     @Override public boolean getIsOnBattery() {
@@ -836,13 +1191,13 @@
         long mStartedTcpBytesSent = -1;
         
         boolean mWifiTurnedOn;
-        Timer mWifiTurnedOnTimer;
+        StopwatchTimer mWifiTurnedOnTimer;
         
         boolean mFullWifiLockOut;
-        Timer mFullWifiLockTimer;
+        StopwatchTimer mFullWifiLockTimer;
         
         boolean mScanWifiLockOut;
-        Timer mScanWifiLockTimer;
+        StopwatchTimer mScanWifiLockTimer;
         
         Counter[] mUserActivityCounters;
         
@@ -868,9 +1223,9 @@
         
         public Uid(int uid) {
             mUid = uid;
-            mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables);
-            mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables);
-            mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables);
+            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
+            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
+            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
         }
 
         @Override
@@ -980,17 +1335,17 @@
         
         @Override 
         public long getWifiTurnedOnTime(long batteryRealtime, int which) {
-            return mWifiTurnedOnTimer.getTotalTime(batteryRealtime, which);
+            return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
         }
         
         @Override 
         public long getFullWifiLockTime(long batteryRealtime, int which) {
-            return mFullWifiLockTimer.getTotalTime(batteryRealtime, which);
+            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
         }
         
         @Override 
         public long getScanWifiLockTime(long batteryRealtime, int which) {
-            return mScanWifiLockTimer.getTotalTime(batteryRealtime, which);
+            return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
         }
         
         @Override
@@ -1013,7 +1368,7 @@
             if (mUserActivityCounters == null) {
                 return 0;
             }
-            return mUserActivityCounters[type].getCount(which);
+            return mUserActivityCounters[type].getCountLocked(which);
         }
         
         void initUserActivityLocked() {
@@ -1120,11 +1475,11 @@
             mTcpBytesReceivedAtLastUnplug = in.readLong();
             mTcpBytesSentAtLastUnplug = in.readLong();
             mWifiTurnedOn = false;
-            mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables, in);
+            mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables, in);
             mFullWifiLockOut = false;
-            mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in);
+            mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
             mScanWifiLockOut = false;
-            mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
+            mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
             if (in.readInt() == 0) {
                 mUserActivityCounters = null;
             } else {
@@ -1142,17 +1497,17 @@
             /**
              * How long (in ms) this uid has been keeping the device partially awake.
              */
-            Timer mTimerPartial;
+            StopwatchTimer mTimerPartial;
 
             /**
              * How long (in ms) this uid has been keeping the device fully awake.
              */
-            Timer mTimerFull;
+            StopwatchTimer mTimerFull;
 
             /**
              * How long (in ms) this uid has had a window keeping the device awake.
              */
-            Timer mTimerWindow;
+            StopwatchTimer mTimerWindow;
 
             /**
              * Reads a possibly null Timer from a Parcel.  The timer is associated with the
@@ -1161,13 +1516,13 @@
              * @param in the Parcel to be read from.
              * return a new Timer, or null.
              */
-            private Timer readTimerFromParcel(int type, ArrayList<Timer> pool,
+            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
                     ArrayList<Unpluggable> unpluggables, Parcel in) {
                 if (in.readInt() == 0) {
                     return null;
                 }
 
-                return new Timer(type, pool, unpluggables, in);
+                return new StopwatchTimer(type, pool, unpluggables, in);
             }
 
             void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -1198,24 +1553,24 @@
 
         public final class Sensor extends BatteryStats.Uid.Sensor {
             final int mHandle;
-            Timer mTimer;
+            StopwatchTimer mTimer;
             
             public Sensor(int handle) {
                 mHandle = handle;
             }
 
-            private Timer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
+            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
                     Parcel in) {
                 if (in.readInt() == 0) {
                     return null;
                 }
 
-                ArrayList<Timer> pool = mSensorTimers.get(mHandle);
+                ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
                 if (pool == null) {
-                    pool = new ArrayList<Timer>();
+                    pool = new ArrayList<StopwatchTimer>();
                     mSensorTimers.put(mHandle, pool);
                 }
-                return new Timer(0, pool, unpluggables, in);
+                return new StopwatchTimer(0, pool, unpluggables, in);
             }
 
             void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -1816,32 +2171,32 @@
             return ss;
         }
 
-        public Timer getWakeTimerLocked(String name, int type) {
+        public StopwatchTimer getWakeTimerLocked(String name, int type) {
             Wakelock wl = mWakelockStats.get(name);
             if (wl == null) {
                 wl = new Wakelock();
                 mWakelockStats.put(name, wl);
             }
-            Timer t = null;
+            StopwatchTimer t = null;
             switch (type) {
                 case WAKE_TYPE_PARTIAL:
                     t = wl.mTimerPartial;
                     if (t == null) {
-                        t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
+                        t = new StopwatchTimer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
                         wl.mTimerPartial = t;
                     }
                     return t;
                 case WAKE_TYPE_FULL:
                     t = wl.mTimerFull;
                     if (t == null) {
-                        t = new Timer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
+                        t = new StopwatchTimer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
                         wl.mTimerFull = t;
                     }
                     return t;
                 case WAKE_TYPE_WINDOW:
                     t = wl.mTimerWindow;
                     if (t == null) {
-                        t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
+                        t = new StopwatchTimer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
                         wl.mTimerWindow = t;
                     }
                     return t;
@@ -1850,7 +2205,7 @@
             }
         }
 
-        public Timer getSensorTimerLocked(int sensor, boolean create) {
+        public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
             Sensor se = mSensorStats.get(sensor);
             if (se == null) {
                 if (!create) {
@@ -1859,36 +2214,36 @@
                 se = new Sensor(sensor);
                 mSensorStats.put(sensor, se);
             }
-            Timer t = se.mTimer;
+            StopwatchTimer t = se.mTimer;
             if (t != null) {
                 return t;
             }
-            ArrayList<Timer> timers = mSensorTimers.get(sensor);
+            ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
             if (timers == null) {
-                timers = new ArrayList<Timer>();
+                timers = new ArrayList<StopwatchTimer>();
                 mSensorTimers.put(sensor, timers);
             }
-            t = new Timer(BatteryStats.SENSOR, timers, mUnpluggables);
+            t = new StopwatchTimer(BatteryStats.SENSOR, timers, mUnpluggables);
             se.mTimer = t;
             return t;
         }
 
         public void noteStartWakeLocked(String name, int type) {
-            Timer t = getWakeTimerLocked(name, type);
+            StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
                 t.startRunningLocked(BatteryStatsImpl.this);
             }
         }
 
         public void noteStopWakeLocked(String name, int type) {
-            Timer t = getWakeTimerLocked(name, type);
+            StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
                 t.stopRunningLocked(BatteryStatsImpl.this);
             }
         }
         
         public void noteStartSensor(int sensor) {
-            Timer t = getSensorTimerLocked(sensor, true);
+            StopwatchTimer t = getSensorTimerLocked(sensor, true);
             if (t != null) {
                 t.startRunningLocked(BatteryStatsImpl.this);
             }            
@@ -1896,21 +2251,21 @@
 
         public void noteStopSensor(int sensor) {
             // Don't create a timer if one doesn't already exist
-            Timer t = getSensorTimerLocked(sensor, false);
+            StopwatchTimer t = getSensorTimerLocked(sensor, false);
             if (t != null) {
                 t.stopRunningLocked(BatteryStatsImpl.this);
             }            
         }
         
         public void noteStartGps() {
-            Timer t = getSensorTimerLocked(Sensor.GPS, true);
+            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
             if (t != null) {
                 t.startRunningLocked(BatteryStatsImpl.this);
             }  
         }
         
         public void noteStopGps() {
-            Timer t = getSensorTimerLocked(Sensor.GPS, false);
+            StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
             if (t != null) {
                 t.stopRunningLocked(BatteryStatsImpl.this);
             }  
@@ -1925,21 +2280,21 @@
         mFile = new File(filename);
         mBackupFile = new File(filename + ".bak");
         mStartCount++;
-        mScreenOnTimer = new Timer(-1, null, mUnpluggables);
+        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i] = new Timer(-100-i, null, mUnpluggables);
+            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables);
         }
         mInputEventCounter = new Counter(mUnpluggables);
-        mPhoneOnTimer = new Timer(-2, null, mUnpluggables);
+        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new Timer(-200-i, null, mUnpluggables);
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables);
         }
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new Timer(-300-i, null, mUnpluggables);
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables);
         }
-        mWifiOnTimer = new Timer(-3, null, mUnpluggables);
-        mWifiRunningTimer = new Timer(-4, null, mUnpluggables);
-        mBluetoothOnTimer = new Timer(-5, null, mUnpluggables);
+        mWifiOnTimer = new StopwatchTimer(-3, null, mUnpluggables);
+        mWifiRunningTimer = new StopwatchTimer(-4, null, mUnpluggables);
+        mBluetoothOnTimer = new StopwatchTimer(-5, null, mUnpluggables);
         mOnBattery = mOnBatteryInternal = false;
         mTrackBatteryPastUptime = 0;
         mTrackBatteryPastRealtime = 0;
@@ -1967,6 +2322,7 @@
 
     public void setOnBattery(boolean onBattery, int level) {
         synchronized(this) {
+            updateKernelWakelocksLocked();
             if (mOnBattery != onBattery) {
                 mOnBattery = mOnBatteryInternal = onBattery;
                 
@@ -1998,6 +2354,35 @@
     public void recordCurrentLevel(int level) {
         mDischargeCurrentLevel = level;
     }
+    
+    public void updateKernelWakelocksLocked() {
+        Map<String, KernelWakelockStats> m = readKernelWakelockStats();
+        
+        for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
+            String name = ent.getKey();
+            KernelWakelockStats kws = ent.getValue();
+        
+            SamplingTimer kwlt = mKernelWakelockStats.get(name);
+            if (kwlt == null) {
+                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal, 
+                        true /* track reported values */);
+                mKernelWakelockStats.put(name, kwlt);
+            }
+            kwlt.updateCurrentReportedCount(kws.mCount);
+            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
+            kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
+        }
+        
+        if (m.size() != mKernelWakelockStats.size()) {
+            // Set timers to stale if they didn't appear in /proc/wakelocks this time.
+            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+                SamplingTimer st = ent.getValue();
+                if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
+                    st.setStale();
+                }
+            }
+        }
+    }
 
     public long getAwakeTimeBattery() {
         return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
@@ -2296,6 +2681,14 @@
         mBluetoothOn = false;
         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
 
+        int NKW = in.readInt();
+        for (int ikw = 0; ikw < NKW; ikw++) {
+            if (in.readInt() != 0) {
+                String kwltName = in.readString();
+                getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
+            }
+        }
+        
         final int NU = in.readInt();
         for (int iu = 0; iu < NU; iu++) {
             int uid = in.readInt();
@@ -2420,6 +2813,18 @@
         mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
 
+        out.writeInt(mKernelWakelockStats.size());
+        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+            Timer kwlt = ent.getValue();
+            if (kwlt != null) {
+                out.writeInt(1);
+                out.writeString(ent.getKey());
+                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
+            } else {
+                out.writeInt(0);
+            }
+        }
+        
         final int NU = mUidStats.size();
         out.writeInt(NU);
         for (int iu = 0; iu < NU; iu++) {
@@ -2548,25 +2953,25 @@
         mBatteryRealtime = in.readLong();
         mBatteryLastRealtime = in.readLong();
         mScreenOn = false;
-        mScreenOnTimer = new Timer(-1, null, mUnpluggables, in);
+        mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables, in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i] = new Timer(-100-i, null, mUnpluggables, in);
+            mScreenBrightnessTimer[i] = new StopwatchTimer(-100-i, null, mUnpluggables, in);
         }
         mInputEventCounter = new Counter(mUnpluggables, in);
         mPhoneOn = false;
-        mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in);
+        mPhoneOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new Timer(-200-i, null, mUnpluggables, in);
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(-200-i, null, mUnpluggables, in);
         }
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new Timer(-300-i, null, mUnpluggables, in);
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(-300-i, null, mUnpluggables, in);
         }
         mWifiOn = false;
-        mWifiOnTimer = new Timer(-2, null, mUnpluggables, in);
+        mWifiOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
         mWifiRunning = false;
-        mWifiRunningTimer = new Timer(-2, null, mUnpluggables, in);
+        mWifiRunningTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
         mBluetoothOn = false;
-        mBluetoothOnTimer = new Timer(-2, null, mUnpluggables, in);
+        mBluetoothOnTimer = new StopwatchTimer(-2, null, mUnpluggables, in);
         mUptime = in.readLong();
         mUptimeStart = in.readLong();
         mLastUptime = in.readLong();
@@ -2585,6 +2990,16 @@
         mDischargeCurrentLevel = in.readInt();
         mLastWriteTime = in.readLong();
 
+        mKernelWakelockStats.clear();
+        int NKW = in.readInt();
+        for (int ikw = 0; ikw < NKW; ikw++) {
+            if (in.readInt() != 0) {
+                String wakelockName = in.readString();
+                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
+                mKernelWakelockStats.put(wakelockName, kwlt);
+            }
+        }
+        
         mPartialTimers.clear();
         mFullTimers.clear();
         mWindowTimers.clear();
@@ -2648,6 +3063,18 @@
         out.writeInt(mDischargeCurrentLevel);
         out.writeLong(mLastWriteTime);
 
+        out.writeInt(mKernelWakelockStats.size());
+        for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+            SamplingTimer kwlt = ent.getValue();
+            if (kwlt != null) {
+                out.writeInt(1);
+                out.writeString(ent.getKey());
+                Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
+            } else {
+                out.writeInt(0);
+            }
+        }
+        
         int size = mUidStats.size();
         out.writeInt(size);
         for (int i = 0; i < size; i++) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 3feccde..bd56605 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -516,39 +516,10 @@
     PROC_OUT_FLOAT = 0x4000,
 };
 
-jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
-        jstring file, jintArray format, jobjectArray outStrings,
-        jlongArray outLongs, jfloatArray outFloats)
+jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
+        char* buffer, jint startIndex, jint endIndex, jintArray format, 
+        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
 {
-    if (file == NULL || format == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", NULL);
-        return JNI_FALSE;
-    }
-    
-    const char* file8 = env->GetStringUTFChars(file, NULL);
-    if (file8 == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
-        return JNI_FALSE;
-    }
-    int fd = open(file8, O_RDONLY);
-    env->ReleaseStringUTFChars(file, file8);
-    
-    if (fd < 0) {
-        //LOGW("Unable to open process file: %s\n", file8);
-        return JNI_FALSE;
-    }
-    
-    char buffer[256];
-    const int len = read(fd, buffer, sizeof(buffer)-1);
-    close(fd);
-    
-    if (len < 0) {
-        //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
-        return JNI_FALSE;
-    }
-    buffer[len] = 0;
-    
-    //LOGI("Process file %s: %s\n", file8, buffer);
     
     const jsize NF = env->GetArrayLength(format);
     const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
@@ -575,7 +546,7 @@
         return JNI_FALSE;
     }
 
-    jsize i = 0;
+    jsize i = startIndex;
     jsize di = 0;
     
     jboolean res = JNI_TRUE;
@@ -587,30 +558,30 @@
         }
         const char term = (char)(mode&PROC_TERM_MASK);
         const jsize start = i;
-        if (i >= len) {
+        if (i >= endIndex) {
             res = JNI_FALSE;
             break;
         }
         
         jsize end = -1;
         if ((mode&PROC_PARENS) != 0) {
-            while (buffer[i] != ')' && i < len) {
+            while (buffer[i] != ')' && i < endIndex) {
                 i++;
             }
             end = i;
             i++;
         }
-        while (buffer[i] != term && i < len) {
+        while (buffer[i] != term && i < endIndex) {
             i++;
         }
         if (end < 0) {
             end = i;
         }
         
-        if (i < len) {
+        if (i < endIndex) {
             i++;
             if ((mode&PROC_COMBINE) != 0) {
-                while (buffer[i] == term && i < len) {
+                while (buffer[i] == term && i < endIndex) {
                     i++;
                 }
             }
@@ -649,6 +620,58 @@
     return res;
 }
 
+jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
+        jbyteArray buffer, jint startIndex, jint endIndex, jintArray format, 
+        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
+{
+        jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
+
+        jboolean result = android_os_Process_parseProcLineArray(env, clazz, 
+                (char*) bufferArray, startIndex, endIndex, format, outStrings, 
+                outLongs, outFloats);
+                
+        env->ReleaseByteArrayElements(buffer, bufferArray, 0);
+        
+        return result;
+}
+
+jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
+        jstring file, jintArray format, jobjectArray outStrings,
+        jlongArray outLongs, jfloatArray outFloats)
+{
+    if (file == NULL || format == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return JNI_FALSE;
+    }
+
+    const char* file8 = env->GetStringUTFChars(file, NULL);
+    if (file8 == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return JNI_FALSE;
+    }
+    int fd = open(file8, O_RDONLY);
+    env->ReleaseStringUTFChars(file, file8);
+    
+    if (fd < 0) {
+        //LOGW("Unable to open process file: %s\n", file8);
+        return JNI_FALSE;
+    }
+    
+    char buffer[256];
+    const int len = read(fd, buffer, sizeof(buffer)-1);
+    close(fd);
+    
+    if (len < 0) {
+        //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
+        return JNI_FALSE;
+    }
+    buffer[len] = 0;
+    
+    return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len, 
+            format, outStrings, outLongs, outFloats);
+    
+}
+
 void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
                                              jobject binderObject)
 {
@@ -728,6 +751,7 @@
     {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
     {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
     {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
+    {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
     {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
     {"getPss", "(I)J", (void*)android_os_Process_getPss},
     //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
@@ -746,4 +770,3 @@
         env, kProcessPathName,
         methods, NELEM(methods));
 }
-
diff --git a/docs/html/guide/developing/tools/avd.jd b/docs/html/guide/developing/tools/avd.jd
new file mode 100644
index 0000000..7ba7968
--- /dev/null
+++ b/docs/html/guide/developing/tools/avd.jd
@@ -0,0 +1,496 @@
+page.title=Android Virtual Devices
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>AVD quickview</h2>
+  <ul>
+    <li>You need to create an AVD to run any app in the Android emulator</li>
+    <li>Each AVD is a completely independent virtual device, with its own
+        hardware options, system image, and data storage.
+    <li>You create AVD configurations to model different device environments 
+        in the Android emulator.</li>
+  </ul>
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#creating">Creating an AVD</a>
+      <ol>
+        <li><a href="#listingtargets">Listing targets</a></li>
+        <li><a href="#selectingtarget">Selecting a target</a></li>
+        <li><a href="#createavd">Creating the AVD</a></li>
+        <li><a href="#hardwareopts">Setting hardware emulation options</a></li>
+        <li><a href="#location">Default location of the AVD files</a></li>
+        <li><a href="#createavdopts">Command-line options, create avd</a></li>
+      </ol>
+    </li>
+    <li><a href="#managing">Managing AVDs</a>
+      <ol>
+        <li><a href="#moving">Moving an AVD</a></li>
+        <li><a href="#updating">Deleting an AVD</a></li>
+        <li><a href="#deleting">Deleting an AVD</a></li>
+      </ol>
+    </li>
+    <li><a href="#options">Command-line options</a></li>
+  </ol>
+  <h2>See Also</h2>
+  <ol>
+    <li>Android <a href="{@docRoot}guide/developing/tools/emulator.html">Emulator</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Android Virtual Devices (AVDs) are configurations of emulator options that let
+you better model an actual device.</p>
+
+<p>Each AVD is made up of: </p>
+
+<ul>
+<li>A hardware profile.&nbsp;&nbsp;You can set options to define the hardware
+features of the virtual device. For example, you can define whether the device
+has a camera, whether it uses a physical QWERTY keyboard or a dialing pad, how
+much memory it has, and so on. </li>
+<li>A mapping to a system image.&nbsp;&nbsp;You can define what version of the
+Android platform will run on the virtual device. You can choose a version of the
+standard Android platform or the system image packaged with an SDK add-on.</li>
+<li>Other options.&nbsp;&nbsp;You can specify the emulator skin you want to use
+with the AVD, which lets you control the screen dimensions, appearance, and so
+on. You can also specify the emulated SD card to use with the AVD.</li>
+<li>A dedicated storage area on your development machine, in which is stored the
+device's user data (installed applications, settings, and so on) and emulated SD
+card.</li>
+</ul>
+
+<p>You can create as many AVDs as you need, based on the types of devices you
+want to model and the Android platforms and external libraries you want to run
+your application on. </p>
+
+<p>In addition to the options in an AVD configuration, you can also
+specify emulator command-line options at launch or by using the emulator
+console to change behaviors or characteristics at run time. For a complete
+reference of emulator options, please see the <a
+href="{@docRoot}/guide/developing/tools/emulator.html">Emulator</a>
+documentation. </p>
+
+<p>To create and manage AVDs, you use the android tool provided in the Android
+SDK. For more information about how to work with AVDs from inside
+your development environment, see <a
+href="{@docRoot}guide/developing/eclipse-adt.html">Developing in Eclipse with
+ADT</a> or <a href="{@docRoot}guide/developing/other-ide.html">Developing in
+Other IDEs</a>, as appropriate for your environment.</p>
+
+<h2 id="creating">Creating an AVD</h2>
+
+<div class="sidebox">The Android SDK does not include any preconfigured AVDs, so
+you need to create an AVD before you can run any application in the emulator
+(even the Hello World application). </div>
+
+<p>To create an AVD, you use the android tool, a command-line utility
+available in the <code>&lt;sdk&gt;/tools/</code> directory. Managing AVDs is one
+of the two main function of the android tool (the other is creating and updating
+Android projects). Open a terminal window and change to the 
+<code>&lt;sdk&gt;/tools/</code> directory, if needed</p>
+
+<p>To create each AVD, you issue the command <code>android avd create</code>,
+with options that specify a name for the new AVD and the system image you want
+to run on the emulator when the AVD is invoked. You can specify other options on
+the command line also, such as to create an emulated SD card for the new AVD, set
+the emulator skin to use, or set a custom location for the AVD's files.</p>
+
+<p>Here's the command-line usage for creating an AVD: </p>
+
+<pre>android -n &lt;name&gt; -t &lt;targetID&gt; [-&lt;option&gt; &lt;value&gt;] ... </pre>
+
+<p>You can use any name you want for the AVD, but since you are likely to be
+creating multiple AVDs, you should choose a name that lets you recognize the
+general characteristics offered by the AVD. </p>
+
+<p>As shown in the usage above, you must use the <code>-t</code> (or
+<code>--target</code>) argument when creating a new AVD. The argument sets up a
+mapping between the AVD and the system image that you want to use whenever the
+AVD is invoked. You can specify any Android system image that is available in
+your local SDK &mdash; it can be the system image of a standard Android platform
+version or that of any SDK add-on. Later, when applications use the AVD, they'll
+be running on the system that you specify in the <code>-t</code> argument.<p>
+
+<p>To specify the system image to use, you refer to its <em>target ID</em>
+&mdash; an integer &mdash; as assigned by the android tool. The target ID is not
+derived from the system image name, version, or API Level, or other attribute,
+so you need to have the android tool list the available system images and the
+target ID of each, as described in the next section. You should do this
+<em>before</em> you run the <code>android create avd</code> command.
+</p>
+
+<h3 id="listingtargets">Listing targets</h3>
+
+<p>To generate a list of system image targets, use this command: </p>
+
+<pre>android list targets</pre>
+
+<p>The android tool scans the <code>&lt;sdk&gt;/platforms</code> and
+<code>&lt;sdk&gt;/add-ons</code> directories looking for valid system images and
+then generates the list of targets. Here's an example of the command output:
+</p>
+
+<pre>Available Android targets:
+id:1
+    Name: Android 1.1
+    Type: platform
+    API level: 2
+    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
+id:2
+    Name: Android 1.5
+    Type: platform
+    API level: 3
+    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
+id:3
+    Name: Google APIs
+    Type: add-on
+    Vendor: Google Inc.
+    Description: Android + Google APIs
+    Based on Android 1.5 (API level 3)
+    Libraries:
+    * com.google.android.maps (maps.jar)
+        API for Google Maps
+    Skins: HVGA (default), HVGA-L, QVGA-P, HVGA-P, QVGA-L</pre>
+
+<h3 id="selectingtarget">Selecting a target</h3>
+
+<p>Once you have generated the list of targets available, you can look at the
+characteristics of each system image &mdash; name, API Level, external
+libraries, and so on &mdash; and determine which target is appropriate for the
+new AVD. </p>
+
+<p>Keep these points in mind when you are selecting a system image target for
+your AVD:</p>
+<ul>
+<li>The API Level of the target is important, because your application will not
+be able to run on a system image whose API Level is less than that required by
+your application, as specified in the <code>minSdkVersion</code> attribute of
+the application's manifest file. For more information about the relationship
+between system API Level and application <code>minSdkVersion</code>, see <a
+href="{@docRoot}guide/publishing/versioning.html#minsdkversion">Specifying
+Minimum System API Version</a>.
+<li>Creating at least one AVD that uses a target whose API Level is greater than
+that required by your application is strongly encouraged, because it allows you to
+test the forward-compatibility of your application. Forward-compatibility
+testing ensures that, when users who have downloaded your application receive a
+system update, your application will continue to function normally. </li>
+<li>If your application declares a <code>uses-library</code> element in its
+manifest file, the application can only run on a system image in which that
+external library is present. If you want your application to run on the AVD you
+are creating, check the application's <code>uses-library</code> element and
+select a system image target that includes that library. 
+
+</ul>
+
+<h3 id="createavd">Creating the AVD</h3>
+
+<p>When you've selected the target you want to use and made a note of its ID,
+use the <code>android create avd</code> command to create the AVD, supplying the
+target ID as the <code>-t</code> argument. Here's an example that creates an
+AVD with name "my_android1.5" and target ID "2" (the standard Android 1.5 
+system image in the list above): </p>
+
+<pre>android create avd -n my_android1.5 -t 2</pre>
+
+<p>If the target you selected was a standard Android system image ("Type:
+platform"), the android tool next asks you whether you want to create a custom
+hardware profile. </p>
+
+<pre>Android 1.5 is a basic Android platform.
+Do you wish to create a custom hardware profile [no]</pre>
+
+<p>If you want to set custom hardware emulation options for the AVD, enter
+"yes" and set values as needed. If you want to use the default hardware
+emulation options for the AVD, just press the return key (the default is "no").
+The android tool creates the AVD with name and system image mapping you
+requested, with the options you specified. 
+
+<p class="note">If you are creating an AVD whose target is an SDK add-on,
+the android tool does not allow you to set hardware emulation options. It
+assumes that the provider of the add-on has set emulation options appropriately
+for the device that the add-on is modeling, and so prevents you from resetting
+the options. </p>
+
+<p>For a list of options you can use in the <code>android create avd</code>
+command, see the table in <a href="#options">Command-line options for AVDs</a>,
+at the bottom of
+this page. </p>
+
+<h3 id="hardwareopts">Setting hardware emulation options</h3>
+
+<p>When are creating a new AVD that uses a standard Android system image ("Type:
+platform"), the android tool lets you set hardware emulation options for virtual
+device. The table below lists the options available and the default values, as
+well as the names of properties that store the emulated hardware options in the AVD's
+configuration file (the config.ini file in the AVD's local directory). </p>
+
+
+<table>
+<tr>
+<th>Characteristic</th>
+<th>Description</th>
+<th>Property</th>
+</tr>
+
+<tr>
+<td>Device ram size</td>
+<td>The amount of physical RAM on the device, in megabytes. Default value is "96".
+<td>hw.ramSize</td>
+</tr>
+
+<tr>
+<td>Touch-screen support</td>
+<td>Whether there is a touch screen or not on the device. Default value is "yes".</td>
+<td>hw.touchScreen
+
+
+<tr>
+<td>Trackball support </td>
+<td>Whether there is a trackball on the device. Default value is "yes".</td>
+<td>hw.trackBall</td>
+</tr>
+
+<tr>
+<td>Keyboard support</td>
+<td>Whether the device has a QWERTY keyboard. Default value is "yes".</td>
+<td>hw.keyboard</td>
+</tr>
+
+<tr>
+<td>DPad support</td>
+<td>Whether the device has DPad keys. Default value is "yes".</td>
+<td>hw.dPad</td>
+</tr>
+
+<tr>
+<td>GSM modem support</td>
+<td>Whether there is a GSM modem in the device. Default value is "yes".</td>
+<td>hw.gsmModem</td>
+</tr>
+
+<tr>
+<td>Camera support</td>
+<td>Whether the device has a camera. Default value is "no".</td>
+<td>hw.camera</td>
+</tr>
+
+<tr>
+<td>Maximum horizontal camera pixels</td>
+<td>Default value is "640".</td>
+<td>hw.camera.maxHorizontalPixels</td>
+</tr>
+
+<tr>
+<td>Maximum vertical camera pixels</td>
+<td>Default value is "480".</td>
+<td>hw.camera.maxVerticalPixels</td>
+</tr>
+
+<tr>
+<td>GPS support</td>
+<td>Whether there is a GPS in the device. Default value is "yes".</td>
+<td>hw.gps</td>
+</tr>
+
+<tr>
+<td>Battery support</td>
+<td>Whether the device can run on a battery. Default value is "yes".</td>
+<td>hw.battery</td>
+</tr>
+
+<tr>
+<td>Accelerometer</td>
+<td>Whether there is an accelerometer in the device. Default value is "yes".</td>
+<td>hw.accelerometer</td>
+</tr>
+
+<tr>
+<td>Audio recording support</td>
+<td>Whether the device can record audio. Default value is "yes".</td>
+<td>hw.audioInput</td>
+</tr>
+
+<tr>
+<td>Audio playback support</td>
+<td>Whether the device can play audio. Default value is "yes".</td>
+<td>hw.audioOutput</td>
+</tr>
+
+<tr>
+<td>SD Card support</td>
+<td>Whether the device supports insertion/removal of virtual SD Cards. Default value is "yes".</td>
+<td>hw.sdCard</td>
+</tr>
+
+<tr>
+<td>Cache partition support</td>
+<td>Whether we use a /cache partition on the device. Default value is "yes".</td>
+<td>disk.cachePartition</td>
+</tr>
+
+<tr>
+<td>Cache partition size</td>
+<td>Default value is "66MB".</td>
+<td>disk.cachePartition.size </td>
+</tr>
+</table>
+
+<h3 id="location">Default location of the AVD files</h3>
+
+<p>When you create an AVD, the android tool creates a dedicated directory for it
+on your development computer. The directory contains the AVD configuration file,
+the user data image and SD card image (if available), and any other files
+associated with the device. Note that the directory does not contain a system
+image &mdash; instead, the AVD configuration file contains a mapping to the
+system image, which it loads when the AVD is launched. </p>
+
+<p>The android tool also creates a &lt;AVD name&gt;.ini file for the AVD at the
+root of the .android/avd directory on your computer. The file specifies the
+location of the AVD directory and always remains at the root the .android 
+directory.</p>
+
+<p>By default, the android tool creates the AVD directory inside
+<code>~/.android/avd/</code> (on Linux/Mac), <code>C:\Documents and
+Settings\&lt;user&gt;\.android\</code> on Windows XP, and 
+<code>C:\Users\&lt;user&gt;\.android\</code> on Windows Vista. 
+If you want to use a custom location for the AVD directory, you 
+can do so by using the <code>-p &lt;path&gt;</code> option when 
+you create the AVD: </p>
+
+<pre>android create avd -n my_android1.5 -t 2 -p path/to/my/avd</pre>
+
+<p>If the .android directory is hosted on a network drive, we recommend using
+the <code>-p</code> option to place the AVD directory in another location. 
+The  AVD's .ini file remains in the .android directory on the network
+drive, regardless of the location of the AVD directory. </p>
+
+<h3 id="moving">Moving an AVD</h3>
+
+<p>If you want to move or rename an AVD, you can do so using this command:</p>
+
+<pre>android move avd -n &lt;name&gt; [-&lt;option&gt; &lt;value&gt;] ...</pre>
+
+<p>The options for this command are listed in <a href="#options">Command-line
+options for AVDs</a> at the bottom of this page. </p>
+
+<h3 id="updating">Updating an AVD</h3>
+
+<p>If, for any reason, the platform/add-on root folder has its name changed (maybe because the user has installed an update of the platform/add-on) then the AVD will not be able to load the system image that it is mapped to. In this case, the <code>android list targets</code> command will produce this output: 
+
+<pre>The following Android Virtual Devices could not be loaded: 
+Name: foo 
+Path: &lt;path&gt;/.android/avd/foo.avd 
+Error: Invalid value in image.sysdir. Run 'android update avd -n foo' </pre>
+
+<p>To fix this error, use the <code>android update avd</code> command to recompute the path to the system images.</p>
+
+<h3 id="deleting">Deleting an AVD</h3>
+
+<p>You can use the android tool to delete an AVD. Here is the command usage:</p>
+
+<pre>android delete avd -n &lt;name&gt; </pre>
+
+<p>When you issue the command, the android tool looks for an AVD matching the 
+specified name deletes the AVD's directory and files. </p>
+
+
+<h2 id="options">Command-line options for AVDs</h2>
+
+<p>The table below lists the command-line options you can use with the 
+android tool. </p>
+
+
+<table>
+<tr>
+  <th width="15%">Action</th>
+  <th width="20%">Option</th>
+  <th width="30%">Description</th>
+  <th>Comments</th>
+</tr>
+
+
+<tr>
+  <td><code>list&nbsp;avds</code></td>
+  <td>&nbsp;</td>
+  <td>List all known AVDs, with name, path, target, and skin. </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td rowspan="6"><code>create&nbsp;avd</code></td>
+  <td><code>-n &lt;name&gt; or <br></code></td>
+  <td>The name for the AVD.</td>
+  <td>Required</td>
+</tr>
+<tr>
+  <td><code>-t &lt;targetID&gt;</code></td>
+  <td>Target ID of the system image to use with the new AVD.</td>
+  <td>Required. To obtain a list of available targets, use <code>android list
+      targets</code>.</td>
+</tr>
+<tr>
+  <td><code>-c &lt;path&gt;</code> or <br>
+      <code>-c &lt;size&gt;[K|M]</code></td>
+  <td>The path to the SD card image to use with this AVD or the size of a new SD
+      card image to create for this AVD.</td>
+  <td>Examples: <code>-c path/to/sdcard</code> or <code>-c 1000M</code></td>
+</tr>
+<tr>
+  <td><code>-f</code></td>
+  <td>Force creation of the AVD</td>
+  <td>By default, if the name of the AVD being created matches that of an 
+      existing AVD, the android tool will not create the new AVD or overwrite 
+      the existing AVD. If you specify the <code>-f</code> option, however, the 
+      android tool will automatically overwrite any existing AVD that has the 
+      same name as the new AVD. The files and data of the existing AVD are 
+      deleted. </td>
+</tr>
+
+<tr>
+  <td><code>-p &lt;path&gt;</code></td>
+  <td>Path to the location at which to create the directory for this AVD's
+files.</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><code>-s &lt;name&gt;</code> or <br>
+      <code>-s &lt;dimensions&gt;</code> </td>
+  <td>The skin to use for this AVD, identified by name or dimensions.</td>
+  <td>The android tool scans for a matching skin by name or dimension in the
+<code>skins/</code> directory of the target referenced in the <code>-t
+&lt;targetID&gt;</code> argument. Example: <code>-s HVGA-L</code></td>
+</tr>
+<tr>
+  <td><code>delete&nbsp;avd</code></td>
+  <td><code>-n &lt;name&gt;</code></td>
+  <td>Delete the specified AVD.</td>
+  <td>Required</td>
+</tr>
+<tr>
+  <td rowspan="3"><code>move&nbsp;avd</code></td>
+  <td><code>-n &lt;name&gt;</code></td>
+  <td>The name of the AVD to move.</td>
+  <td>Required</td>
+</tr>
+<tr>
+  <td><code>-p &lt;path&gt;</code></td>
+  <td>The path to the new location for the AVD.</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><code>-r &lt;new-name&gt;</code></td>
+  <td>Rename the AVD.</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><code>update&nbsp;avds</code></td>
+  <td>&nbsp;</td>
+  <td>Recompute the paths to all system images.</td>
+  <td>&nbsp;</td>
+</tr>
+
+
+
+</table>
+
diff --git a/docs/html/offline.jd b/docs/html/offline.jd
index d41459b..57c55c7 100644
--- a/docs/html/offline.jd
+++ b/docs/html/offline.jd
@@ -9,10 +9,10 @@
 <img src="{@docRoot}images/android_icon_125.png" style="float:right; margin:1em 6em 6em;" />
 
 <p>If you've just downloaded the SDK, then continue with  
-<a href="{@docRoot}sdk/1.1_r1/installing.html">Installing the Android SDK</a>.</p>
+<a href="{@docRoot}sdk/{@sdkCurrent}/installing.html">Installing the Android SDK</a>.</p>
 
 <p>If you're upgrading from a previously installed version, then refer to the 
-<a href="{@docRoot}sdk/1.1_r1/upgrading.html">Upgrading</a> guide.</p>
+<a href="{@docRoot}sdk/{@sdkCurrent}/upgrading.html">Upgrading</a> guide.</p>
 
 <p>Once you've completed the SDK installation, you can start learning about
 development on the Android framework by reading the <a
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a49bd67..3346bed 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -40,7 +40,7 @@
  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
  * fill with the new audio data. The size of this buffer, specified during the construction, 
  * determines how long an AudioRecord can record before "over-running" data that has not
- * been read yet. Data should be from the audio hardware in chunks of sizes inferior to
+ * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
  */
 public class AudioRecord
@@ -49,20 +49,20 @@
     // Constants
     //--------------------
     /**
-     *  State of an AudioRecord that was not successfully initialized upon creation 
+     *  indicates AudioRecord state is not successfully initialized. 
      */
     public static final int STATE_UNINITIALIZED = 0;
     /**
-     *  State of an AudioRecord that is ready to be used 
+     *  indicates AudioRecord state is ready to be used 
      */
     public static final int STATE_INITIALIZED   = 1;
 
     /**
-     * State of an AudioRecord this is not recording 
+     * indicates AudioRecord recording state is not recording 
      */
     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
     /**
-     * State of an AudioRecord this is recording 
+     * indicates AudioRecord recording state is recording 
      */
     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
 
@@ -94,11 +94,11 @@
     // Events:
     // to keep in sync with frameworks/base/include/media/AudioRecord.h 
     /**
-     * Event id for when the recording head has reached a previously set marker.
+     * Event id denotes when record head has reached a previously set marker.
      */
     private static final int NATIVE_EVENT_MARKER  = 2;
     /**
-     * Event id for when the previously set update period has passed during recording.
+     * Event id denotes when previously set update period has elapsed during recording.
      */
     private static final int NATIVE_EVENT_NEW_POS = 3;
     
@@ -188,7 +188,7 @@
      */
     private int mNativeBufferSizeInBytes = 0;
 
-    
+
     //---------------------------------------------------------
     // Constructor, Finalize
     //--------------------
@@ -206,7 +206,9 @@
      *   {@link AudioFormat#ENCODING_PCM_8BIT}
      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
      *   to during the recording. New audio data can be read from this buffer in smaller chunks 
-     *   than this size.
+     *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
+     *   required buffer size for the successful creation of an AudioRecord instance. Using values
+     *   smaller than getMinBufferSize() will result in an initialization failure.
      * @throws java.lang.IllegalArgumentException
      */
     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, 
@@ -319,11 +321,13 @@
 
         mNativeBufferSizeInBytes = audioBufferSize;
     }    
-    
-    
+
+
 
     /**
      * Releases the native AudioRecord resources.
+     * The object can no longer be used and the reference should be set to null
+     * after a call to release()
      */
     public void release() {
         try {
@@ -334,7 +338,7 @@
         native_release();
         mState = STATE_UNINITIALIZED;
     }
-    
+
 
     @Override
     protected void finalize() {
@@ -404,24 +408,27 @@
     public int getRecordingState() {
         return mRecordingState;
     }
-    
+
     /**
-     * @return marker position in frames
+     * Returns the notification marker position expressed in frames.
      */
     public int getNotificationMarkerPosition() {
         return native_get_marker_pos();
     }
 
     /**
-     * @return update period in frames
+     * Returns the notification update period expressed in frames.
      */
     public int getPositionNotificationPeriod() {
         return native_get_pos_update_period();
     }
-    
+
     /**
      * Returns the minimum buffer size required for the successful creation of an AudioRecord
      * object.
+     * Note that this size doesn't guarantee a smooth recording under load, and higher values
+     * should be chosen according to the expected frequency at which the AudioRecord instance
+     * will be polled for new data.
      * @param sampleRateInHz the sample rate expressed in Hertz.
      * @param channelConfig describes the configuration of the audio channels. 
      *   See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
@@ -432,7 +439,7 @@
      *  hardware, or an invalid parameter was passed,
      *  or {@link #ERROR} if the implementation was unable to query the hardware for its 
      *  output properties, 
-     *   or the minimum buffer size expressed in of bytes.
+     *   or the minimum buffer size expressed in bytes.
      */
     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
         int channelCount = 0;
@@ -516,7 +523,7 @@
     /**
      * Reads audio data from the audio hardware for recording into a buffer.
      * @param audioData the array to which the recorded audio data is written.
-     * @param offsetInBytes index in audioData from which the data is written.
+     * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
      * @param sizeInBytes the number of requested bytes.
      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
@@ -540,9 +547,9 @@
     /**
      * Reads audio data from the audio hardware for recording into a buffer.
      * @param audioData the array to which the recorded audio data is written.
-     * @param offsetInShorts index in audioData from which the data is written.
+     * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
      * @param sizeInShorts the number of requested shorts.
-     * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+     * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
      *    the parameters don't resolve to valid data and indexes.
      *    The number of shorts will not exceed sizeInShorts.
@@ -595,8 +602,15 @@
     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
         setRecordPositionUpdateListener(listener, null);
     }
-    
 
+    /**
+     * Sets the listener the AudioRecord notifies when a previously set marker is reached or
+     * for each periodic record head position update.
+     * Use this method to receive AudioRecord events in the Handler associated with another
+     * thread than the one in which you created the AudioTrack instance.
+     * @param listener
+     * @param handler the Handler that will receive the event notification messages.
+     */
     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 
                                                     Handler handler) {
         synchronized (mPositionListenerLock) {
@@ -616,8 +630,8 @@
         }
         
     }
-    
-    
+
+
     /**
      * Sets the marker position at which the listener is called, if set with 
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 
@@ -629,8 +643,8 @@
     public int setNotificationMarkerPosition(int markerInFrames) {
         return native_set_marker_pos(markerInFrames);
     }
-    
-    
+
+
     /**
      * Sets the period at which the listener is called, if set with
      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 
@@ -648,7 +662,9 @@
     //--------------------
     /**
      * Interface definition for a callback to be invoked when an AudioRecord has
-     * reached a notification marker set by setNotificationMarkerPosition().
+     * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
+     * or for periodic updates on the progress of the record head, as set by
+     * {@link AudioRecord#setPositionNotificationPeriod(int)}.
      */
     public interface OnRecordPositionUpdateListener  {
         /**
@@ -663,10 +679,9 @@
          */
         void onPeriodicNotification(AudioRecord recorder);
     }
-    
-    
 
-    
+
+
     //---------------------------------------------------------
     // Inner classes
     //--------------------
@@ -678,12 +693,12 @@
     private class NativeEventHandler extends Handler {
         
         private final AudioRecord mAudioRecord;
-        
+
         NativeEventHandler(AudioRecord recorder, Looper looper) {
             super(looper);
             mAudioRecord = recorder;
         }
-        
+
         @Override
         public void handleMessage(Message msg) {
             OnRecordPositionUpdateListener listener = null;
@@ -779,7 +794,3 @@
 
 }
 
-
-
-
-
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index c9efac5..4fb0ead 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -30,8 +30,29 @@
 
 /**
  * JetPlayer provides access to JET content playback and control.
- * <p>
- * Use <code>JetPlayer.getJetPlayer()</code> to get an instance of this class.
+ * 
+ * <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
+ * music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
+ * 
+ * <p>Use of the JetPlayer class is based around the playback of a number of JET segments
+ * sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
+ * segment can be dynamically affected by two mechanisms:
+ * <ul>
+ * <li>tracks in a segment can be muted or unmuted at any moment, individually or through
+ *    a mask (to change the mute state of multiple tracks at once)</li>
+ * <li>parts of tracks in a segment can be played at predefined points in the segment, in order
+ *    to maintain synchronization with the other tracks in the segment. This is achieved through
+ *    the notion of "clips", which can be triggered at any time, but that will play only at the
+ *    right time, as authored in the corresponding JET file.</li>
+ * </ul>
+ * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
+ * can receive notifications from the JET engine relative to:
+ * <ul>
+ * <li>the playback state,</li>
+ * <li>the number of segments left to play in the queue,</li>
+ * <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
+ * </ul>
+ *  Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
  * 
  */
 public class JetPlayer
@@ -40,7 +61,7 @@
     // Constants
     //------------------------
     /**
-     * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to
+     * The maximum number of simultaneous tracks. Use {@link #getMaxTracks()} to
      * access this value.
      */
     private static int MAXTRACKS = 32;
@@ -107,6 +128,10 @@
     //--------------------------------------------
     // Constructor, finalize
     //------------------------
+    /**
+     * Factory method for the JetPlayer class.
+     * @return the singleton JetPlayer instance
+     */
     public static JetPlayer getJetPlayer() {
         if (singletonRef == null) {
             singletonRef = new JetPlayer();
@@ -114,7 +139,9 @@
         return singletonRef;
     }
     
-    
+    /**
+     * Cloning a JetPlayer instance is not supported. Calling clone() will generate an exception.
+     */
     public Object clone() throws CloneNotSupportedException {
         // JetPlayer is a singleton class,
         // so you can't clone a JetPlayer instance
@@ -149,6 +176,11 @@
     }
     
     
+    /**
+     * Stops the current JET playback, and releases all associated native resources.
+     * The object can no longer be used and the reference should be set to null
+     * after a call to release().
+     */
     public void release() {
         native_release();
     }
@@ -158,7 +190,7 @@
     // Getters
     //------------------------
     /**
-     * Returns the maximum number of simultaneous MIDI tracks supported by the Jet player
+     * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
      */
     public static int getMaxTracks() {
         return JetPlayer.MAXTRACKS;
@@ -168,11 +200,21 @@
     //--------------------------------------------
     // Jet functionality
     //------------------------
+    /**
+     * Loads a .jet file from a given path.
+     * @param path the path to the .jet file, for instance "/sdcard/mygame/music.jet".
+     * @return true if loading the .jet file was successful, false if loading failed.
+     */
     public boolean loadJetFile(String path) {
         return native_loadJetFromFile(path);
     }
     
     
+    /**
+     * Loads a .jet file from an asset file descriptor.
+     * @param afd the asset file descriptor.
+     * @return true if loading the .jet file was successful, false if loading failed.
+     */
     public boolean loadJetFile(AssetFileDescriptor afd) {
         long len = afd.getLength();
         if (len < 0) {
@@ -182,22 +224,54 @@
                 afd.getFileDescriptor(), afd.getStartOffset(), len);
     }
     
-    
+    /**
+     * Closes the resource containing the JET content.
+     * @return true if successfully closed, false otherwise.
+     */
     public boolean closeJetFile() {
         return native_closeJetFile();
     }
     
     
+    /**
+     * Starts playing the JET segment queue.
+     * @return true if rendering and playback is successfully started, false otherwise.
+     */
     public boolean play() {
         return native_playJet();
     }
     
     
+    /**
+     * Pauses the playback of the JET segment queue.
+     * @return true if rendering and playback is successfully paused, false otherwise.
+     */
     public boolean pause() {
         return native_pauseJet();
     }
     
     
+    /**
+     * Queues the specified segment in the JET queue.
+     * @param segmentNum the identifier of the segment.
+     * @param libNum the index of the sound bank associated with the segment. Use -1 to indicate
+     *    that no sound bank (DLS file) is associated with this segment, in which case JET will use
+     *    the General MIDI library.
+     * @param repeatCount the number of times the segment will be repeated. 0 means the segment will
+     *    only play once. -1 means the segment will repeat indefinitely.
+     * @param transpose the amount of pitch transposition. Set to 0 for normal playback. 
+     *    Range is -12 to +12.
+     * @param muteFlags a bitmask to specify which MIDI tracks will be muted during playback. Bit 0
+     *    affects track 0, bit 1 affects track 1 etc.
+     * @param userID a value specified by the application that uniquely identifies the segment. 
+     *    this value is received in the
+     *    {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method.
+     *    Normally, the application will keep a byte value that is incremented each time a new
+     *    segment is queued up. This can be used to look up any special characteristics of that
+     *    track including trigger clips and mute flags.
+     * @return true if the segment was successfully queued, false if the queue is full or if the
+     *    parameters are invalid.
+     */
     public boolean queueJetSegment(int segmentNum, int libNum, int repeatCount,
         int transpose, int muteFlags, byte userID) {
         return native_queueJetSegment(segmentNum, libNum, repeatCount, 
@@ -205,6 +279,28 @@
     }
     
     
+    /**
+     * Queues the specified segment in the JET queue.
+     * @param segmentNum the identifier of the segment.
+     * @param libNum the index of the soundbank associated with the segment. Use -1 to indicate that
+     *    no sound bank (DLS file) is associated with this segment, in which case JET will use
+     *    the General MIDI library.
+     * @param repeatCount the number of times the segment will be repeated. 0 means the segment will
+     *    only play once. -1 means the segment will repeat indefinitely.
+     * @param transpose the amount of pitch transposition. Set to 0 for normal playback. 
+     *    Range is -12 to +12.
+     * @param muteArray an array of booleans to specify which MIDI tracks will be muted during
+     *    playback. The value at index 0 affects track 0, value at index 1 affects track 1 etc. 
+     *    The length of the array must be {@link #getMaxTracks()} for the call to succeed.
+     * @param userID a value specified by the application that uniquely identifies the segment. 
+     *    this value is received in the
+     *    {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method.
+     *    Normally, the application will keep a byte value that is incremented each time a new
+     *    segment is queued up. This can be used to look up any special characteristics of that
+     *    track including trigger clips and mute flags.
+     * @return true if the segment was successfully queued, false if the queue is full or if the
+     *    parameters are invalid.
+     */
     public boolean queueJetSegmentMuteArray(int segmentNum, int libNum, int repeatCount,
             int transpose, boolean[] muteArray, byte userID) {
         if (muteArray.length != JetPlayer.getMaxTracks()) {
@@ -215,11 +311,32 @@
     }
     
     
+    /**
+     * Modifies the mute flags.
+     * @param muteFlags a bitmask to specify which MIDI tracks are muted. Bit 0 affects track 0,
+     *    bit 1 affects track 1 etc.
+     * @param sync if false, the new mute flags will be applied as soon as possible by the JET
+     *    render and playback engine. If true, the mute flags will be updated at the start of the
+     *    next segment. If the segment is repeated, the flags will take effect the next time 
+     *    segment is repeated.
+     * @return true if the mute flags were successfully updated, false otherwise.
+     */
     public boolean setMuteFlags(int muteFlags, boolean sync) {
         return native_setMuteFlags(muteFlags, sync);
     }
     
     
+    /**
+     * Modifies the mute flags for the current active segment.
+     * @param muteArray an array of booleans to specify which MIDI tracks are muted. The value at
+     *    index 0 affects track 0, value at index 1 affects track 1 etc. 
+     *    The length of the array must be {@link #getMaxTracks()} for the call to succeed.
+     * @param sync if false, the new mute flags will be applied as soon as possible by the JET
+     *    render and playback engine. If true, the mute flags will be updated at the start of the
+     *    next segment. If the segment is repeated, the flags will take effect the next time 
+     *    segment is repeated.
+     * @return true if the mute flags were successfully updated, false otherwise.
+     */
     public boolean setMuteArray(boolean[] muteArray, boolean sync) {
         if(muteArray.length != JetPlayer.getMaxTracks())
             return false;
@@ -227,16 +344,41 @@
     }
     
     
+    /**
+     * Mutes or unmutes a single track.
+     * @param trackId the index of the track to mute.
+     * @param muteFlag set to true to mute, false to unmute.
+     * @param sync if false, the new mute flags will be applied as soon as possible by the JET
+     *    render and playback engine. If true, the mute flag will be updated at the start of the
+     *    next segment. If the segment is repeated, the flag will take effect the next time 
+     *    segment is repeated.
+     * @return true if the mute flag was successfully updated, false otherwise.
+     */
     public boolean setMuteFlag(int trackId, boolean muteFlag, boolean sync) {
         return native_setMuteFlag(trackId, muteFlag, sync);
     }
     
     
+    /**
+     * Schedules the playback of a clip.
+     * This will automatically update the mute flags in sync with the JET Clip Marker (controller 
+     * 103). The parameter clipID must be in the range of 0-63. After the call to triggerClip, when
+     * JET next encounters a controller event 103 with bits 0-5 of the value equal to clipID and 
+     * bit 6 set to 1, it will automatically unmute the track containing the controller event.
+     * When JET encounters the complementary controller event 103 with bits 0-5 of the value equal
+     * to clipID and bit 6 set to 0, it will mute the track again.
+     * @param clipId the identifier of the clip to trigger.
+     * @return true if the clip was successfully triggered, false otherwise.
+     */
     public boolean triggerClip(int clipId) {
         return native_triggerClip(clipId);
     }
     
     
+    /**
+     * Empties the segment queue, and clears all clips that are scheduled for playback.
+     * @return true if the queue was successfully cleared, false otherwise.
+     */
     public boolean clearQueue() {
         return native_clearQueue();
     }
@@ -302,10 +444,25 @@
     //--------------------------------------------
     // Jet event listener
     //------------------------
+    /**
+     * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
+     * playback engine.
+     * Notifications will be received in the same thread as the one in which the JetPlayer
+     * instance was created.
+     * @param listener
+     */
     public void setEventListener(OnJetEventListener listener) {
         setEventListener(listener, null);
     }
     
+    /**
+     * Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
+     * playback engine.
+     * Use this method to receive JET events in the Handler associated with another
+     * thread than the one in which you created the JetPlayer instance.
+     * @param listener
+     * @param handler the Handler that will receive the event notification messages.
+     */
     public void setEventListener(OnJetEventListener listener, Handler handler) {
         synchronized(mEventListenerLock) {
             
@@ -343,7 +500,7 @@
         void onJetEvent(JetPlayer player,
                 short segment, byte track, byte channel, byte controller, byte value);
         /**
-         * Callback for when JET's currently playing segment userID is updated.
+         * Callback for when JET's currently playing segment's userID is updated.
          * 
          * @param player the JET player the status update is coming from
          * @param userId the ID of the currently playing segment
@@ -363,7 +520,7 @@
          * Callback for when JET pause state is updated.
          * 
          * @param player the JET player the status update is coming from
-         * @param paused indicates whether JET is paused or not
+         * @param paused indicates whether JET is paused (1) or not (0)
          */
         void onJetPauseUpdate(JetPlayer player, int paused);
     }
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index fe97b93..9443a95 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -75,14 +75,6 @@
     private static final boolean V = false || Config.LOGV;
     private static final boolean D = true || Config.LOGD;
     
-    /*
-     * When this was "net.dns1", sometimes the mobile data's DNS was seen
-     * instead due to a race condition. All we really care about is the
-     * DHCP-replied DNS server anyway.
-     */
-    /** The system property whose value provides the current DNS address. */
-    private static final String SYSTEMPROPERTY_KEY_DNS = "dhcp.tiwlan0.dns1";
-
     private Context mContext;
     private ContentResolver mContentResolver;
     private WifiStateTracker mWifiStateTracker;
diff --git a/tests/sketch/Android.mk b/tests/sketch/Android.mk
new file mode 100644
index 0000000..814e370
--- /dev/null
+++ b/tests/sketch/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Sketch
+
+include $(BUILD_PACKAGE)
diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java b/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java
index 0f8d317..8fee21a 100755
--- a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java
+++ b/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java
@@ -71,7 +71,6 @@
         mResult = (Spinner) findViewById(R.id.spinner);
         mResult.setOnItemSelectedListener(new OnItemSelectedListener() {
 
-            @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                 // TODO Auto-generated method stub
                 // correct the recognition result by adding the new example
@@ -83,7 +82,6 @@
                 }
             }
   
-            @Override
             public void onNothingSelected(AdapterView<?> parent) {
               // TODO Auto-generated method stub
               
@@ -96,17 +94,14 @@
         mView.cacheGesture(false);
         mView.setFadingOut(false);
         mView.addGestureListener(new GestureListener() {
-            @Override
             public void onFinishGesture(GesturePad patch, MotionEvent event) {
                 // TODO Auto-generated method stub
                 recognize(patch.getCurrentGesture());
             }
-            @Override
             public void onGesture(GesturePad patch, MotionEvent event) {
               // TODO Auto-generated method stub
               
             }
-            @Override
             public void onStartGesture(GesturePad patch, MotionEvent event) {
               // TODO Auto-generated method stub
               
diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
index a9893bc..7ae7fc5 100755
--- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
+++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java
@@ -87,7 +87,6 @@
         }
         
         mResult.setOnItemSelectedListener(new OnItemSelectedListener() {
-            @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                 // TODO Auto-generated method stub
                 mSamples = mRecognizer.getGestures(
@@ -103,7 +102,6 @@
                 mView.invalidate();
             }
   
-            @Override
             public void onNothingSelected(AdapterView<?> parent) {
               // TODO Auto-generated method stub
               
@@ -113,7 +111,6 @@
         
         Button remove = (Button)this.findViewById(R.id.remove);
         remove.setOnClickListener(new OnClickListener() {
-            @Override
             public void onClick(View v) {
                 // TODO Auto-generated method stub
                 if (mSamples.isEmpty())
@@ -154,7 +151,6 @@
         
         Button next = (Button)this.findViewById(R.id.next);
         next.setOnClickListener(new OnClickListener() {
-            @Override
             public void onClick(View v) {
                 // TODO Auto-generated method stub
                 if (mCurrentGestureIndex >= mSamples.size()-1)
@@ -172,7 +168,6 @@
 
         Button previous = (Button)this.findViewById(R.id.previous);
         previous.setOnClickListener(new OnClickListener() {
-            @Override
             public void onClick(View v) {
                 // TODO Auto-generated method stub
                 if (mCurrentGestureIndex >= 1 &&
diff --git a/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java b/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java
index 2035fad..cb8a9d3 100755
--- a/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java
+++ b/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java
@@ -66,7 +66,6 @@
     
         
         Collections.sort(list, new Comparator<Prediction>() {
-            @Override
             public int compare(Prediction object1, Prediction object2) {
                 // TODO Auto-generated method stub
                 double score1 = object1.score;