Merge "Added frustum plane extraction and sphere culling code."
diff --git a/api/9.xml b/api/9.xml
index 9d8456a..7a4aed0 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -195395,6 +195395,39 @@
 <parameter name="defStyle" type="int">
 </parameter>
 </constructor>
+<field name="CHOICE_MODE_MULTIPLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_SINGLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <method name="afterTextChanged"
  return="void"
  abstract="false"
@@ -203851,39 +203884,6 @@
 <parameter name="y" type="int">
 </parameter>
 </method>
-<field name="CHOICE_MODE_MULTIPLE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_NONE"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_SINGLE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ListView.FixedViewInfo"
  extends="java.lang.Object"
diff --git a/api/current.xml b/api/current.xml
index 4356852..739b0c9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -128150,6 +128150,16 @@
  visibility="public"
 >
 </field>
+<field name="SERIAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TAGS"
  type="java.lang.String"
  transient="false"
@@ -215125,6 +215135,17 @@
 <parameter name="after" type="int">
 </parameter>
 </method>
+<method name="clearChoices"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="clearTextFilter"
  return="void"
  abstract="false"
@@ -215147,6 +215168,61 @@
  visibility="public"
 >
 </method>
+<method name="getCheckedItemCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemIds"
+ return="long[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCheckedItemPositions"
+ return="android.util.SparseBooleanArray"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChoiceMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getListPaddingBottom"
  return="int"
  abstract="false"
@@ -215290,6 +215366,19 @@
  visibility="protected"
 >
 </method>
+<method name="isItemChecked"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
 <method name="isScrollingCacheEnabled"
  return="boolean"
  abstract="false"
@@ -215490,6 +215579,19 @@
 <parameter name="views" type="java.util.List&lt;android.view.View&gt;">
 </parameter>
 </method>
+<method name="setAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.ListAdapter">
+</parameter>
+</method>
 <method name="setCacheColorHint"
  return="void"
  abstract="false"
@@ -215503,6 +215605,19 @@
 <parameter name="color" type="int">
 </parameter>
 </method>
+<method name="setChoiceMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="choiceMode" type="int">
+</parameter>
+</method>
 <method name="setDrawSelectorOnTop"
  return="void"
  abstract="false"
@@ -215542,6 +215657,34 @@
 <parameter name="filterText" type="java.lang.String">
 </parameter>
 </method>
+<method name="setItemChecked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+<parameter name="value" type="boolean">
+</parameter>
+</method>
+<method name="setMultiChoiceModeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.AbsListView.MultiChoiceModeListener">
+</parameter>
+</method>
 <method name="setOnScrollListener"
  return="void"
  abstract="false"
@@ -215758,6 +215901,50 @@
 <parameter name="dr" type="android.graphics.drawable.Drawable">
 </parameter>
 </method>
+<field name="CHOICE_MODE_MULTIPLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_MULTIPLE_MODAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHOICE_MODE_SINGLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TRANSCRIPT_MODE_ALWAYS_SCROLL"
  type="int"
  transient="false"
@@ -215849,6 +216036,35 @@
 </parameter>
 </constructor>
 </class>
+<interface name="AbsListView.MultiChoiceModeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.ActionMode.Callback">
+</implements>
+<method name="onItemCheckedStateChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+<parameter name="position" type="int">
+</parameter>
+<parameter name="id" type="long">
+</parameter>
+<parameter name="checked" type="boolean">
+</parameter>
+</method>
+</interface>
 <interface name="AbsListView.OnScrollListener"
  abstract="true"
  static="true"
@@ -222296,19 +222512,6 @@
  visibility="public"
 >
 </method>
-<method name="setAdapter"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="adapter" type="android.widget.ListAdapter">
-</parameter>
-</method>
 <method name="setColumnWidth"
  return="void"
  abstract="false"
@@ -224611,17 +224814,6 @@
 <parameter name="v" type="android.view.View">
 </parameter>
 </method>
-<method name="clearChoices"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="findViewTraversal"
  return="android.view.View"
  abstract="false"
@@ -224670,61 +224862,6 @@
  visibility="public"
 >
 </method>
-<method name="getCheckedItemCount"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemIds"
- return="long[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemPosition"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getCheckedItemPositions"
- return="android.util.SparseBooleanArray"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getChoiceMode"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDivider"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -224791,19 +224928,6 @@
  visibility="public"
 >
 </method>
-<method name="isItemChecked"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="position" type="int">
-</parameter>
-</method>
 <method name="removeFooterView"
  return="boolean"
  abstract="false"
@@ -224830,32 +224954,6 @@
 <parameter name="v" type="android.view.View">
 </parameter>
 </method>
-<method name="setAdapter"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="adapter" type="android.widget.ListAdapter">
-</parameter>
-</method>
-<method name="setChoiceMode"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="choiceMode" type="int">
-</parameter>
-</method>
 <method name="setDivider"
  return="void"
  abstract="false"
@@ -224908,21 +225006,6 @@
 <parameter name="headerDividersEnabled" type="boolean">
 </parameter>
 </method>
-<method name="setItemChecked"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="position" type="int">
-</parameter>
-<parameter name="value" type="boolean">
-</parameter>
-</method>
 <method name="setItemsCanFocus"
  return="void"
  abstract="false"
@@ -224936,19 +225019,6 @@
 <parameter name="itemsCanFocus" type="boolean">
 </parameter>
 </method>
-<method name="setMultiChoiceModeListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.widget.ListView.MultiChoiceModeListener">
-</parameter>
-</method>
 <method name="setSelection"
  return="void"
  abstract="false"
@@ -225001,50 +225071,6 @@
 <parameter name="offset" type="int">
 </parameter>
 </method>
-<field name="CHOICE_MODE_MULTIPLE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_MULTIPLE_MODAL"
- type="int"
- transient="false"
- volatile="false"
- value="3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_NONE"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="CHOICE_MODE_SINGLE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ListView.FixedViewInfo"
  extends="java.lang.Object"
@@ -225093,35 +225119,6 @@
 >
 </field>
 </class>
-<interface name="ListView.MultiChoiceModeListener"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.view.ActionMode.Callback">
-</implements>
-<method name="onItemCheckedStateChanged"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="mode" type="android.view.ActionMode">
-</parameter>
-<parameter name="position" type="int">
-</parameter>
-<parameter name="id" type="long">
-</parameter>
-<parameter name="checked" type="boolean">
-</parameter>
-</method>
-</interface>
 <class name="MediaController"
  extends="android.widget.FrameLayout"
  abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d66e98b..d5741fc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -365,7 +365,8 @@
         
         /**
          * The time when the service was first made active, either by someone
-         * starting or binding to it.
+         * starting or binding to it.  This
+         * is in units of {@link android.os.SystemClock#elapsedRealtime()}.
          */
         public long activeSince;
         
@@ -387,7 +388,8 @@
         
         /**
          * The time when there was last activity in the service (either
-         * explicit requests to start it or clients binding to it).
+         * explicit requests to start it or clients binding to it).  This
+         * is in units of {@link android.os.SystemClock#uptimeMillis()}.
          */
         public long lastActivityTime;
         
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a699388..95f217f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -23,6 +23,7 @@
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.TimeUtils;
 
 /**
  * A class providing access to battery usage statistics, including information on
@@ -290,6 +291,11 @@
          */
         public static abstract class Proc {
 
+            public static class ExcessiveWake {
+                public long overTime;
+                public long usedTime;
+            }
+
             /**
              * Returns the total time (in 1/100 sec) spent executing in user code.
              *
@@ -326,6 +332,10 @@
              * @see BatteryStats#getCpuSpeedSteps()
              */
             public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
+
+            public abstract int countExcessiveWakes();
+
+            public abstract ExcessiveWake getExcessiveWake(int i);
         }
 
         /**
@@ -421,6 +431,8 @@
         public static final int STATE_BLUETOOTH_ON_FLAG = 1<<20;
         public static final int STATE_AUDIO_ON_FLAG = 1<<19;
         public static final int STATE_VIDEO_ON_FLAG = 1<<18;
+        public static final int STATE_WAKE_LOCK_FLAG = 1<<17;
+        public static final int STATE_SENSOR_ON_FLAG = 1<<16;
         
         public int states;
 
@@ -470,6 +482,16 @@
             batteryVoltage = o.batteryVoltage;
             states = o.states;
         }
+
+        public boolean same(HistoryItem o) {
+            return batteryLevel == o.batteryLevel
+                    && batteryStatus == o.batteryStatus
+                    && batteryHealth == o.batteryHealth
+                    && batteryPlugType == o.batteryPlugType
+                    && batteryTemperature == o.batteryTemperature
+                    && batteryVoltage == o.batteryVoltage
+                    && states == o.states;
+        }
     }
     
     public static final class BitDescription {
@@ -633,6 +655,8 @@
         new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth"),
         new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio"),
         new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video"),
+        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock"),
+        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor"),
         new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
                 HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness",
                 SCREEN_BRIGHTNESS_NAMES),
@@ -1376,7 +1400,6 @@
                         pw.println(getDischargeStartLevel());
                 pw.print(prefix); pw.print("    Discharge cycle current level: ");
                         pw.println(getDischargeCurrentLevel());
-            } else {
                 pw.print(prefix); pw.println("  Device is currently plugged into power");
                 pw.print(prefix); pw.print("    Last discharge cycle start level: "); 
                         pw.println(getDischargeStartLevel());
@@ -1384,6 +1407,13 @@
                         pw.println(getDischargeCurrentLevel());
             }
             pw.println(" ");
+        } else {
+            pw.print(prefix); pw.println("  Device battery use since last full charge");
+            pw.print(prefix); pw.print("    Amount discharged (lower bound): ");
+                    pw.println(getLowDischargeAmountSinceCharge());
+            pw.print(prefix); pw.print("    Amount discharged (upper bound): ");
+                    pw.println(getHighDischargeAmountSinceCharge());
+            pw.println(" ");
         }
         
 
@@ -1524,12 +1554,16 @@
                     long userTime;
                     long systemTime;
                     int starts;
+                    int numExcessive;
 
                     userTime = ps.getUserTime(which);
                     systemTime = ps.getSystemTime(which);
                     starts = ps.getStarts(which);
+                    numExcessive = which == STATS_SINCE_CHARGED
+                            ? ps.countExcessiveWakes() : 0;
 
-                    if (userTime != 0 || systemTime != 0 || starts != 0) {
+                    if (userTime != 0 || systemTime != 0 || starts != 0
+                            || numExcessive != 0) {
                         sb.setLength(0);
                         sb.append(prefix); sb.append("    Proc ");
                                 sb.append(ent.getKey()); sb.append(":\n");
@@ -1539,6 +1573,18 @@
                         sb.append(prefix); sb.append("      "); sb.append(starts);
                                 sb.append(" proc starts");
                         pw.println(sb.toString());
+                        for (int e=0; e<numExcessive; e++) {
+                            Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e);
+                            if (ew != null) {
+                                pw.print(prefix); pw.print("      * Killed for wake lock use: ");
+                                        TimeUtils.formatDuration(ew.usedTime, pw);
+                                        pw.print(" over ");
+                                        TimeUtils.formatDuration(ew.overTime, pw);
+                                        pw.print(" (");
+                                        pw.print((ew.usedTime*100)/ew.overTime);
+                                        pw.println("%)");
+                            }
+                        }
                         uidActivity = true;
                     }
                 }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 78ec638..8624467 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -62,6 +62,9 @@
     /** The name of the hardware (from the kernel command line or /proc). */
     public static final String HARDWARE = getString("ro.hardware");
 
+    /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */ 
+    public static final String SERIAL = getString("ro.serialno");
+  
     /** Various version strings. */
     public static class VERSION {
         /**
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a9d7342..d360140 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -192,10 +192,11 @@
         pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
         if (mQueue != null) {
             synchronized (mQueue) {
+                long now = SystemClock.uptimeMillis();
                 Message msg = mQueue.mMessages;
                 int n = 0;
                 while (msg != null) {
-                    pw.println(prefix + "  Message " + n + ": " + msg);
+                    pw.println(prefix + "  Message " + n + ": " + msg.toString(now));
                     n++;
                     msg = msg.next;
                 }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 476da1d..49b72fe 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.TimeUtils;
 
 /**
  * 
@@ -366,13 +367,17 @@
     }
 
     public String toString() {
+        return toString(SystemClock.uptimeMillis());
+    }
+
+    String toString(long now) {
         StringBuilder   b = new StringBuilder();
         
         b.append("{ what=");
         b.append(what);
 
         b.append(" when=");
-        b.append(when);
+        TimeUtils.formatDuration(when-now, b);
 
         if (arg1 != 0) {
             b.append(" arg1=");
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 0fc70d5..b01a71d 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -24,6 +24,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.TimeZone;
 import java.util.Date;
 
@@ -130,4 +131,128 @@
     public static String getTimeZoneDatabaseVersion() {
         return ZoneInfoDB.getVersion();
     }
+
+    private static final int SECONDS_PER_MINUTE = 60;
+    private static final int SECONDS_PER_HOUR = 60 * 60;
+    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+    /** @hide Just for debugging; not internationalized. */
+    public static void formatDuration(long duration, StringBuilder builder) {
+        if (duration == 0) {
+            builder.append("0");
+            return;
+        }
+        if (duration > 0) {
+            builder.append("+");
+        } else {
+            builder.append("-");
+            duration = -duration;
+        }
+
+        int millis = (int)(duration%1000);
+        int seconds = (int) Math.floor(duration / 1000);
+        int days = 0, hours = 0, minutes = 0;
+
+        if (seconds > SECONDS_PER_DAY) {
+            days = seconds / SECONDS_PER_DAY;
+            seconds -= days * SECONDS_PER_DAY;
+        }
+        if (seconds > SECONDS_PER_HOUR) {
+            hours = seconds / SECONDS_PER_HOUR;
+            seconds -= hours * SECONDS_PER_HOUR;
+        }
+        if (seconds > SECONDS_PER_MINUTE) {
+            minutes = seconds / SECONDS_PER_MINUTE;
+            seconds -= minutes * SECONDS_PER_MINUTE;
+        }
+
+        boolean doall = false;
+        if (days > 0) {
+            builder.append(days);
+            builder.append('d');
+            doall = true;
+        }
+        if (doall || hours > 0) {
+            builder.append(hours);
+            builder.append('h');
+            doall = true;
+        }
+        if (doall || minutes > 0) {
+            builder.append(minutes);
+            builder.append('m');
+            doall = true;
+        }
+        if (doall || seconds > 0) {
+            builder.append(seconds);
+            builder.append('s');
+            doall = true;
+        }
+        builder.append(millis);
+        builder.append("ms");
+    }
+
+    /** @hide Just for debugging; not internationalized. */
+    public static void formatDuration(long duration, PrintWriter pw) {
+        if (duration == 0) {
+            pw.print("0");
+            return;
+        }
+        if (duration > 0) {
+            pw.print("+");
+        } else {
+            pw.print("-");
+            duration = -duration;
+        }
+
+        int millis = (int)(duration%1000);
+        int seconds = (int) Math.floor(duration / 1000);
+        int days = 0, hours = 0, minutes = 0;
+
+        if (seconds > SECONDS_PER_DAY) {
+            days = seconds / SECONDS_PER_DAY;
+            seconds -= days * SECONDS_PER_DAY;
+        }
+        if (seconds > SECONDS_PER_HOUR) {
+            hours = seconds / SECONDS_PER_HOUR;
+            seconds -= hours * SECONDS_PER_HOUR;
+        }
+        if (seconds > SECONDS_PER_MINUTE) {
+            minutes = seconds / SECONDS_PER_MINUTE;
+            seconds -= minutes * SECONDS_PER_MINUTE;
+        }
+
+        boolean doall = false;
+        if (days > 0) {
+            pw.print(days);
+            pw.print('d');
+            doall = true;
+        }
+        if (doall || hours > 0) {
+            pw.print(hours);
+            pw.print('h');
+            doall = true;
+        }
+        if (doall || minutes > 0) {
+            pw.print(minutes);
+            pw.print('m');
+            doall = true;
+        }
+        if (doall || seconds > 0) {
+            pw.print(seconds);
+            pw.print('s');
+            doall = true;
+        }
+        pw.print(millis);
+        pw.print("ms");
+    }
+
+
+    /** @hide Just for debugging; not internationalized. */
+    public static void formatDuration(long time, long now, PrintWriter pw) {
+        if (time == 0) {
+            pw.print("--");
+            return;
+        }
+        formatDuration(time-now, pw);
+    }
 }
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index fabe5c8..34d7935 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -27,7 +27,8 @@
 
     
     /**
-     * Use the WindowManager interface to create a Display object.
+     * Use {@link android.view.WindowManager#getDefaultDisplay()
+     * WindowManager.getDefaultDisplay()} to create a Display object.
      * Display gives you access to some information about a particular display
      * connected to the device.
      */
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e572d3d..c155dda 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -34,10 +34,16 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -45,7 +51,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.view.ContextMenu.ContextMenuInfo;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -69,6 +74,7 @@
  * @attr ref android.R.styleable#AbsListView_cacheColorHint
  * @attr ref android.R.styleable#AbsListView_fastScrollEnabled
  * @attr ref android.R.styleable#AbsListView_smoothScrollbar
+ * @attr ref android.R.styleable#AbsListView_choiceMode
  */
 public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
         ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
@@ -167,6 +173,57 @@
     static final int LAYOUT_MOVE_SELECTION = 6;
 
     /**
+     * Normal list that does not indicate choices
+     */
+    public static final int CHOICE_MODE_NONE = 0;
+
+    /**
+     * The list allows up to one choice
+     */
+    public static final int CHOICE_MODE_SINGLE = 1;
+
+    /**
+     * The list allows multiple choices
+     */
+    public static final int CHOICE_MODE_MULTIPLE = 2;
+
+    /**
+     * The list allows multiple choices in a modal selection mode
+     */
+    public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
+
+    /**
+     * Controls if/how the user may choose/check items in the list
+     */
+    int mChoiceMode = CHOICE_MODE_NONE;
+
+    /**
+     * Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
+     */
+    ActionMode mChoiceActionMode;
+
+    /**
+     * Wrapper for the multiple choice mode callback; AbsListView needs to perform
+     * a few extra actions around what application code does.
+     */
+    MultiChoiceModeWrapper mMultiChoiceModeCallback;
+
+    /**
+     * Running count of how many items are currently checked
+     */
+    int mCheckedItemCount;
+
+    /**
+     * Running state of which positions are currently checked
+     */
+    SparseBooleanArray mCheckStates;
+
+    /**
+     * Running state of which IDs are currently checked
+     */
+    LongSparseArray<Boolean> mCheckedIdStates;
+
+    /**
      * Controls how the next layout will happen
      */
     int mLayoutMode = LAYOUT_NORMAL;
@@ -577,6 +634,8 @@
             });
         }
 
+        setChoiceMode(a.getInt(R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE));
+
         a.recycle();
     }
 
@@ -596,6 +655,311 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAdapter(ListAdapter adapter) {
+        if (adapter != null) {
+            if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() &&
+                    mCheckedIdStates == null) {
+                mCheckedIdStates = new LongSparseArray<Boolean>();
+            }
+        }
+
+        if (mCheckStates != null) {
+            mCheckStates.clear();
+        }
+
+        if (mCheckedIdStates != null) {
+            mCheckedIdStates.clear();
+        }
+    }
+
+    /**
+     * Returns the number of items currently selected. This will only be valid
+     * if the choice mode is not {@link #CHOICE_MODE_NONE} (default).
+     *
+     * <p>To determine the specific items that are currently selected, use one of
+     * the <code>getChecked*</code> methods.
+     *
+     * @return The number of items currently selected
+     *
+     * @see #getCheckedItemPosition()
+     * @see #getCheckedItemPositions()
+     * @see #getCheckedItemIds()
+     */
+    public int getCheckedItemCount() {
+        return mCheckedItemCount;
+    }
+
+    /**
+     * Returns the checked state of the specified position. The result is only
+     * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
+     * or {@link #CHOICE_MODE_MULTIPLE}.
+     *
+     * @param position The item whose checked state to return
+     * @return The item's checked state or <code>false</code> if choice mode
+     *         is invalid
+     *
+     * @see #setChoiceMode(int)
+     */
+    public boolean isItemChecked(int position) {
+        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
+            return mCheckStates.get(position);
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the currently checked item. The result is only valid if the choice
+     * mode has been set to {@link #CHOICE_MODE_SINGLE}.
+     *
+     * @return The position of the currently checked item or
+     *         {@link #INVALID_POSITION} if nothing is selected
+     *
+     * @see #setChoiceMode(int)
+     */
+    public int getCheckedItemPosition() {
+        if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
+            return mCheckStates.keyAt(0);
+        }
+
+        return INVALID_POSITION;
+    }
+
+    /**
+     * Returns the set of checked items in the list. The result is only valid if
+     * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
+     *
+     * @return  A SparseBooleanArray which will return true for each call to
+     *          get(int position) where position is a position in the list,
+     *          or <code>null</code> if the choice mode is set to
+     *          {@link #CHOICE_MODE_NONE}.
+     */
+    public SparseBooleanArray getCheckedItemPositions() {
+        if (mChoiceMode != CHOICE_MODE_NONE) {
+            return mCheckStates;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the set of checked items ids. The result is only valid if the
+     * choice mode has not been set to {@link #CHOICE_MODE_NONE} and the adapter
+     * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
+     *
+     * @return A new array which contains the id of each checked item in the
+     *         list.
+     */
+    public long[] getCheckedItemIds() {
+        if (mChoiceMode == CHOICE_MODE_NONE || mCheckedIdStates == null || mAdapter == null) {
+            return new long[0];
+        }
+
+        final LongSparseArray<Boolean> idStates = mCheckedIdStates;
+        final int count = idStates.size();
+        final long[] ids = new long[count];
+
+        for (int i = 0; i < count; i++) {
+            ids[i] = idStates.keyAt(i);
+        }
+
+        return ids;
+    }
+
+    /**
+     * Clear any choices previously set
+     */
+    public void clearChoices() {
+        if (mCheckStates != null) {
+            mCheckStates.clear();
+        }
+        if (mCheckedIdStates != null) {
+            mCheckedIdStates.clear();
+        }
+        mCheckedItemCount = 0;
+    }
+
+    /**
+     * Sets the checked state of the specified position. The is only valid if
+     * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
+     * {@link #CHOICE_MODE_MULTIPLE}.
+     *
+     * @param position The item whose checked state is to be checked
+     * @param value The new checked state for the item
+     */
+    public void setItemChecked(int position, boolean value) {
+        if (mChoiceMode == CHOICE_MODE_NONE) {
+            return;
+        }
+
+        // Start selection mode if needed. We don't need to if we're unchecking something.
+        if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+            mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
+        }
+
+        if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+            boolean oldValue = mCheckStates.get(position);
+            mCheckStates.put(position, value);
+            if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+                if (value) {
+                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+                } else {
+                    mCheckedIdStates.delete(mAdapter.getItemId(position));
+                }
+            }
+            if (oldValue != value) {
+                if (value) {
+                    mCheckedItemCount++;
+                } else {
+                    mCheckedItemCount--;
+                }
+            }
+            if (mChoiceActionMode != null) {
+                final long id = mAdapter.getItemId(position);
+                mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
+                        position, id, value);
+            }
+        } else {
+            boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
+            // Clear all values if we're checking something, or unchecking the currently
+            // selected item
+            if (value || isItemChecked(position)) {
+                mCheckStates.clear();
+                if (updateIds) {
+                    mCheckedIdStates.clear();
+                }
+            }
+            // this may end up selecting the value we just cleared but this way
+            // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
+            if (value) {
+                mCheckStates.put(position, true);
+                if (updateIds) {
+                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+                }
+                mCheckedItemCount = 1;
+            } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
+                mCheckedItemCount = 0;
+            }
+        }
+
+        // Do not generate a data change while we are in the layout phase
+        if (!mInLayout && !mBlockLayoutRequests) {
+            mDataChanged = true;
+            rememberSyncState();
+            requestLayout();
+        }
+    }
+
+    @Override
+    public boolean performItemClick(View view, int position, long id) {
+        boolean handled = false;
+
+        if (mChoiceMode != CHOICE_MODE_NONE) {
+            handled = true;
+
+            if (mChoiceMode == CHOICE_MODE_MULTIPLE ||
+                    (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null)) {
+                boolean newValue = !mCheckStates.get(position, false);
+                mCheckStates.put(position, newValue);
+                if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+                    if (newValue) {
+                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+                    } else {
+                        mCheckedIdStates.delete(mAdapter.getItemId(position));
+                    }
+                }
+                if (newValue) {
+                    mCheckedItemCount++;
+                } else {
+                    mCheckedItemCount--;
+                }
+                if (mChoiceActionMode != null) {
+                    mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
+                            position, id, newValue);
+                }
+            } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
+                boolean newValue = !mCheckStates.get(position, false);
+                if (newValue) {
+                    mCheckStates.clear();
+                    mCheckStates.put(position, true);
+                    if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
+                        mCheckedIdStates.clear();
+                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+                    }
+                    mCheckedItemCount = 1;
+                } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
+                    mCheckedItemCount = 0;
+                }
+            }
+
+            mDataChanged = true;
+            rememberSyncState();
+            requestLayout();
+        }
+
+        handled |= super.performItemClick(view, position, id);
+
+        return handled;
+    }
+
+    /**
+     * @see #setChoiceMode(int)
+     *
+     * @return The current choice mode
+     */
+    public int getChoiceMode() {
+        return mChoiceMode;
+    }
+
+    /**
+     * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
+     * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
+     * List allows up to one item to  be in a chosen state. By setting the choiceMode to
+     * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
+     *
+     * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
+     * {@link #CHOICE_MODE_MULTIPLE}
+     */
+    public void setChoiceMode(int choiceMode) {
+        mChoiceMode = choiceMode;
+        if (mChoiceActionMode != null) {
+            mChoiceActionMode.finish();
+            mChoiceActionMode = null;
+        }
+        if (mChoiceMode != CHOICE_MODE_NONE) {
+            if (mCheckStates == null) {
+                mCheckStates = new SparseBooleanArray();
+            }
+            if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
+                mCheckedIdStates = new LongSparseArray<Boolean>();
+            }
+            // Modal multi-choice mode only has choices when the mode is active. Clear them.
+            if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+                clearChoices();
+                setLongClickable(true);
+            }
+        }
+    }
+
+    /**
+     * Set a {@link MultiChoiceModeListener} that will manage the lifecycle of the
+     * selection {@link ActionMode}. Only used when the choice mode is set to
+     * {@link #CHOICE_MODE_MULTIPLE_MODAL}.
+     *
+     * @param listener Listener that will manage the selection mode
+     *
+     * @see #setChoiceMode(int)
+     */
+    public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
+        if (mMultiChoiceModeCallback == null) {
+            mMultiChoiceModeCallback = new MultiChoiceModeWrapper();
+        }
+        mMultiChoiceModeCallback.setWrapped(listener);
+    }
+
+    /**
      * Enables fast scrolling by letting the user quickly scroll through lists by
      * dragging the fast scroll thumb. The adapter attached to the list may want
      * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
@@ -813,6 +1177,8 @@
         int position;
         int height;
         String filter;
+        SparseBooleanArray checkState;
+        LongSparseArray<Boolean> checkIdState;
 
         /**
          * Constructor called from {@link AbsListView#onSaveInstanceState()}
@@ -832,6 +1198,13 @@
             position = in.readInt();
             height = in.readInt();
             filter = in.readString();
+            checkState = in.readSparseBooleanArray();
+            long[] idState = in.createLongArray();
+
+            if (idState.length > 0) {
+                checkIdState = new LongSparseArray<Boolean>();
+                checkIdState.setValues(idState, Boolean.TRUE);
+            }
         }
 
         @Override
@@ -843,6 +1216,8 @@
             out.writeInt(position);
             out.writeInt(height);
             out.writeString(filter);
+            out.writeSparseBooleanArray(checkState);
+            out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
         }
 
         @Override
@@ -854,7 +1229,8 @@
                     + " viewTop=" + viewTop
                     + " position=" + position
                     + " height=" + height
-                    + " filter=" + filter + "}";
+                    + " filter=" + filter
+                    + " checkState=" + checkState + "}";
         }
 
         public static final Parcelable.Creator<SavedState> CREATOR
@@ -918,6 +1294,9 @@
             }
         }
 
+        ss.checkState = mCheckStates;
+        ss.checkIdState = mCheckedIdStates;
+
         return ss;
     }
 
@@ -949,6 +1328,14 @@
 
         setFilterText(ss.filter);
 
+        if (ss.checkState != null) {
+            mCheckStates = ss.checkState;
+        }
+
+        if (ss.checkIdState != null) {
+            mCheckedIdStates = ss.checkIdState;
+        }
+
         requestLayout();
     }
 
@@ -1774,8 +2161,19 @@
 
     boolean performLongPress(final View child,
             final int longPressPosition, final long longPressId) {
-        boolean handled = false;
+        // CHOICE_MODE_MULTIPLE_MODAL takes over long press.
+        if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
+            if (mChoiceActionMode == null) {
+                mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
+                setItemChecked(longPressPosition, true);
+            }
+            // TODO Should we select the long pressed item if we were already in
+            // selection mode? (i.e. treat it like an item click?)
+            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            return true;
+        }
 
+        boolean handled = false;
         if (mOnItemLongClickListener != null) {
             handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
                     longPressPosition, longPressId);
@@ -3991,6 +4389,75 @@
     }
 
     /**
+     * A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.
+     * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
+     * {@link #onItemCheckedStateChanged(ActionMode, int, long, boolean)} events when the user
+     * selects and deselects list items.
+     */
+    public interface MultiChoiceModeListener extends ActionMode.Callback {
+        /**
+         * Called when an item is checked or unchecked during selection mode.
+         *
+         * @param mode The {@link ActionMode} providing the selection mode
+         * @param position Adapter position of the item that was checked or unchecked
+         * @param id Adapter ID of the item that was checked or unchecked
+         * @param checked <code>true</code> if the item is now checked, <code>false</code>
+         *                if the item is now unchecked.
+         */
+        public void onItemCheckedStateChanged(ActionMode mode,
+                int position, long id, boolean checked);
+    }
+
+    class MultiChoiceModeWrapper implements MultiChoiceModeListener {
+        private MultiChoiceModeListener mWrapped;
+
+        public void setWrapped(MultiChoiceModeListener wrapped) {
+            mWrapped = wrapped;
+        }
+
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            if (mWrapped.onCreateActionMode(mode, menu)) {
+                // Initialize checked graphic state?
+                setLongClickable(false);
+                return true;
+            }
+            return false;
+        }
+
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return mWrapped.onPrepareActionMode(mode, menu);
+        }
+
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return mWrapped.onActionItemClicked(mode, item);
+        }
+
+        public void onDestroyActionMode(ActionMode mode) {
+            mWrapped.onDestroyActionMode(mode);
+            mChoiceActionMode = null;
+
+            // Ending selection mode means deselecting everything.
+            clearChoices();
+
+            mDataChanged = true;
+            rememberSyncState();
+            requestLayout();
+
+            setLongClickable(true);
+        }
+
+        public void onItemCheckedStateChanged(ActionMode mode,
+                int position, long id, boolean checked) {
+            mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
+
+            // If there are no items selected we no longer need the selection mode.
+            if (getCheckedItemCount() == 0) {
+                mode.finish();
+            }
+        }
+    }
+
+    /**
      * AbsListView extends LayoutParams to provide a place to hold the view type.
      */
     public static class LayoutParams extends ViewGroup.LayoutParams {
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a5b3ed5..ea767f6 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -104,6 +104,26 @@
         a.recycle();
     }
 
+    /**
+     * Set how the user may select items from the grid.
+     *
+     * <p>GridView only supports {@link AbsListView#CHOICE_MODE_NONE} and
+     * {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}. Attempting to set an unsupported choice
+     * mode will throw an UnsupportedOperationException.
+     */
+    @Override
+    public void setChoiceMode(int choiceMode) {
+        switch (choiceMode) {
+        case CHOICE_MODE_NONE:
+        case CHOICE_MODE_MULTIPLE_MODAL:
+            super.setChoiceMode(choiceMode);
+            break;
+
+        default:
+            throw new UnsupportedOperationException("Unsupported choice mode " + choiceMode);
+        }
+    }
+
     @Override
     public ListAdapter getAdapter() {
         return mAdapter;
@@ -136,7 +156,10 @@
 
         mOldSelectedPosition = INVALID_POSITION;
         mOldSelectedRowId = INVALID_ROW_ID;
-        
+
+        // AbsListView#setAdapter will update choice mode states.
+        super.setAdapter(adapter);
+
         if (mAdapter != null) {
             mOldItemCount = mItemCount;
             mItemCount = mAdapter.getCount();
@@ -1312,6 +1335,12 @@
             child.setPressed(isPressed);
         }
 
+        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
+            if (child instanceof Checkable) {
+                ((Checkable) child).setChecked(mCheckStates.get(position));
+            }
+        }
+
         if (needToMeasure) {
             int childHeightSpec = ViewGroup.getChildMeasureSpec(
                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 32a9146..e30d4c8 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -53,6 +53,8 @@
  * within a larger container.
  *
  * <p>HorizontalScrollView only supports horizontal scrolling.
+ * 
+ * @attr ref android.R.styleable#HorizontalScrollView_fillViewport 
  */
 public class HorizontalScrollView extends FrameLayout {
     private static final int ANIMATED_SCROLL_GAP = ScrollView.ANIMATED_SCROLL_GAP;
@@ -248,20 +250,25 @@
     }
 
     /**
-     * Indicates whether this ScrollView's content is stretched to fill the viewport.
+     * Indicates whether this HorizontalScrollView's content is stretched to
+     * fill the viewport.
      *
      * @return True if the content fills the viewport, false otherwise.
+     *
+     * @attr ref android.R.styleable#HorizontalScrollView_fillViewport
      */
     public boolean isFillViewport() {
         return mFillViewport;
     }
 
     /**
-     * Indicates this ScrollView whether it should stretch its content width to fill
-     * the viewport or not.
+     * Indicates this HorizontalScrollView whether it should stretch its content width
+     * to fill the viewport or not.
      *
      * @param fillViewport True to stretch the content's width to the viewport's
      *        boundaries, false otherwise.
+     * 
+     * @attr ref android.R.styleable#HorizontalScrollView_fillViewport
      */
     public void setFillViewport(boolean fillViewport) {
         if (fillViewport != mFillViewport) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 0d0a1ba..de7157b 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -28,17 +28,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.AttributeSet;
-import android.util.LongSparseArray;
 import android.util.SparseBooleanArray;
-import android.view.ActionMode;
 import android.view.FocusFinder;
-import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
 import android.view.View;
@@ -67,7 +60,6 @@
  * @attr ref android.R.styleable#ListView_entries
  * @attr ref android.R.styleable#ListView_divider
  * @attr ref android.R.styleable#ListView_dividerHeight
- * @attr ref android.R.styleable#ListView_choiceMode
  * @attr ref android.R.styleable#ListView_headerDividersEnabled
  * @attr ref android.R.styleable#ListView_footerDividersEnabled
  */
@@ -79,26 +71,6 @@
     static final int NO_POSITION = -1;
 
     /**
-     * Normal list that does not indicate choices
-     */
-    public static final int CHOICE_MODE_NONE = 0;
-
-    /**
-     * The list allows up to one choice
-     */
-    public static final int CHOICE_MODE_SINGLE = 1;
-
-    /**
-     * The list allows multiple choices
-     */
-    public static final int CHOICE_MODE_MULTIPLE = 2;
-
-    /**
-     * The list allows multiple choices in a modal selection mode
-     */
-    public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
-
-    /**
      * When arrow scrolling, ListView will never scroll more than this factor
      * times the height of the list.
      */
@@ -141,11 +113,6 @@
 
     private boolean mItemsCanFocus = false;
 
-    private int mChoiceMode = CHOICE_MODE_NONE;
-
-    private SparseBooleanArray mCheckStates;
-    private LongSparseArray<Boolean> mCheckedIdStates;
-
     // used for temporary calculations.
     private final Rect mTempRect = new Rect();
     private Paint mDividerPaint;
@@ -157,11 +124,6 @@
     // Keeps focused children visible through resizes
     private FocusSelector mFocusSelector;
 
-    // Controls CHOICE_MODE_MULTIPLE_MODAL. null when inactive.
-    private ActionMode mChoiceActionMode;
-    private MultiChoiceModeWrapper mMultiChoiceModeCallback;
-    private int mCheckedItemCount;
-
     public ListView(Context context) {
         this(context, null);
     }
@@ -196,8 +158,6 @@
             setDividerHeight(dividerHeight);
         }
 
-        setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE));
-        
         mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
         mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
 
@@ -457,6 +417,10 @@
 
         mOldSelectedPosition = INVALID_POSITION;
         mOldSelectedRowId = INVALID_ROW_ID;
+
+        // AbsListView#setAdapter will update choice mode states.
+        super.setAdapter(adapter);
+
         if (mAdapter != null) {
             mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
             mOldItemCount = mItemCount;
@@ -481,13 +445,6 @@
                 // Nothing selected
                 checkSelectionChanged();
             }
-
-            if (mChoiceMode != CHOICE_MODE_NONE &&
-                    mAdapter.hasStableIds() &&
-                    mCheckedIdStates == null) {
-                mCheckedIdStates = new LongSparseArray<Boolean>();
-            }
-
         } else {
             mAreAllItemsSelectable = true;
             checkFocus();
@@ -495,14 +452,6 @@
             checkSelectionChanged();
         }
 
-        if (mCheckStates != null) {
-            mCheckStates.clear();
-        }
-        
-        if (mCheckedIdStates != null) {
-            mCheckedIdStates.clear();
-        }
-
         requestLayout();
     }
 
@@ -3360,270 +3309,6 @@
     }
 
     /**
-     * @see #setChoiceMode(int)
-     *
-     * @return The current choice mode
-     */
-    public int getChoiceMode() {
-        return mChoiceMode;
-    }
-
-    /**
-     * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
-     * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
-     * List allows up to one item to  be in a chosen state. By setting the choiceMode to
-     * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
-     *
-     * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
-     * {@link #CHOICE_MODE_MULTIPLE}
-     */
-    public void setChoiceMode(int choiceMode) {
-        mChoiceMode = choiceMode;
-        if (mChoiceActionMode != null) {
-            mChoiceActionMode.finish();
-            mChoiceActionMode = null;
-        }
-        if (mChoiceMode != CHOICE_MODE_NONE) {
-            if (mCheckStates == null) {
-                mCheckStates = new SparseBooleanArray();
-            }
-            if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
-                mCheckedIdStates = new LongSparseArray<Boolean>();
-            }
-            // Modal multi-choice mode only has choices when the mode is active. Clear them.
-            if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
-                clearChoices();
-                setLongClickable(true);
-            }
-        }
-    }
-
-    /**
-     * Set a {@link MultiChoiceModeListener} that will manage the lifecycle of the
-     * selection {@link ActionMode}. Only used when the choice mode is set to
-     * {@link #CHOICE_MODE_MULTIPLE_MODAL}.
-     *
-     * @param listener Listener that will manage the selection mode
-     *
-     * @see #setChoiceMode(int)
-     */
-    public void setMultiChoiceModeListener(MultiChoiceModeListener listener) {
-        if (mMultiChoiceModeCallback == null) {
-            mMultiChoiceModeCallback = new MultiChoiceModeWrapper();
-        }
-        mMultiChoiceModeCallback.setWrapped(listener);
-    }
-
-    @Override
-    boolean performLongPress(final View child,
-            final int longPressPosition, final long longPressId) {
-        boolean handled = false;
-        if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
-            handled = true;
-            if (mChoiceActionMode == null) {
-                mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
-                setItemChecked(longPressPosition, true);
-            }
-            // TODO Should we select the long pressed item if we were already in
-            // selection mode? (i.e. treat it like an item click?)
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-        }
-        return handled | super.performLongPress(child, longPressPosition, longPressId);
-    }
-
-    @Override
-    public boolean performItemClick(View view, int position, long id) {
-        boolean handled = false;
-
-        if (mChoiceMode != CHOICE_MODE_NONE) {
-            handled = true;
-
-            if (mChoiceMode == CHOICE_MODE_MULTIPLE ||
-                    (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null)) {
-                boolean newValue = !mCheckStates.get(position, false);
-                mCheckStates.put(position, newValue);
-                if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                    if (newValue) {
-                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
-                    } else {
-                        mCheckedIdStates.delete(mAdapter.getItemId(position));
-                    }
-                }
-                if (newValue) {
-                    mCheckedItemCount++;
-                } else {
-                    mCheckedItemCount--;
-                }
-                if (mChoiceActionMode != null) {
-                    mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
-                            position, id, newValue);
-                }
-            } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
-                boolean newValue = !mCheckStates.get(position, false);
-                if (newValue) {
-                    mCheckStates.clear();
-                    mCheckStates.put(position, true);
-                    if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                        mCheckedIdStates.clear();
-                        mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
-                    }
-                    mCheckedItemCount = 1;
-                } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
-                    mCheckedItemCount = 0;
-                }
-            }
-
-            mDataChanged = true;
-            rememberSyncState();
-            requestLayout();
-        }
-
-        handled |= super.performItemClick(view, position, id);
-
-        return handled;
-    }
-
-    /**
-     * Sets the checked state of the specified position. The is only valid if
-     * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
-     * {@link #CHOICE_MODE_MULTIPLE}.
-     * 
-     * @param position The item whose checked state is to be checked
-     * @param value The new checked state for the item
-     */
-    public void setItemChecked(int position, boolean value) {
-        if (mChoiceMode == CHOICE_MODE_NONE) {
-            return;
-        }
-
-        // Start selection mode if needed. We don't need to if we're unchecking something.
-        if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
-            mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
-        }
-
-        if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
-            boolean oldValue = mCheckStates.get(position);
-            mCheckStates.put(position, value);
-            if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                if (value) {
-                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
-                } else {
-                    mCheckedIdStates.delete(mAdapter.getItemId(position));
-                }
-            }
-            if (oldValue != value) {
-                if (value) {
-                    mCheckedItemCount++;
-                } else {
-                    mCheckedItemCount--;
-                }
-            }
-            if (mChoiceActionMode != null) {
-                final long id = mAdapter.getItemId(position);
-                mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
-                        position, id, value);
-            }
-        } else {
-            boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
-            // Clear all values if we're checking something, or unchecking the currently
-            // selected item
-            if (value || isItemChecked(position)) {
-                mCheckStates.clear();
-                if (updateIds) {
-                    mCheckedIdStates.clear();
-                }
-            }
-            // this may end up selecting the value we just cleared but this way
-            // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
-            if (value) {
-                mCheckStates.put(position, true);
-                if (updateIds) {
-                    mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
-                }
-                mCheckedItemCount = 1;
-            } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
-                mCheckedItemCount = 0;
-            }
-        }
-
-        // Do not generate a data change while we are in the layout phase
-        if (!mInLayout && !mBlockLayoutRequests) {
-            mDataChanged = true;
-            rememberSyncState();
-            requestLayout();
-        }
-    }
-
-    /**
-     * Returns the number of items currently selected. This will only be valid
-     * if the choice mode is not {@link #CHOICE_MODE_NONE} (default).
-     * 
-     * <p>To determine the specific items that are currently selected, use one of
-     * the <code>getChecked*</code> methods.
-     *
-     * @return The number of items currently selected
-     *
-     * @see #getCheckedItemPosition()
-     * @see #getCheckedItemPositions()
-     * @see #getCheckedItemIds()
-     */
-    public int getCheckedItemCount() {
-        return mCheckedItemCount;
-    }
-
-    /**
-     * Returns the checked state of the specified position. The result is only
-     * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
-     * or {@link #CHOICE_MODE_MULTIPLE}.
-     *
-     * @param position The item whose checked state to return
-     * @return The item's checked state or <code>false</code> if choice mode
-     *         is invalid
-     *
-     * @see #setChoiceMode(int)
-     */
-    public boolean isItemChecked(int position) {
-        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
-            return mCheckStates.get(position);
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the currently checked item. The result is only valid if the choice
-     * mode has been set to {@link #CHOICE_MODE_SINGLE}.
-     *
-     * @return The position of the currently checked item or
-     *         {@link #INVALID_POSITION} if nothing is selected
-     *
-     * @see #setChoiceMode(int)
-     */
-    public int getCheckedItemPosition() {
-        if (mChoiceMode == CHOICE_MODE_SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
-            return mCheckStates.keyAt(0);
-        }
-
-        return INVALID_POSITION;
-    }
-
-    /**
-     * Returns the set of checked items in the list. The result is only valid if
-     * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
-     *
-     * @return  A SparseBooleanArray which will return true for each call to
-     *          get(int position) where position is a position in the list,
-     *          or <code>null</code> if the choice mode is set to
-     *          {@link #CHOICE_MODE_NONE}.
-     */
-    public SparseBooleanArray getCheckedItemPositions() {
-        if (mChoiceMode != CHOICE_MODE_NONE) {
-            return mCheckStates;
-        }
-        return null;
-    }
-
-    /**
      * Returns the set of checked items ids. The result is only valid if the
      * choice mode has not been set to {@link #CHOICE_MODE_NONE}.
      * 
@@ -3667,185 +3352,4 @@
         }
         return new long[0];
     }
-    
-    /**
-     * Returns the set of checked items ids. The result is only valid if the
-     * choice mode has not been set to {@link #CHOICE_MODE_NONE} and the adapter
-     * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
-     * 
-     * @return A new array which contains the id of each checked item in the
-     *         list.
-     */
-    public long[] getCheckedItemIds() {
-        if (mChoiceMode == CHOICE_MODE_NONE || mCheckedIdStates == null || mAdapter == null) {
-            return new long[0];
-        }
-        
-        final LongSparseArray<Boolean> idStates = mCheckedIdStates;
-        final int count = idStates.size();
-        final long[] ids = new long[count];
-        
-        for (int i = 0; i < count; i++) {
-            ids[i] = idStates.keyAt(i);
-        }
-        
-        return ids;
-    }
-
-    /**
-     * Clear any choices previously set
-     */
-    public void clearChoices() {
-        if (mCheckStates != null) {
-            mCheckStates.clear();
-        }
-        if (mCheckedIdStates != null) {
-            mCheckedIdStates.clear();
-        }
-        mCheckedItemCount = 0;
-    }
-
-    /**
-     * A MultiChoiceModeListener receives events for {@link ListView#CHOICE_MODE_MULTIPLE_MODAL}.
-     * It acts as the {@link ActionMode.Callback} for the selection mode and also receives
-     * {@link #onItemCheckedStateChanged(ActionMode, int, long, boolean)} events when the user
-     * selects and deselects list items.
-     */
-    public interface MultiChoiceModeListener extends ActionMode.Callback {
-        /**
-         * Called when an item is checked or unchecked during selection mode.
-         *
-         * @param mode The {@link ActionMode} providing the selection mode
-         * @param position Adapter position of the item that was checked or unchecked
-         * @param id Adapter ID of the item that was checked or unchecked
-         * @param checked <code>true</code> if the item is now checked, <code>false</code>
-         *                if the item is now unchecked.
-         */
-        public void onItemCheckedStateChanged(ActionMode mode,
-                int position, long id, boolean checked);
-    }
-
-    private class MultiChoiceModeWrapper implements MultiChoiceModeListener {
-        private MultiChoiceModeListener mWrapped;
-
-        public void setWrapped(MultiChoiceModeListener wrapped) {
-            mWrapped = wrapped;
-        }
-
-        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            if (mWrapped.onCreateActionMode(mode, menu)) {
-                // Initialize checked graphic state?
-                setLongClickable(false);
-                return true;
-            }
-            return false;
-        }
-
-        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-            return mWrapped.onPrepareActionMode(mode, menu);
-        }
-
-        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-            return mWrapped.onActionItemClicked(mode, item);
-        }
-
-        public void onDestroyActionMode(ActionMode mode) {
-            mWrapped.onDestroyActionMode(mode);
-            mChoiceActionMode = null;
-
-            // Ending selection mode means deselecting everything.
-            clearChoices();
-
-            mDataChanged = true;
-            rememberSyncState();
-            requestLayout();
-
-            setLongClickable(true);
-        }
-
-        public void onItemCheckedStateChanged(ActionMode mode,
-                int position, long id, boolean checked) {
-            mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
-
-            // If there are no items selected we no longer need the selection mode.
-            if (getCheckedItemCount() == 0) {
-                mode.finish();
-            }
-        }
-    }
-
-    static class SavedState extends BaseSavedState {
-        SparseBooleanArray checkState;
-        LongSparseArray<Boolean> checkIdState;
-
-        /**
-         * Constructor called from {@link ListView#onSaveInstanceState()}
-         */
-        SavedState(Parcelable superState, SparseBooleanArray checkState,
-                LongSparseArray<Boolean> checkIdState) {
-            super(superState);
-            this.checkState = checkState;
-            this.checkIdState = checkIdState;
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-            checkState = in.readSparseBooleanArray();
-            long[] idState = in.createLongArray();
-
-            if (idState.length > 0) {
-                checkIdState = new LongSparseArray<Boolean>();
-                checkIdState.setValues(idState, Boolean.TRUE);
-            }
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeSparseBooleanArray(checkState);
-            out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
-        }
-
-        @Override
-        public String toString() {
-            return "ListView.SavedState{"
-                    + Integer.toHexString(System.identityHashCode(this))
-                    + " checkState=" + checkState + "}";
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        return new SavedState(superState, mCheckStates, mCheckedIdStates);
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
-
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        if (ss.checkState != null) {
-           mCheckStates = ss.checkState;
-        }
-
-        if (ss.checkIdState != null) {
-            mCheckedIdStates = ss.checkIdState;
-        }
-    }
 }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 959e982..eb527eb 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -49,6 +49,8 @@
  * within a larger container.
  * 
  * <p>ScrollView only supports vertical scrolling.
+ *
+ * @attr ref android.R.styleable#ScrollView_fillViewport
  */
 public class ScrollView extends FrameLayout {
     static final int ANIMATED_SCROLL_GAP = 250;
@@ -247,6 +249,8 @@
      * Indicates whether this ScrollView's content is stretched to fill the viewport.
      *
      * @return True if the content fills the viewport, false otherwise.
+     * 
+     * @attr ref android.R.styleable#ScrollView_fillViewport
      */
     public boolean isFillViewport() {
         return mFillViewport;
@@ -258,6 +262,8 @@
      *
      * @param fillViewport True to stretch the content's height to the viewport's
      *        boundaries, false otherwise.
+     * 
+     * @attr ref android.R.styleable#ScrollView_fillViewport
      */
     public void setFillViewport(boolean fillViewport) {
         if (fillViewport != mFillViewport) {
@@ -566,16 +572,6 @@
         }
     }
     
-    private int getScrollRange() {
-        int scrollRange = 0;
-        if (getChildCount() > 0) {
-            View child = getChildAt(0);
-            scrollRange = Math.max(0,
-                    child.getHeight() - getHeight() - mPaddingBottom - mPaddingTop);
-        }
-        return scrollRange;
-    }
-
     /**
      * <p>
      * Finds the next focusable component that fits in this View's bounds
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index d040d3f..1620778 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -22,8 +22,8 @@
 
 interface IBatteryStats {
     byte[] getStatistics();
-    void noteStartWakelock(int uid, String name, int type);
-    void noteStopWakelock(int uid, String name, int type);
+    void noteStartWakelock(int uid, int pid, String name, int type);
+    void noteStopWakelock(int uid, int pid, String name, int type);
     
     /* DO NOT CHANGE the position of noteStartSensor without updating
        SensorService.cpp */
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index ce5959d..e1c5564 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,17 +18,31 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.MotionEvent;
 import android.widget.ImageView;
+import android.widget.Toast;
 
 public class PlatLogoActivity extends Activity {
+    Toast mToast;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
+        mToast = Toast.makeText(this, "Zombie art by Jack Larson", Toast.LENGTH_SHORT);
+
         ImageView content = new ImageView(this);
         content.setImageResource(com.android.internal.R.drawable.platlogo);
         content.setScaleType(ImageView.ScaleType.FIT_CENTER);
         
         setContentView(content);
     }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_UP) {
+            mToast.show();
+        }
+        return super.dispatchTouchEvent(ev);
+    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 13b3033..a70dbf6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -63,7 +63,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 49;
+    private static final int VERSION = 50;
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 1000;
@@ -107,6 +107,7 @@
     int mNumHistoryItems;
     HistoryItem mHistory;
     HistoryItem mHistoryEnd;
+    HistoryItem mHistoryLastEnd;
     HistoryItem mHistoryCache;
     final HistoryItem mHistoryCur = new HistoryItem();
     
@@ -451,7 +452,7 @@
          * Clear state of this timer.  Returns true if the timer is inactive
          * so can be completely dropped.
          */
-        boolean reset(boolean detachIfReset) {
+        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
             mTotalTime = mLoadedTime = mLastTime = 0;
             mCount = mLoadedCount = mLastCount = 0;
             if (detachIfReset) {
@@ -713,8 +714,8 @@
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
         
-        boolean reset(boolean detachIfReset) {
-            super.reset(detachIfReset);
+        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
+            super.reset(stats, detachIfReset);
             setStale();
             return true;
         }
@@ -749,7 +750,7 @@
         long mUpdateTime;
         
         /**
-         * The total time at which the timer was acquired, to determine if
+         * The total time at which the timer was acquired, to determine if it
          * was actually held for an interesting duration.
          */
         long mAcquireTime;
@@ -890,9 +891,14 @@
             return mCount;
         }
 
-        boolean reset(boolean detachIfReset) {
+        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
             boolean canDetach = mNesting <= 0;
-            super.reset(canDetach && detachIfReset);
+            super.reset(stats, canDetach && detachIfReset);
+            if (mNesting > 0) {
+                mUpdateTime = stats.getBatteryRealtimeLocked(
+                        SystemClock.elapsedRealtime() * 1000);
+            }
+            mAcquireTime = mTotalTime;
             return canDetach;
         }
         
@@ -1115,6 +1121,26 @@
         if (!mHaveBatteryLevel || !mRecordingHistory) {
             return;
         }
+
+        // If the current time is basically the same as the last time,
+        // just collapse into one record.
+        if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
+                && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) {
+            // If the current is the same as the one before, then we no
+            // longer need the entry.
+            if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
+                    && mHistoryLastEnd.same(mHistoryCur)) {
+                mHistoryLastEnd.next = null;
+                mHistoryEnd.next = mHistoryCache;
+                mHistoryCache = mHistoryEnd;
+                mHistoryEnd = mHistoryLastEnd;
+                mHistoryLastEnd = null;
+            } else {
+                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
+            }
+            return;
+        }
+
         if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
             // Once we've reached the maximum number of items, we only
             // record changes to the battery level.
@@ -1123,6 +1149,7 @@
                 return;
             }
         }
+
         addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
     }
     
@@ -1141,6 +1168,7 @@
     void addHistoryRecordLocked(HistoryItem rec) {
         mNumHistoryItems++;
         rec.next = null;
+        mHistoryLastEnd = mHistoryEnd;
         if (mHistoryEnd != null) {
             mHistoryEnd.next = rec;
             mHistoryEnd = rec;
@@ -1153,7 +1181,7 @@
         if (mHistory != null) {
             mHistoryEnd.next = mHistoryCache;
             mHistoryCache = mHistory;
-            mHistory = mHistoryEnd = null;
+            mHistory = mHistoryLastEnd = mHistoryEnd = null;
         }
         mNumHistoryItems = 0;
         mHistoryBaseTime = 0;
@@ -1211,6 +1239,89 @@
         mBluetoothPingStart = -1;
     }
 
+    int mWakeLockNesting;
+
+    public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+        if (type == WAKE_TYPE_PARTIAL) {
+            // Only care about partial wake locks, since full wake locks
+            // will be canceled when the user puts the screen to sleep.
+            if (mWakeLockNesting == 0) {
+                mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            }
+            mWakeLockNesting++;
+        }
+        if (uid >= 0) {
+            getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
+        }
+    }
+
+    public void noteStopWakeLocked(int uid, int pid, String name, int type) {
+        if (type == WAKE_TYPE_PARTIAL) {
+            mWakeLockNesting--;
+            if (mWakeLockNesting == 0) {
+                mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            }
+        }
+        if (uid >= 0) {
+            getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
+        }
+    }
+
+    public void noteProcessDiedLocked(int uid, int pid) {
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.mPids.remove(pid);
+        }
+    }
+
+    public long getProcessWakeTime(int uid, int pid, long realtime) {
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            Uid.Pid p = u.mPids.get(pid);
+            if (p != null) {
+                return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0);
+            }
+        }
+        return 0;
+    }
+
+    public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.reportExcessiveWakeLocked(proc, overTime, usedTime);
+        }
+    }
+
+    int mSensorNesting;
+
+    public void noteStartSensorLocked(int uid, int sensor) {
+        if (mSensorNesting == 0) {
+            mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+        }
+        mSensorNesting++;
+        getUidStatsLocked(uid).noteStartSensor(sensor);
+    }
+
+    public void noteStopSensorLocked(int uid, int sensor) {
+        mSensorNesting--;
+        if (mSensorNesting == 0) {
+            mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+        }
+        getUidStatsLocked(uid).noteStopSensor(sensor);
+    }
+
     int mGpsNesting;
     
     public void noteStartGpsLocked(int uid) {
@@ -1246,6 +1357,10 @@
             if (mScreenBrightnessBin >= 0) {
                 mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
             }
+
+            // Fake a wake lock, so we consider the device waked as long
+            // as the screen is on.
+            noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
         }
     }
     
@@ -1260,6 +1375,8 @@
             if (mScreenBrightnessBin >= 0) {
                 mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
             }
+
+            noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
         }
     }
     
@@ -1800,6 +1917,11 @@
          */
         final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
         
+        /**
+         * The transient wake stats we have collected for this uid's pids.
+         */
+        final SparseArray<Pid> mPids = new SparseArray<Pid>();
+
         public Uid(int uid) {
             mUid = uid;
             mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
@@ -2083,27 +2205,27 @@
             boolean active = false;
             
             if (mWifiTurnedOnTimer != null) {
-                active |= !mWifiTurnedOnTimer.reset(false);
+                active |= !mWifiTurnedOnTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiTurnedOn;
             }
             if (mFullWifiLockTimer != null) {
-                active |= !mFullWifiLockTimer.reset(false);
+                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
                 active |= mFullWifiLockOut;
             }
             if (mScanWifiLockTimer != null) {
-                active |= !mScanWifiLockTimer.reset(false);
+                active |= !mScanWifiLockTimer.reset(BatteryStatsImpl.this, false);
                 active |= mScanWifiLockOut;
             }
             if (mWifiMulticastTimer != null) {
-                active |= !mWifiMulticastTimer.reset(false);
+                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiMulticastEnabled;
             }
             if (mAudioTurnedOnTimer != null) {
-                active |= !mAudioTurnedOnTimer.reset(false);
+                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
                 active |= mAudioTurnedOn;
             }
             if (mVideoTurnedOnTimer != null) {
-                active |= !mVideoTurnedOnTimer.reset(false);
+                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
                 active |= mVideoTurnedOn;
             }
             
@@ -2148,6 +2270,14 @@
                 }
                 mProcessStats.clear();
             }
+            if (mPids.size() > 0) {
+                for (int i=0; !active && i<mPids.size(); i++) {
+                    Pid pid = mPids.valueAt(i);
+                    if (pid.mWakeStart != 0) {
+                        active = true;
+                    }
+                }
+            }
             if (mPackageStats.size() > 0) {
                 Iterator<Map.Entry<String, Pkg>> it = mPackageStats.entrySet().iterator();
                 while (it.hasNext()) {
@@ -2166,6 +2296,8 @@
                 mPackageStats.clear();
             }
             
+            mPids.clear();
+
             if (!active) {
                 if (mWifiTurnedOnTimer != null) {
                     mWifiTurnedOnTimer.detach();
@@ -2414,13 +2546,13 @@
             boolean reset() {
                 boolean wlactive = false;
                 if (mTimerFull != null) {
-                    wlactive |= !mTimerFull.reset(false);
+                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
                 }
                 if (mTimerPartial != null) {
-                    wlactive |= !mTimerPartial.reset(false);
+                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
                 }
                 if (mTimerWindow != null) {
-                    wlactive |= !mTimerWindow.reset(false);
+                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
                 }
                 if (!wlactive) {
                     if (mTimerFull != null) {
@@ -2488,7 +2620,7 @@
             }
 
             boolean reset() {
-                if (mTimer.reset(true)) {
+                if (mTimer.reset(BatteryStatsImpl.this, true)) {
                     mTimer = null;
                     return true;
                 }
@@ -2600,6 +2732,8 @@
 
             SamplingCounter[] mSpeedBins;
 
+            ArrayList<ExcessiveWake> mExcessiveWake;
+
             Proc() {
                 mUnpluggables.add(this);
                 mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
@@ -2626,6 +2760,58 @@
                 }
             }
             
+            public int countExcessiveWakes() {
+                return mExcessiveWake != null ? mExcessiveWake.size() : 0;
+            }
+
+            public ExcessiveWake getExcessiveWake(int i) {
+                if (mExcessiveWake != null) {
+                    return mExcessiveWake.get(i);
+                }
+                return null;
+            }
+
+            public void addExcessiveWake(long overTime, long usedTime) {
+                if (mExcessiveWake == null) {
+                    mExcessiveWake = new ArrayList<ExcessiveWake>();
+                }
+                ExcessiveWake ew = new ExcessiveWake();
+                ew.overTime = overTime;
+                ew.usedTime = usedTime;
+                mExcessiveWake.add(ew);
+            }
+
+            void writeExcessiveWakeToParcelLocked(Parcel out) {
+                if (mExcessiveWake == null) {
+                    out.writeInt(0);
+                    return;
+                }
+
+                final int N = mExcessiveWake.size();
+                out.writeInt(N);
+                for (int i=0; i<N; i++) {
+                    ExcessiveWake ew = mExcessiveWake.get(i);
+                    out.writeLong(ew.overTime);
+                    out.writeLong(ew.usedTime);
+                }
+            }
+
+            void readExcessiveWakeFromParcelLocked(Parcel in) {
+                final int N = in.readInt();
+                if (N == 0) {
+                    mExcessiveWake = null;
+                    return;
+                }
+
+                mExcessiveWake = new ArrayList<ExcessiveWake>();
+                for (int i=0; i<N; i++) {
+                    ExcessiveWake ew = new ExcessiveWake();
+                    ew.overTime = in.readLong();
+                    ew.usedTime = in.readLong();
+                    mExcessiveWake.add(ew);
+                }
+            }
+
             void writeToParcelLocked(Parcel out) {
                 out.writeLong(mUserTime);
                 out.writeLong(mSystemTime);
@@ -2650,6 +2836,8 @@
                         out.writeInt(0);
                     }
                 }
+
+                writeExcessiveWakeToParcelLocked(out);
             }
 
             void readFromParcelLocked(Parcel in) {
@@ -2678,6 +2866,8 @@
                         mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
                     }
                 }
+
+                readExcessiveWakeFromParcelLocked(in);
             }
 
             public BatteryStatsImpl getBatteryStats() {
@@ -3155,6 +3345,11 @@
             }
         }
 
+        public class Pid {
+            long mWakeSum;
+            long mWakeStart;
+        }
+
         /**
          * Retrieve the statistics object for a particular process, creating
          * if needed.
@@ -3169,6 +3364,15 @@
             return ps;
         }
 
+        public Pid getPidStatsLocked(int pid) {
+            Pid p = mPids.get(pid);
+            if (p == null) {
+                p = new Pid();
+                mPids.put(pid, p);
+            }
+            return p;
+        }
+
         /**
          * Retrieve the statistics object for a particular service, creating
          * if needed.
@@ -3261,18 +3465,36 @@
             return t;
         }
 
-        public void noteStartWakeLocked(String name, int type) {
+        public void noteStartWakeLocked(int pid, String name, int type) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
                 t.startRunningLocked(BatteryStatsImpl.this);
             }
+            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
+                Pid p = getPidStatsLocked(pid);
+                p.mWakeStart = SystemClock.elapsedRealtime();
+            }
         }
 
-        public void noteStopWakeLocked(String name, int type) {
+        public void noteStopWakeLocked(int pid, String name, int type) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
                 t.stopRunningLocked(BatteryStatsImpl.this);
             }
+            if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
+                Pid p = mPids.get(pid);
+                if (p != null) {
+                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
+                    p.mWakeStart = 0;
+                }
+            }
+        }
+
+        public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) {
+            Proc p = getProcessStatsLocked(proc);
+            if (p != null) {
+                p.addExcessiveWake(overTime, usedTime);
+            }
         }
         
         public void noteStartSensor(int sensor) {
@@ -3374,6 +3596,10 @@
         return mOnBattery;
     }
 
+    public boolean isScreenOn() {
+        return mScreenOn;
+    }
+
     void initTimes() {
         mBatteryRealtime = mTrackBatteryPastUptime = 0;
         mBatteryUptime = mTrackBatteryPastRealtime = 0;
@@ -3386,24 +3612,24 @@
     public void resetAllStatsLocked() {
         mStartCount = 0;
         initTimes();
-        mScreenOnTimer.reset(false);
+        mScreenOnTimer.reset(this, false);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i].reset(false);
+            mScreenBrightnessTimer[i].reset(this, false);
         }
         mInputEventCounter.reset(false);
-        mPhoneOnTimer.reset(false);
-        mAudioOnTimer.reset(false);
-        mVideoOnTimer.reset(false);
+        mPhoneOnTimer.reset(this, false);
+        mAudioOnTimer.reset(this, false);
+        mVideoOnTimer.reset(this, false);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i].reset(false);
+            mPhoneSignalStrengthsTimer[i].reset(this, false);
         }
-        mPhoneSignalScanningTimer.reset(false);
+        mPhoneSignalScanningTimer.reset(this, false);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i].reset(false);
+            mPhoneDataConnectionsTimer[i].reset(this, false);
         }
-        mWifiOnTimer.reset(false);
-        mWifiRunningTimer.reset(false);
-        mBluetoothOnTimer.reset(false);
+        mWifiOnTimer.reset(this, false);
+        mWifiRunningTimer.reset(this, false);
+        mBluetoothOnTimer.reset(this, false);
         
         for (int i=0; i<mUidStats.size(); i++) {
             if (mUidStats.valueAt(i).reset()) {
@@ -4085,6 +4311,7 @@
                 p.mUserTime = p.mLoadedUserTime = in.readLong();
                 p.mSystemTime = p.mLoadedSystemTime = in.readLong();
                 p.mStarts = p.mLoadedStarts = in.readInt();
+                p.readExcessiveWakeFromParcelLocked(in);
             }
 
             NP = in.readInt();
@@ -4273,6 +4500,7 @@
                     out.writeLong(ps.mUserTime);
                     out.writeLong(ps.mSystemTime);
                     out.writeInt(ps.mStarts);
+                    ps.writeExcessiveWakeToParcelLocked(out);
                 }
             }
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index c3c0db2..885ed6d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -163,7 +163,6 @@
             LayoutInflater inflater = LayoutInflater.from(context);
             mCustomNavView = (View) inflater.inflate(customNavId, null);
             mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
-            addView(mCustomNavView);
         }
 
         mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
@@ -553,7 +552,7 @@
             if (mSpinner != null) {
                 mSpinner.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
-                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
             }
             break;
         case ActionBar.NAVIGATION_MODE_CUSTOM:
@@ -563,8 +562,16 @@
                         MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
                 final int customNavWidth = lp.width >= 0 ?
                         Math.min(lp.width, availableWidth) : availableWidth;
-                final int customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
-                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+
+                // If the action bar is wrapping to its content height, don't allow a custom
+                // view to MATCH_PARENT.
+                int customNavHeightMode;
+                if (mContentHeight <= 0) {
+                    customNavHeightMode = MeasureSpec.AT_MOST;
+                } else {
+                    customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                            MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+                }
                 final int customNavHeight = lp.height >= 0 ?
                         Math.min(lp.height, height) : height;
                 mCustomNavView.measure(
@@ -576,7 +583,7 @@
             if (mTabLayout != null) {
                 mTabLayout.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
-                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
             }
             break;
         }
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e0608f9..67327b2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1594,6 +1594,26 @@
         <attr name="smoothScrollbar" format="boolean" />
         <!-- A reference to an XML description of the adapter to attach to the list. -->
         <attr name="adapter" format="reference" />
+        <!-- Defines the choice behavior for the view. By default, lists do not have
+             any choice behavior. By setting the choiceMode to singleChoice, the list
+             allows up to one item to be in a chosen state. By setting the choiceMode to
+             multipleChoice, the list allows any number of items to be chosen.
+             Finally, by setting the choiceMode to multipleChoiceModal the list allows
+             any number of items to be chosen in a special selection mode.
+             The application will supply a
+             {@link android.widget.AbsListView.MultiChoiceModeListener} using
+             {@link android.widget.AbsListView#setMultiChoiceModeListener} to control the
+             selection mode. This uses the {@link android.view.ActionMode} API. -->
+        <attr name="choiceMode">
+            <!-- Normal list that does not indicate choices. -->
+            <enum name="none" value="0" />
+            <!-- The list allows up to one choice. -->
+            <enum name="singleChoice" value="1" />
+            <!-- The list allows multiple choices. -->
+            <enum name="multipleChoice" value="2" />
+            <!-- The list allows multiple choices in a custom selection mode. -->
+            <enum name="multipleChoiceModal" value="3" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="AbsSpinner">
         <!-- Reference to an array resource that will populate the Spinner.  For static content,
@@ -1800,20 +1820,6 @@
         <!-- Height of the divider. Will use the intrinsic height of the divider if this
              is not specified. -->
         <attr name="dividerHeight" format="dimension" />
-        <!-- Defines the choice behavior for the ListView. By default, lists do not have
-             any choice behavior. By setting the choiceMode to singleChoice, the List
-             allows up to one item to be in a chosen state. By setting the choiceMode to
-             multipleChoice, the list allows any number of items to be chosen. -->
-        <attr name="choiceMode">
-            <!-- Normal list that does not indicate choices. -->
-            <enum name="none" value="0" />
-            <!-- The list allows up to one choice. -->
-            <enum name="singleChoice" value="1" />
-            <!-- The list allows multiple choices. -->
-            <enum name="multipleChoice" value="2" />
-            <!-- The list allows multiple choices in a custom selection mode. -->
-            <enum name="multipleChoiceModal" value="3" />
-        </attr>
         <!-- When set to false, the ListView will not draw the divider after each header view.
              The default value is true. -->
         <attr name="headerDividersEnabled" format="boolean" />
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2e1e8d8..be96935 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -128,6 +128,12 @@
     // Write the first chunk from the given ChunkInfo.
     void writeFirstChunk(ChunkInfo* info);
 
+    // Adjust other track media clock (presumably wall clock)
+    // based on audio track media clock with the drift time.
+    int64_t mDriftTimeUs;
+    void addDriftTimeUs(int64_t driftTimeUs);
+    int64_t getDriftTimeUs();
+
     void lock();
     void unlock();
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab1fa4f..43354c2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -86,10 +86,10 @@
 
     // Track authoring progress status
     // kKeyTrackTimeStatus is used to track progress in elapsed time
-    // kKeyTrackFrameStatus is used to track progress in authored frames
-    kKeyTrackFrameStatus  = 'tkfm',  // int32_t
     kKeyTrackTimeStatus   = 'tktm',  // int64_t
 
+    kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
+
 };
 
 enum {
diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
deleted file mode 100755
index e91bfb4..0000000
--- a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 24ef547..4a4d837 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -44,7 +44,6 @@
     private ScriptC_Threshold mScript;
     private ScriptC_Vertical_blur mScriptVBlur;
     private ScriptC_Horizontal_blur mScriptHBlur;
-    private ScriptC_Levels mScriptLevels;
     private int mRadius = 0;
     private SeekBar mRadiusSeekBar;
 
@@ -73,7 +72,8 @@
     @SuppressWarnings({"FieldCanBeLocal"})
     private Allocation mOutPixelsAllocation;
     @SuppressWarnings({"FieldCanBeLocal"})
-    private Allocation mScratchPixelsAllocation;
+    private Allocation mScratchPixelsAllocation1;
+    private Allocation mScratchPixelsAllocation2;
 
     private SurfaceView mSurfaceView;
     private ImageView mDisplayView;
@@ -261,29 +261,29 @@
             }
             else if(seekBar == mInBlackSeekBar) {
                 mInBlack = (float)progress;
-                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mOutBlackSeekBar) {
                 mOutBlack = (float)progress;
-                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mInWhiteSeekBar) {
                 mInWhite = (float)progress + 127.0f;
-                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mOutWhiteSeekBar) {
                 mOutWhite = (float)progress + 127.0f;
-                mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+                mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
             }
             else if(seekBar == mGammaSeekBar) {
                 mGamma = (float)progress/100.0f;
                 mGamma = Math.max(mGamma, 0.1f);
                 mGamma = 1.0f / mGamma;
-                mScriptLevels.invoke_setGamma(mGamma);
+                mScriptVBlur.invoke_setGamma(mGamma);
             }
             else if(seekBar == mSaturationSeekBar) {
                 mSaturation = (float)progress / 50.0f;
-                mScriptLevels.invoke_setSaturation(mSaturation);
+                mScriptVBlur.invoke_setSaturation(mSaturation);
             }
 
             long t = java.lang.System.currentTimeMillis();
@@ -373,28 +373,32 @@
 
         mInPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapIn);
         mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut);
-        mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch);
+
+        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
+        tb.add(android.renderscript.Dimension.X, mBitmapIn.getWidth());
+        tb.add(android.renderscript.Dimension.Y, mBitmapIn.getHeight());
+        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
+        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
 
         mScriptVBlur = new ScriptC_Vertical_blur(mRS, getResources(), R.raw.vertical_blur, false);
         mScriptHBlur = new ScriptC_Horizontal_blur(mRS, getResources(), R.raw.horizontal_blur, false);
-        mScriptLevels = new ScriptC_Levels(mRS, getResources(), R.raw.levels, false);
 
         mScript = new ScriptC_Threshold(mRS, getResources(), R.raw.threshold, false);
         mScript.set_width(mBitmapIn.getWidth());
         mScript.set_height(mBitmapIn.getHeight());
         mScript.set_radius(mRadius);
 
-        mScriptLevels.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
-        mScriptLevels.invoke_setGamma(mGamma);
-        mScriptLevels.invoke_setSaturation(mSaturation);
+        mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite);
+        mScriptVBlur.invoke_setGamma(mGamma);
+        mScriptVBlur.invoke_setSaturation(mSaturation);
 
         mScript.bind_InPixel(mInPixelsAllocation);
         mScript.bind_OutPixel(mOutPixelsAllocation);
-        mScript.bind_ScratchPixel(mScratchPixelsAllocation);
+        mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
+        mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
 
         mScript.set_vBlurScript(mScriptVBlur);
         mScript.set_hBlurScript(mScriptHBlur);
-        mScript.set_levelsScript(mScriptLevels);
     }
 
     private Bitmap loadBitmap(int resource) {
@@ -420,15 +424,15 @@
 
         long t = java.lang.System.currentTimeMillis();
 
-        mScript.invoke_filterBenchmark();
+        mScript.invoke_filter();
         mRS.finish();
 
         t = java.lang.System.currentTimeMillis() - t;
         android.util.Log.v("Img", "Renderscript frame time core ms " + t);
 
-        long javaTime = javaFilter();
-        mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
-        //mBenchmarkResult.setText("RS: " + t + " ms");
+        //long javaTime = javaFilter();
+        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
+        mBenchmarkResult.setText("RS: " + t + " ms");
 
         mRadius = oldRadius;
         mScript.set_radius(mRadius);
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
index 58c9acf..cfffac8 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
@@ -3,16 +3,16 @@
 #include "ip.rsh"
 
 void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    uchar4 *output = (uchar4 *)v_out;
+    float4 *output = (float4 *)v_out;
     const FilterStruct *fs = (const FilterStruct *)usrData;
-    const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, 0, y);
+    const float4 *input = (const float4 *)rsGetElementAt(fs->ain, 0, y);
 
     float3 blurredPixel = 0;
     const float *gPtr = fs->gaussian;
     if ((x > fs->radius) && (x < (fs->width - fs->radius))) {
-        const uchar4 *i = input + (x - fs->radius);
+        const float4 *i = input + (x - fs->radius);
         for(int r = -fs->radius; r <= fs->radius; r ++) {
-            blurredPixel += convert_float3(i->xyz) * gPtr[0];
+            blurredPixel += i->xyz * gPtr[0];
             gPtr++;
             i++;
         }
@@ -20,11 +20,11 @@
         for(int r = -fs->radius; r <= fs->radius; r ++) {
             // Stepping left and right away from the pixel
             int validW = rsClamp(x + r, (uint)0, (uint)(fs->width - 1));
-            blurredPixel += convert_float3(input[validW].xyz) * gPtr[0];
+            blurredPixel += input[validW].xyz * gPtr[0];
             gPtr++;
         }
     }
 
-    output->xyz = convert_uchar3(blurredPixel);
+    output->xyz = blurredPixel;
 }
 
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
deleted file mode 100644
index bb8a6fc..0000000
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/levels.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-#pragma version(1)
-
-#include "ip.rsh"
-
-
-static float inBlack;
-static float outBlack;
-static float inWhite;
-static float outWhite;
-static float3 gamma;
-static float saturation;
-
-static float inWMinInB;
-static float outWMinOutB;
-static float overInWMinInB;
-static rs_matrix3x3 colorMat;
-
-//#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript)
-#pragma rs export_func(setLevels, setSaturation, setGamma);
-
-void setLevels(float iBlk, float oBlk, float iWht, float oWht) {
-    inBlack = iBlk;
-    outBlack = oBlk;
-    inWhite = iWht;
-    outWhite = oWht;
-
-    inWMinInB = inWhite - inBlack;
-    outWMinOutB = outWhite - outBlack;
-    overInWMinInB = 1.f / inWMinInB;
-}
-
-void setSaturation(float sat) {
-    saturation = sat;
-
-    // Saturation
-    // Linear weights
-    //float rWeight = 0.3086f;
-    //float gWeight = 0.6094f;
-    //float bWeight = 0.0820f;
-
-    // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
-    float rWeight = 0.299f;
-    float gWeight = 0.587f;
-    float bWeight = 0.114f;
-
-    float oneMinusS = 1.0f - saturation;
-    rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
-    rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
-    rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
-    rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
-    rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
-    rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
-    rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
-    rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
-    rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
-}
-
-void setGamma(float g) {
-    gamma = (float3)g;
-}
-
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    const uchar4 *input = v_in;
-    uchar4 *output = v_out;
-
-    float3 currentPixel = 0;
-
-    //currentPixel.xyz = convert_float3(input.xyz);
-    currentPixel.x = (float)(input->x);
-    currentPixel.y = (float)(input->y);
-    currentPixel.z = (float)(input->z);
-
-    float3 temp = rsMatrixMultiply(&colorMat, currentPixel);
-    temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
-    if (gamma.x != 1.0f)
-        temp = pow(temp, (float3)gamma);
-    currentPixel = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
-
-    //output.xyz = convert_uchar3(currentPixel.xyz);
-    output->x = (uint8_t)currentPixel.x;
-    output->y = (uint8_t)currentPixel.y;
-    output->z = (uint8_t)currentPixel.z;
-    output->w = input->w;
-}
-
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
index 8e198c7..33945a5 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -8,14 +8,14 @@
 
 uchar4 * InPixel;
 uchar4 * OutPixel;
-uchar4 * ScratchPixel;
+float4 * ScratchPixel1;
+float4 * ScratchPixel2;
 
-#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, vBlurScript, hBlurScript, levelsScript)
-#pragma rs export_func(filter, filterBenchmark);
+#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel1, ScratchPixel2, vBlurScript, hBlurScript)
+#pragma rs export_func(filter);
 
 rs_script vBlurScript;
 rs_script hBlurScript;
-rs_script levelsScript;
 
 const int CMD_FINISHED = 1;
 
@@ -64,7 +64,21 @@
 }
 
 
-static void blur() {
+static void copyInput() {
+    RS_DEBUG_MARKER;
+    rs_allocation ain = rsGetAllocation(InPixel);
+    uint32_t dimx = rsAllocationGetDimX(ain);
+    uint32_t dimy = rsAllocationGetDimY(ain);
+    for(uint32_t y = 0; y < dimy; y++) {
+        for(uint32_t x = 0; x < dimx; x++) {
+            ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]);
+        }
+    }
+    RS_DEBUG_MARKER;
+}
+
+void filter() {
+    copyInput();
     computeGaussianWeights();
 
     FilterStruct fs;
@@ -73,28 +87,11 @@
     fs.height = height;
     fs.radius = radius;
 
-    fs.ain = rsGetAllocation(InPixel);
-    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel), &fs);
+    fs.ain = rsGetAllocation(ScratchPixel1);
+    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel2), &fs);
 
-    fs.ain = rsGetAllocation(ScratchPixel);
+    fs.ain = rsGetAllocation(ScratchPixel2);
     rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs);
-}
-
-void filter() {
-    //RS_DEBUG(radius);
-
-    if(radius > 0) {
-        blur();
-        rsForEach(levelsScript, rsGetAllocation(OutPixel), rsGetAllocation(OutPixel), 0);
-    } else {
-        rsForEach(levelsScript, rsGetAllocation(InPixel), rsGetAllocation(OutPixel), 0);
-    }
-
-    rsSendToClientBlocking(CMD_FINISHED);
-}
-
-void filterBenchmark() {
-    blur();
     rsSendToClientBlocking(CMD_FINISHED);
 }
 
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index 3c69289..d901d2a 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -2,28 +2,91 @@
 
 #include "ip.rsh"
 
+static float inBlack;
+static float outBlack;
+static float inWhite;
+static float outWhite;
+static float3 gamma;
+static float saturation;
+
+static float inWMinInB;
+static float outWMinOutB;
+static float overInWMinInB;
+static rs_matrix3x3 colorMat;
+
+#pragma rs export_func(setLevels, setSaturation, setGamma);
+
+void setLevels(float iBlk, float oBlk, float iWht, float oWht) {
+    inBlack = iBlk;
+    outBlack = oBlk;
+    inWhite = iWht;
+    outWhite = oWht;
+
+    inWMinInB = inWhite - inBlack;
+    outWMinOutB = outWhite - outBlack;
+    overInWMinInB = 1.f / inWMinInB;
+}
+
+void setSaturation(float sat) {
+    saturation = sat;
+
+    // Saturation
+    // Linear weights
+    //float rWeight = 0.3086f;
+    //float gWeight = 0.6094f;
+    //float bWeight = 0.0820f;
+
+    // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
+    float rWeight = 0.299f;
+    float gWeight = 0.587f;
+    float bWeight = 0.114f;
+
+    float oneMinusS = 1.0f - saturation;
+    rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
+    rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
+    rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
+}
+
+void setGamma(float g) {
+    gamma = (float3)g;
+}
+
 void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
     uchar4 *output = (uchar4 *)v_out;
     const FilterStruct *fs = (const FilterStruct *)usrData;
-    const uchar4 *input = (const uchar4 *)rsGetElementAt(fs->ain, x, 0);
+    const float4 *input = (const float4 *)rsGetElementAt(fs->ain, x, 0);
 
     float3 blurredPixel = 0;
     const float *gPtr = fs->gaussian;
     if ((y > fs->radius) && (y < (fs->height - fs->radius))) {
-        const uchar4 *i = input + ((y - fs->radius) * fs->width);
+        const float4 *i = input + ((y - fs->radius) * fs->width);
         for(int r = -fs->radius; r <= fs->radius; r ++) {
-            blurredPixel += convert_float3(i->xyz) * gPtr[0];
+            blurredPixel += i->xyz * gPtr[0];
             gPtr++;
             i += fs->width;
         }
     } else {
         for(int r = -fs->radius; r <= fs->radius; r ++) {
             int validH = rsClamp(y + r, (uint)0, (uint)(fs->height - 1));
-            const uchar4 *i = input + validH * fs->width;
-            blurredPixel += convert_float3(i->xyz) * gPtr[0];
+            const float4 *i = input + validH * fs->width;
+            blurredPixel += i->xyz * gPtr[0];
             gPtr++;
         }
     }
-    output->xyz = convert_uchar3(blurredPixel);
+
+    float3 temp = rsMatrixMultiply(&colorMat, blurredPixel);
+    temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB;
+    if (gamma.x != 1.0f)
+        temp = pow(temp, (float3)gamma);
+    temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f);
+
+    output->xyz = convert_uchar3(temp);
+    //output->w = input->w;
 }
 
diff --git a/libs/rs/java/ModelViewer/res/drawable/robot.png b/libs/rs/java/ModelViewer/res/drawable/robot.png
index 7c85e56..f7353fd 100644
--- a/libs/rs/java/ModelViewer/res/drawable/robot.png
+++ b/libs/rs/java/ModelViewer/res/drawable/robot.png
Binary files differ
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index ac32810..5a2b6ba 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -239,7 +239,7 @@
     return a->getType()->getDimFaces();
 }
 
-const void * SC_getElementAtX(RsAllocation va, uint32_t x)
+static const void * SC_getElementAtX(RsAllocation va, uint32_t x)
 {
     const Allocation *a = static_cast<const Allocation *>(va);
     const Type *t = a->getType();
@@ -247,7 +247,7 @@
     return &p[t->getElementSizeBytes() * x];
 }
 
-const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
+static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
 {
     const Allocation *a = static_cast<const Allocation *>(va);
     const Type *t = a->getType();
@@ -255,7 +255,7 @@
     return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
 }
 
-const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
+static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
 {
     const Allocation *a = static_cast<const Allocation *>(va);
     const Type *t = a->getType();
@@ -263,6 +263,20 @@
     return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
 }
 
+static void SC_setObject(void **vdst, void * vsrc) {
+    static_cast<ObjectBase *>(vsrc)->incSysRef();
+    static_cast<ObjectBase *>(vdst[0])->decSysRef();
+    *vdst = vsrc;
+}
+static void SC_clearObject(void **vdst) {
+    static_cast<ObjectBase *>(vdst[0])->decSysRef();
+    *vdst = NULL;
+}
+static bool SC_isObject(RsAllocation vsrc) {
+    return vsrc != NULL;
+}
+
+
 
 static void SC_debugF(const char *s, float f) {
     LOGE("%s %f, 0x%08x", s, f, *((int *) (&f)));
@@ -405,6 +419,11 @@
     { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
     { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
 
+    { "_Z11rsSetObjectP13rs_allocation13rs_allocation", (void *)&SC_setObject },
+    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject },
+    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject },
+
+
     // Debug
     { "_Z7rsDebugPKcf", (void *)&SC_debugF },
     { "_Z7rsDebugPKcff", (void *)&SC_debugFv2 },
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index bb4aafb..c842ef1 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -29,6 +29,77 @@
 #include "rs_cl.rsh"
 #include "rs_core.rsh"
 
+extern void __attribute__((overloadable))
+    rsSetObject(rs_element *dst, rs_element src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_type *dst, rs_type src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_allocation *dst, rs_allocation src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_sampler *dst, rs_sampler src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_script *dst, rs_script src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_mesh *dst, rs_mesh src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_program_fragment *dst, rs_program_fragment src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_program_vertex *dst, rs_program_vertex src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_program_raster *dst, rs_program_raster src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_program_store *dst, rs_program_store src);
+extern void __attribute__((overloadable))
+    rsSetObject(rs_font *dst, rs_font src);
+
+extern void __attribute__((overloadable))
+    rsClearObject(rs_element *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_type *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_allocation *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_sampler *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_script *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_mesh *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_program_fragment *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_program_vertex *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_program_raster *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_program_store *dst);
+extern void __attribute__((overloadable))
+    rsClearObject(rs_font *dst);
+
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_element);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_type);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_allocation);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_sampler);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_script);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_mesh);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_program_fragment);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_program_vertex);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_program_raster);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_program_store);
+extern bool __attribute__((overloadable))
+    rsIsObject(rs_font);
+
+
+
 // Allocations
 
 // Return the rs_allocation associated with a bound data
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index fd9ac16..dd42972 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -14,17 +14,18 @@
 typedef uint32_t uint;
 typedef uint64_t ulong;
 
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_element;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_type;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_allocation;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_sampler;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_script;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_mesh;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_fragment;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_vertex;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_raster;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_program_store;
-typedef struct { int* p; } __attribute__((packed, aligned(4))) rs_font;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_element;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_type;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_allocation;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sampler;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_script;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_fragment;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_vertex;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_raster;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_store;
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_font;
+
 
 typedef float float2 __attribute__((ext_vector_type(2)));
 typedef float float3 __attribute__((ext_vector_type(3)));
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index daa20a8..a616aae 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -731,7 +731,9 @@
     encMeta->setInt32(kKeyChannelCount, mAudioChannels);
     encMeta->setInt32(kKeySampleRate, mSampleRate);
     encMeta->setInt32(kKeyBitRate, mAudioBitRate);
-    encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+    if (mAudioTimeScale > 0) {
+        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+    }
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
@@ -1032,7 +1034,9 @@
     enc_meta->setInt32(kKeyStride, stride);
     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
     enc_meta->setInt32(kKeyColorFormat, colorFormat);
-    enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+    if (mVideoTimeScale > 0) {
+        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+    }
     if (mVideoEncoderProfile != -1) {
         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
     }
@@ -1115,7 +1119,9 @@
     meta->setInt32(kKeyFileType, mOutputFormat);
     meta->setInt32(kKeyBitRate, totalBitRate);
     meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
-    meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+    if (mMovieTimeScale > 0) {
+        meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+    }
     if (mTrackEveryTimeDurationUs > 0) {
         meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
@@ -1191,9 +1197,9 @@
     mIFramesIntervalSec = 1;
     mAudioSourceNode = 0;
     mUse64BitFileOffset = false;
-    mMovieTimeScale  = 1000;
-    mAudioTimeScale  = 1000;
-    mVideoTimeScale  = 1000;
+    mMovieTimeScale  = -1;
+    mAudioTimeScale  = -1;
+    mVideoTimeScale  = -1;
     mCameraId        = 0;
     mVideoEncoderProfile = -1;
     mVideoEncoderLevel   = -1;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 1460f37..f52ec1a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,6 +72,11 @@
     bool mIsAudio;
     bool mIsMPEG4;
     int64_t mTrackDurationUs;
+
+    // For realtime applications, we need to adjust the media clock
+    // for video track based on the audio media clock
+    bool mIsRealTimeRecording;
+    int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMaxWriteTimeUs;
     int32_t mTimeScale;
@@ -163,6 +168,12 @@
 
     void getCodecSpecificDataFromInputFormatIfPossible();
 
+    // Determine the track time scale
+    // If it is an audio track, try to use the sampling rate as
+    // the time scale; however, if user chooses the overwrite
+    // value, the user-supplied time scale will be used.
+    void setTimeScale();
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
@@ -429,7 +440,7 @@
     mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
     mMoovBoxBufferOffset = 0;
     CHECK(mMoovBoxBuffer != NULL);
-    int32_t duration = (maxDurationUs * mTimeScale) / 1E6;
+    int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6;
 
     beginBox("moov");
 
@@ -744,10 +755,6 @@
       mReachedEOS(false) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
-    if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) {
-        mTimeScale = 1000;
-    }
-
     const char *mime;
     mMeta->findCString(kKeyMIMEType, &mime);
     mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
@@ -755,6 +762,28 @@
     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
 
+    setTimeScale();
+}
+
+void MPEG4Writer::Track::setTimeScale() {
+    LOGV("setTimeScale");
+    // Default time scale
+    mTimeScale = 90000;
+
+    if (mIsAudio) {
+        // Use the sampling rate as the default time scale for audio track.
+        int32_t sampleRate;
+        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
+        CHECK(success);
+        mTimeScale = sampleRate;
+    }
+
+    // If someone would like to overwrite the timescale, use user-supplied value.
+    int32_t timeScale;
+    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
+        mTimeScale = timeScale;
+    }
+
     CHECK(mTimeScale > 0);
 }
 
@@ -940,6 +969,7 @@
 
     mDone = false;
     mIsFirstChunk = true;
+    mDriftTimeUs = 0;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         ChunkInfo info;
@@ -967,6 +997,14 @@
         startTimeUs = 0;
     }
 
+    mIsRealTimeRecording = true;
+    {
+        int32_t isNotRealTime;
+        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
+            mIsRealTimeRecording = (isNotRealTime == 0);
+        }
+    }
+
     initTrackingProgressStatus(params);
 
     sp<MetaData> meta = new MetaData;
@@ -1322,10 +1360,16 @@
     int32_t nZeroLengthFrames = 0;
     int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
     int64_t lastDurationUs = 0;   // Between the previous two samples in ms
+    int64_t currDurationTicks = 0;  // Timescale based ticks
+    int64_t lastDurationTicks = 0;  // Timescale based ticks
     int32_t sampleCount = 1;      // Sample count in the current stts table entry
     uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs;
+
+    int64_t wallClockTimeUs = 0;
+    int64_t lastWallClockTimeUs = 0;
+
     sp<MetaData> meta_data;
     bool collectStats = collectStatisticalData();
 
@@ -1429,6 +1473,33 @@
         }
 
         timestampUs -= previousPausedDurationUs;
+        if (mIsRealTimeRecording && !mIsAudio) {
+            // The minor adjustment on the timestamp is heuristic/experimental
+            // We are adjusting the timestamp to reduce the fluctuation of the duration
+            // of neighboring samples. This in turn helps reduce the track header size,
+            // especially, the number of entries in the "stts" box.
+            if (mNumSamples > 1) {
+                int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs;
+                int64_t diffUs = (durationUs > lastDurationUs)
+                            ? durationUs - lastDurationUs
+                            : lastDurationUs - durationUs;
+                if (diffUs <= 5000) {  // XXX: Magic number 5ms
+                    timestampUs = lastTimestampUs + lastDurationUs;
+                } else {
+                    timestampUs += mOwner->getDriftTimeUs();
+                }
+            }
+        }
+        CHECK(timestampUs >= 0);
+        if (mNumSamples > 1) {
+            if (timestampUs <= lastTimestampUs) {
+                LOGW("Drop a frame, since it arrives too late!");
+                copy->release();
+                copy = NULL;
+                continue;
+            }
+        }
+
         LOGV("time stamp: %lld and previous paused duration %lld",
                 timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
@@ -1438,7 +1509,16 @@
         mSampleSizes.push_back(sampleSize);
         ++mNumSamples;
         if (mNumSamples > 2) {
-            if (lastDurationUs != timestampUs - lastTimestampUs) {
+            // We need to use the time scale based ticks, rather than the
+            // timestamp itself to determine whether we have to use a new
+            // stts entry, since we may have rounding errors.
+            // The calculation is intended to reduce the accumulated
+            // rounding errors.
+            currDurationTicks =
+                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
+                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+
+            if (currDurationTicks != lastDurationTicks) {
                 SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
                 mSttsTableEntries.push_back(sttsEntry);
                 sampleCount = 1;
@@ -1453,7 +1533,16 @@
             previousSampleSize = sampleSize;
         }
         lastDurationUs = timestampUs - lastTimestampUs;
+        lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
+        if (mIsRealTimeRecording && mIsAudio) {
+            wallClockTimeUs = systemTime() / 1000;
+            int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs;
+            if (mNumSamples > 2) {
+                mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs);
+            }
+            lastWallClockTimeUs = wallClockTimeUs;
+        }
 
         if (isSync != 0) {
             mStssTableEntries.push_back(mNumSamples);
@@ -1679,6 +1768,18 @@
     }
 }
 
+void MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) {
+    LOGV("addDriftTimeUs: %lld us", driftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    mDriftTimeUs += driftTimeUs;
+}
+
+int64_t MPEG4Writer::getDriftTimeUs() {
+    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    return mDriftTimeUs;
+}
+
 void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
     LOGV("bufferChunk");
 
@@ -1709,7 +1810,6 @@
     LOGV("%s track time scale: %d",
         mIsAudio? "Audio": "Video", mTimeScale);
 
-
     time_t now = time(NULL);
     int32_t mvhdTimeScale = mOwner->getTimeScale();
     int64_t trakDurationUs = getDurationUs();
@@ -2024,10 +2124,18 @@
           mOwner->beginBox("stts");
             mOwner->writeInt32(0);  // version=0, flags=0
             mOwner->writeInt32(mSttsTableEntries.size());
+            int64_t prevTimestampUs = 0;
             for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
                  it != mSttsTableEntries.end(); ++it) {
                 mOwner->writeInt32(it->sampleCount);
-                int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6;
+
+                // Make sure that we are calculating the sample duration the exactly
+                // same way as we made decision on how to create stts entries.
+                int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
+                int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
+                               (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+                prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
+
                 mOwner->writeInt32(dur);
             }
           mOwner->endBox();  // stts
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
index 0aaa370..e7b0509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
@@ -185,11 +185,11 @@
         final Segment newSegment = new Segment(n, icon, n.notification.tickerText);
 
         // If there's already a notification schedule for this package and id, remove it.
-        for (int i=0; i<initialCount; i++) {
+        for (int i=0; i<mSegments.size(); i++) {
             Segment seg = mSegments.get(i);
             if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
                 // just update that one to use this new data instead
-                mSegments.remove(i);
+                mSegments.remove(i--); // restart iteration here
             }
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a410fa4..6be5546 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -643,17 +643,16 @@
             
             boolean playSoundEffect = false;
             final PanelFeatureState st = getPanelState(featureId, true);
-            if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null) {
-                if (mActionBar.isOverflowReserved()) {
-                    if (!mActionBar.isOverflowMenuShowing()) {
-                        final Callback cb = getCallback();
-                        if (cb != null &&
-                                cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) {
-                            playSoundEffect = mActionBar.showOverflowMenu();
-                        }
-                    } else {
-                        playSoundEffect = mActionBar.hideOverflowMenu();
+            if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
+                    mActionBar.isOverflowReserved()) {
+                if (!mActionBar.isOverflowMenuShowing()) {
+                    final Callback cb = getCallback();
+                    if (cb != null &&
+                            cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) {
+                        playSoundEffect = mActionBar.showOverflowMenu();
                     }
+                } else {
+                    playSoundEffect = mActionBar.hideOverflowMenu();
                 }
             } else {
                 if (st.isOpen || st.isHandled) {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2fb481c..4ee89cc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -151,6 +151,7 @@
     static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
 
     private final int MY_UID;
+    private final int MY_PID;
 
     private boolean mDoneBooting = false;
     private boolean mBootCompleted = false;
@@ -309,7 +310,7 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
-                            MY_UID, mTag);
+                            MY_UID, MY_PID, mTag);
                     mHeld = true;
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -434,11 +435,11 @@
         }
     }
 
-    PowerManagerService()
-    {
+    PowerManagerService() {
         // Hack to get our uid...  should have a func for this.
         long token = Binder.clearCallingIdentity();
-        MY_UID = Binder.getCallingUid();
+        MY_UID = Process.myUid();
+        MY_PID = Process.myPid();
         Binder.restoreCallingIdentity(token);
 
         // XXX remove this when the kernel doesn't timeout wake locks
@@ -573,13 +574,13 @@
 
     private class WakeLock implements IBinder.DeathRecipient
     {
-        WakeLock(int f, IBinder b, String t, int u) {
+        WakeLock(int f, IBinder b, String t, int u, int p) {
             super();
             flags = f;
             binder = b;
             tag = t;
             uid = u == MY_UID ? Process.SYSTEM_UID : u;
-            pid = Binder.getCallingPid();
+            pid = p;
             if (u != MY_UID || (
                     !"KEEP_SCREEN_ON_FLAG".equals(tag)
                     && !"KeyInputQueue".equals(tag))) {
@@ -631,21 +632,23 @@
 
     public void acquireWakeLock(int flags, IBinder lock, String tag) {
         int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
         if (uid != Process.myUid()) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
         }
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mLocks) {
-                acquireWakeLockLocked(flags, lock, uid, tag);
+                acquireWakeLockLocked(flags, lock, uid, pid, tag);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
+    public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) {
         int acquireUid = -1;
+        int acquirePid = -1;
         String acquireName = null;
         int acquireType = -1;
 
@@ -657,7 +660,7 @@
         WakeLock wl;
         boolean newlock;
         if (index < 0) {
-            wl = new WakeLock(flags, lock, tag, uid);
+            wl = new WakeLock(flags, lock, tag, uid, pid);
             switch (wl.flags & LOCK_MASK)
             {
                 case PowerManager.FULL_WAKE_LOCK:
@@ -730,13 +733,14 @@
         }
         if (newlock) {
             acquireUid = wl.uid;
+            acquirePid = wl.pid;
             acquireName = wl.tag;
             acquireType = wl.monitorType;
         }
 
         if (acquireType >= 0) {
             try {
-                mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
+                mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType);
             } catch (RemoteException e) {
                 // Ignore
             }
@@ -756,6 +760,7 @@
 
     private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
         int releaseUid;
+        int releasePid;
         String releaseName;
         int releaseType;
 
@@ -800,13 +805,14 @@
         // Unlink the lock from the binder.
         wl.binder.unlinkToDeath(wl, 0);
         releaseUid = wl.uid;
+        releasePid = wl.pid;
         releaseName = wl.tag;
         releaseType = wl.monitorType;
 
         if (releaseType >= 0) {
             long origId = Binder.clearCallingIdentity();
             try {
-                mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
+                mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType);
             } catch (RemoteException e) {
                 // Ignore
             } finally {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3f5888b..57f93c4 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8085,12 +8085,12 @@
                     if (oldHold != newHold) {
                         try {
                             if (oldHold != null) {
-                                mBatteryStats.noteStopWakelock(oldHold.mUid,
+                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
                                         "window",
                                         BatteryStats.WAKE_TYPE_WINDOW);
                             }
                             if (newHold != null) {
-                                mBatteryStats.noteStartWakelock(newHold.mUid,
+                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
                                         "window",
                                         BatteryStats.WAKE_TYPE_WINDOW);
                             }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index df930ad..55ec6aa 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import com.android.internal.R;
-import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
@@ -39,7 +38,6 @@
 import android.app.ApplicationErrorReport;
 import android.app.Dialog;
 import android.app.IActivityController;
-import android.app.IActivityManager;
 import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
@@ -50,7 +48,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.ResultInfo;
 import android.app.Service;
 import android.app.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
@@ -95,7 +92,6 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -110,6 +106,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.SparseArray;
+import android.util.TimeUtils;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -200,6 +197,9 @@
     // The minimum amount of time between successive GC requests for a process.
     static final int GC_MIN_INTERVAL = 60*1000;
 
+    // The rate at which we check for apps using excessive wake locks -- 15 mins.
+    static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000;
+
     // How long we allow a receiver to run before giving up on it.
     static final int BROADCAST_TIMEOUT = 10*1000;
 
@@ -771,6 +771,11 @@
     boolean mDidAppSwitch;
     
     /**
+     * Last time (in realtime) at which we checked for wake lock usage.
+     */
+    long mLastWakeLockCheckTime;
+
+    /**
      * Set while we are wanting to sleep, to prevent any
      * activities from being started/resumed.
      */
@@ -915,6 +920,7 @@
     static final int POST_HEAVY_NOTIFICATION_MSG = 24;
     static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
     static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
+    static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
 
     AlertDialog mUidAlert;
 
@@ -1174,6 +1180,16 @@
                 } catch (RemoteException e) {
                 }
             } break;
+            case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    checkExcessiveWakeLocksLocked(true);
+                    removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+                    if (mSleeping) {
+                        Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+                        sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
+                    }
+                }
+            } break;
             }
         }
     };
@@ -2560,6 +2576,11 @@
 
         mProcDeaths[0]++;
         
+        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        synchronized (stats) {
+            stats.noteProcessDiedLocked(app.info.uid, pid);
+        }
+
         // Clean up already done if the process has been re-started.
         if (app.pid == pid && app.thread != null &&
                 app.thread.asBinder() == thread.asBinder()) {
@@ -3577,6 +3598,9 @@
             }
             
             if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+                // Start looking for apps that are abusing wake locks.
+                Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+                mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
                 broadcastIntentLocked(null, null,
@@ -5382,6 +5406,12 @@
             } else {
                 Slog.w(TAG, "goingToSleep with no resumed activity!");
             }
+
+            // Initialize the wake times of all processes.
+            checkExcessiveWakeLocksLocked(false);
+            mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+            Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+            mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
         }
     }
 
@@ -5431,6 +5461,7 @@
             mWindowManager.setEventDispatching(true);
             mSleeping = false;
             mMainStack.resumeTopActivityLocked(null);
+            mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
         }
     }
 
@@ -11287,6 +11318,62 @@
         }
     }
 
+    final void checkExcessiveWakeLocksLocked(boolean doKills) {
+        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        if (mLastWakeLockCheckTime == 0) {
+            doKills = false;
+        }
+        if (stats.isScreenOn()) {
+            doKills = false;
+        }
+        final long curRealtime = SystemClock.elapsedRealtime();
+        final long timeSince = curRealtime - mLastWakeLockCheckTime;
+        mLastWakeLockCheckTime = curRealtime;
+        if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) {
+            doKills = false;
+        }
+        int i = mLruProcesses.size();
+        while (i > 0) {
+            i--;
+            ProcessRecord app = mLruProcesses.get(i);
+            if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+                long wtime;
+                synchronized (stats) {
+                    wtime = stats.getProcessWakeTime(app.info.uid,
+                            app.pid, curRealtime);
+                }
+                long timeUsed = wtime - app.lastWakeTime;
+                if (false) {
+                    StringBuilder sb = new StringBuilder(128);
+                    sb.append("Wake for ");
+                    app.toShortString(sb);
+                    sb.append(": over ");
+                    TimeUtils.formatDuration(timeSince, sb);
+                    sb.append(" used ");
+                    TimeUtils.formatDuration(timeUsed, sb);
+                    sb.append(" (");
+                    sb.append((timeUsed*100)/timeSince);
+                    sb.append("%)");
+                    Slog.i(TAG, sb.toString());
+                }
+                // If a process has held a wake lock for more
+                // than 50% of the time during this period,
+                // that sounds pad.  Kill!
+                if (doKills && timeSince > 0
+                        && ((timeUsed*100)/timeSince) >= 50) {
+                    Slog.i(TAG, "Excessive wake lock in " + app.processName
+                            + " (pid " + app.pid + "): held " + timeUsed
+                            + " during " + timeSince);
+                    EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                            app.processName, app.setAdj, "excessive wake lock");
+                    Process.killProcessQuiet(app.pid);
+                } else {
+                    app.lastWakeTime = wtime;
+                }
+            }
+        }
+    }
+
     private final boolean updateOomAdjLocked(
         ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
         app.hiddenAdj = hiddenAdj;
@@ -11309,6 +11396,12 @@
                     // Likewise do a gc when an app is moving in to the
                     // background (such as a service stopping).
                     scheduleAppGcLocked(app);
+                    // And note its current wake lock time.
+                    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+                    synchronized (stats) {
+                        app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
+                                app.pid, SystemClock.elapsedRealtime());
+                    }
                 }
                 app.setRawAdj = app.curRawAdj;
             }
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 37da6f7..7314e04 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -93,31 +93,31 @@
         return data;
     }
     
-    public void noteStartWakelock(int uid, String name, int type) {
+    public void noteStartWakelock(int uid, int pid, String name, int type) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type);
+            mStats.noteStartWakeLocked(uid, pid, name, type);
         }
     }
 
-    public void noteStopWakelock(int uid, String name, int type) {
+    public void noteStopWakelock(int uid, int pid, String name, int type) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type);
+            mStats.noteStopWakeLocked(uid, pid, name, type);
         }
     }
 
     public void noteStartSensor(int uid, int sensor) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.getUidStatsLocked(uid).noteStartSensor(sensor);
+            mStats.noteStartSensorLocked(uid, sensor);
         }
     }
     
     public void noteStopSensor(int uid, int sensor) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.getUidStatsLocked(uid).noteStopSensor(sensor);
+            mStats.noteStopSensorLocked(uid, sensor);
         }
     }
     
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 18b1acb..6d1fbab 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.Watchdog;
 
 import android.app.ActivityManager;
 import android.app.Dialog;
@@ -27,8 +26,9 @@
 import android.content.pm.ApplicationInfo;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.PrintWriterPrinter;
+import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -74,6 +74,7 @@
     Bundle instrumentationArguments;// as given to us
     ComponentName instrumentationResultClass;// copy of instrumentationClass
     BroadcastRecord curReceiver;// receiver currently running in the app
+    long lastWakeTime;          // How long proc held wake lock at last check
     long lastRequestedGc;       // When we last asked the app to do a gc
     long lastLowMemory;         // When we last told the app that memory is low
     boolean reportLowMemory;    // Set to true when waiting to report low mem
@@ -128,6 +129,8 @@
     ComponentName errorReportReceiver;
 
     void dump(PrintWriter pw, String prefix) {
+        final long now = SystemClock.uptimeMillis();
+
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
         }
@@ -157,8 +160,9 @@
                 pw.print(" curReceiver="); pw.println(curReceiver);
         pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
                 pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
-        pw.print(prefix); pw.print("lastActivityTime="); pw.print(lastActivityTime);
-                pw.print(" lruWeight="); pw.println(lruWeight);
+        pw.print(prefix); pw.print("lastActivityTime=");
+                TimeUtils.formatDuration(lastActivityTime, now, pw);
+                pw.print(" lruWeight="); pw.print(lruWeight);
                 pw.print(" hidden="); pw.print(hidden);
                 pw.print(" empty="); pw.println(empty);
         pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
@@ -177,6 +181,12 @@
                 pw.print(" persistentActivities="); pw.println(persistentActivities);
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.println(lruSeq);
+        pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
+                pw.print(" lastRequestedGc=");
+                TimeUtils.formatDuration(lastRequestedGc, now, pw);
+                pw.print(" lastLowMemory=");
+                TimeUtils.formatDuration(lastLowMemory, now, pw);
+                pw.print(" reportLowMemory="); pw.println(reportLowMemory);
         if (killedBackground) {
             pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
         }
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 75365ad..ab5a78d 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -31,6 +31,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -117,7 +118,10 @@
             StartItem si = list.get(i);
             pw.print(prefix); pw.print("#"); pw.print(i);
                     pw.print(" id="); pw.print(si.id);
-                    if (now != 0) pw.print(" dur="); pw.print(now-si.deliveredTime);
+                    if (now != 0) {
+                        pw.print(" dur=");
+                        TimeUtils.formatDuration(si.deliveredTime, now, pw);
+                    }
                     if (si.deliveryCount != 0) {
                         pw.print(" dc="); pw.print(si.deliveryCount);
                     }
@@ -140,18 +144,26 @@
             pw.print(prefix); pw.print("permission="); pw.println(permission);
         }
         long now = SystemClock.uptimeMillis();
-        pw.print(prefix); pw.print("baseDir="); pw.print(baseDir);
-                if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir);
-                pw.print(" dataDir="); pw.println(dataDir);
+        long nowReal = SystemClock.elapsedRealtime();
+        pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
+        if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+        pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
         pw.print(prefix); pw.print("app="); pw.println(app);
         if (isForeground || foregroundId != 0) {
             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
                     pw.print(" foregroundId="); pw.print(foregroundId);
                     pw.print(" foregroundNoti="); pw.println(foregroundNoti);
         }
-        pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now);
-                pw.print(" executingStart="); pw.print(executingStart-now);
-                pw.print(" restartTime="); pw.println(restartTime);
+        pw.print(prefix); pw.print("createTime=");
+                TimeUtils.formatDuration(createTime, nowReal, pw);
+                pw.print(" lastActivity=");
+                TimeUtils.formatDuration(lastActivity, now, pw);
+                pw.println("");
+        pw.print(prefix); pw.print(" executingStart=");
+                TimeUtils.formatDuration(executingStart, now, pw);
+                pw.print(" restartTime=");
+                TimeUtils.formatDuration(restartTime, now, pw);
+                pw.println("");
         if (startRequested || lastStartId != 0) {
             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
@@ -162,13 +174,15 @@
                 || restartDelay != 0 || nextRestartTime != 0) {
             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
                     pw.print(" restartCount="); pw.print(restartCount);
-                    pw.print(" restartDelay="); pw.print(restartDelay-now);
-                    pw.print(" nextRestartTime="); pw.print(nextRestartTime-now);
+                    pw.print(" restartDelay=");
+                    TimeUtils.formatDuration(restartDelay, now, pw);
+                    pw.print(" nextRestartTime=");
+                    TimeUtils.formatDuration(nextRestartTime, now, pw);
                     pw.print(" crashCount="); pw.println(crashCount);
         }
         if (deliveredStarts.size() > 0) {
             pw.print(prefix); pw.println("Delivered Starts:");
-            dumpStartList(pw, prefix, deliveredStarts, SystemClock.uptimeMillis());
+            dumpStartList(pw, prefix, deliveredStarts, now);
         }
         if (pendingStarts.size() > 0) {
             pw.print(prefix); pw.println("Pending Starts:");
@@ -213,7 +227,8 @@
         dataDir = sInfo.applicationInfo.dataDir;
         exported = sInfo.exported;
         this.restarter = restarter;
-        createTime = lastActivity = SystemClock.uptimeMillis();
+        createTime = SystemClock.elapsedRealtime();
+        lastActivity = SystemClock.uptimeMillis();
     }
 
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index 3b326df..0f448e0 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -190,7 +190,7 @@
         return err;
     }
 
-    if (texture->target != GL_TEXTURE_2D)
+    if (texture->target != Texture::TEXTURE_2D)
         return INVALID_OPERATION;
 
     glBindTexture(GL_TEXTURE_2D, texture->name);
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index 37ef912..0c63c37 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -304,9 +304,9 @@
             int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly);
             ret[1] = septets;
             if (septets > MAX_USER_DATA_SEPTETS) {
-                ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
-                ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
-                            - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+                ret[0] = (septets + (MAX_USER_DATA_SEPTETS_WITH_HEADER - 1)) /
+                            MAX_USER_DATA_SEPTETS_WITH_HEADER;
+                ret[2] = (ret[0] * MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;
             } else {
                 ret[0] = 1;
                 ret[2] = MAX_USER_DATA_SEPTETS - septets;
@@ -318,9 +318,9 @@
             ret[1] = messageBody.length();
             if (octets > MAX_USER_DATA_BYTES) {
                 // 6 is the size of the user data header
-                ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
-                ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
-                            - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+                ret[0] = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+                            MAX_USER_DATA_BYTES_WITH_HEADER;
+                ret[2] = ((ret[0] * MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
             } else {
                 ret[0] = 1;
                 ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 65d87f5..e95b2f9 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -442,7 +442,7 @@
      */
     public static TextEncodingDetails calculateLength(CharSequence messageBody,
             boolean use7bitOnly) {
-        return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+        return BearerData.calcTextEncodingDetails(messageBody, use7bitOnly);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index e9fea55..cf06dab 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -402,6 +402,7 @@
     /**
      * Calculate the message text encoding length, fragmentation, and other details.
      *
+     * @param msg message text
      * @param force7BitEncoding ignore (but still count) illegal characters if true
      * @return septet count, or -1 on failure
      */
@@ -424,9 +425,10 @@
                 ted.codeUnitCount = msg.length();
                 int octets = ted.codeUnitCount * 2;
                 if (octets > MAX_USER_DATA_BYTES) {
-                    ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
-                    ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
-                              - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+                    ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+                            MAX_USER_DATA_BYTES_WITH_HEADER;
+                    ted.codeUnitsRemaining = ((ted.msgCount *
+                            MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
                 } else {
                     ted.msgCount = 1;
                     ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
@@ -801,7 +803,7 @@
      *
      * @param bData an instance of BearerData.
      *
-     * @return data byte array of raw encoded SMS bearer data.
+     * @return byte array of raw encoded SMS bearer data.
      */
     public static byte[] encode(BearerData bData) {
         bData.hasUserDataHeader = ((bData.userData != null) &&
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 278e1ba..a77484a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -795,9 +795,10 @@
             int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
             ted.codeUnitCount = septets;
             if (septets > MAX_USER_DATA_SEPTETS) {
-                ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
-                ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
-                    - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+                ted.msgCount = (septets + (MAX_USER_DATA_SEPTETS_WITH_HEADER - 1)) /
+                        MAX_USER_DATA_SEPTETS_WITH_HEADER;
+                ted.codeUnitsRemaining = (ted.msgCount *
+                        MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;
             } else {
                 ted.msgCount = 1;
                 ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
@@ -807,9 +808,10 @@
             int octets = msgBody.length() * 2;
             ted.codeUnitCount = msgBody.length();
             if (octets > MAX_USER_DATA_BYTES) {
-                ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
-                ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
-                          - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+                ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+                        MAX_USER_DATA_BYTES_WITH_HEADER;
+                ted.codeUnitsRemaining = ((ted.msgCount *
+                        MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
             } else {
                 ted.msgCount = 1;
                 ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
new file mode 100644
index 0000000..b214887
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.SmsMessage;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
+
+public class SmsMessageBodyTest extends AndroidTestCase {
+
+    private static final String sAsciiChars = "@$_ !\"#%&'()*+,-./0123456789" +
+            ":;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\r";
+    private static final String sGsmBasicChars = "\u00a3\u00a5\u00e8\u00e9" +
+            "\u00f9\u00ec\u00f2\u00c7\u00d8\u00f8\u00c5\u00e5\u0394\u03a6" +
+            "\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u00c6\u00e6" +
+            "\u00df\u00c9\u00a4\u00a1\u00c4\u00d6\u00d1\u00dc\u00a7\u00bf" +
+            "\u00e4\u00f6\u00f1\u00fc\u00e0";
+    private static final String sGsmExtendedAsciiChars = "{|}\\[~]^\f";
+    private static final String sGsmExtendedEuroSymbol = "\u20ac";
+    private static final String sUnicodeChars = "\u4e00\u4e01\u4e02\u4e03" +
+            "\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d" +
+            "\u4e0e\u4e0f\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048" +
+            "\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8" +
+            "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18" +
+            "\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78" +
+            "\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408" +
+            "\u00a2\u00a9\u00ae\u2122";
+
+    private static final int sTestLengthCount = 12;
+
+    private static final int[] sSeptetTestLengths =
+            {  0,   1,   2, 80, 159, 160, 161, 240, 305, 306, 307, 320};
+
+    private static final int[] sUnicodeTestLengths =
+            {  0,   1,   2, 35,  69,  70,  71, 100, 133, 134, 135, 160};
+
+    private static final int[] sTestMsgCounts =
+            {  1,   1,   1,  1,   1,   1,   2,   2,   2,   2,   3,   3};
+
+    private static final int[] sSeptetUnitsRemaining =
+            {160, 159, 158, 80,   1,   0, 145,  66,   1,   0, 152, 139};
+
+    private static final int[] sUnicodeUnitsRemaining =
+            { 70,  69,  68, 35,   1,   0,  63,  34,   1,   0,  66,  41};
+
+
+    @SmallTest
+    public void testCalcLengthAscii() throws Exception {
+        StringBuilder sb = new StringBuilder(320);
+        int[] values = {0, 0, 0, SmsMessage.ENCODING_7BIT};
+        int startPos = 0;
+        int asciiCharsLen = sAsciiChars.length();
+
+        for (int i = 0; i < sTestLengthCount; i++) {
+            int len = sSeptetTestLengths[i];
+            assertTrue(sb.length() <= len);
+
+            while (sb.length() < len) {
+                int addCount = len - sb.length();
+                int endPos = (asciiCharsLen - startPos > addCount) ?
+                        (startPos + addCount) : asciiCharsLen;
+                sb.append(sAsciiChars, startPos, endPos);
+                startPos = (endPos == asciiCharsLen) ? 0 : endPos;
+            }
+            assertEquals(len, sb.length());
+
+            String testStr = sb.toString();
+            values[0] = sTestMsgCounts[i];
+            values[1] = len;
+            values[2] = sSeptetUnitsRemaining[i];
+
+            callGsmLengthMethods(testStr, false, values);
+            callGsmLengthMethods(testStr, true, values);
+            callCdmaLengthMethods(testStr, false, values);
+            callCdmaLengthMethods(testStr, true, values);
+        }
+    }
+
+    @SmallTest
+    public void testCalcLength7bitGsm() throws Exception {
+        // TODO
+    }
+
+    @SmallTest
+    public void testCalcLength7bitGsmExtended() throws Exception {
+        // TODO
+    }
+
+    @SmallTest
+    public void testCalcLengthUnicode() throws Exception {
+        StringBuilder sb = new StringBuilder(160);
+        int[] values = {0, 0, 0, SmsMessage.ENCODING_16BIT};
+        int[] values7bit = {1, 0, 0, SmsMessage.ENCODING_7BIT};
+        int startPos = 0;
+        int unicodeCharsLen = sUnicodeChars.length();
+
+        // start with length 1: empty string uses ENCODING_7BIT
+        for (int i = 1; i < sTestLengthCount; i++) {
+            int len = sUnicodeTestLengths[i];
+            assertTrue(sb.length() <= len);
+
+            while (sb.length() < len) {
+                int addCount = len - sb.length();
+                int endPos = (unicodeCharsLen - startPos > addCount) ?
+                        (startPos + addCount) : unicodeCharsLen;
+                sb.append(sUnicodeChars, startPos, endPos);
+                startPos = (endPos == unicodeCharsLen) ? 0 : endPos;
+            }
+            assertEquals(len, sb.length());
+
+            String testStr = sb.toString();
+            values[0] = sTestMsgCounts[i];
+            values[1] = len;
+            values[2] = sUnicodeUnitsRemaining[i];
+            values7bit[1] = len;
+            values7bit[2] = MAX_USER_DATA_SEPTETS - len;
+
+            callGsmLengthMethods(testStr, false, values);
+            callCdmaLengthMethods(testStr, false, values);
+            callGsmLengthMethods(testStr, true, values7bit);
+            callCdmaLengthMethods(testStr, true, values7bit);
+        }
+    }
+
+    private void callGsmLengthMethods(CharSequence msgBody, boolean use7bitOnly,
+            int[] expectedValues)
+    {
+        // deprecated GSM-specific method
+        int[] values = android.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
+        assertEquals("msgCount",           expectedValues[0], values[0]);
+        assertEquals("codeUnitCount",      expectedValues[1], values[1]);
+        assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+        assertEquals("codeUnitSize",       expectedValues[3], values[3]);
+
+        int activePhone = TelephonyManager.getDefault().getPhoneType();
+        if (TelephonyManager.PHONE_TYPE_GSM == activePhone) {
+            values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
+            assertEquals("msgCount",           expectedValues[0], values[0]);
+            assertEquals("codeUnitCount",      expectedValues[1], values[1]);
+            assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+            assertEquals("codeUnitSize",       expectedValues[3], values[3]);
+        }
+
+        SmsMessageBase.TextEncodingDetails ted =
+                com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
+        assertEquals("msgCount",           expectedValues[0], ted.msgCount);
+        assertEquals("codeUnitCount",      expectedValues[1], ted.codeUnitCount);
+        assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+        assertEquals("codeUnitSize",       expectedValues[3], ted.codeUnitSize);
+    }
+
+    private void callCdmaLengthMethods(CharSequence msgBody, boolean use7bitOnly,
+            int[] expectedValues)
+    {
+        int activePhone = TelephonyManager.getDefault().getPhoneType();
+        if (TelephonyManager.PHONE_TYPE_CDMA == activePhone) {
+            int[] values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
+            assertEquals("msgCount",           expectedValues[0], values[0]);
+            assertEquals("codeUnitCount",      expectedValues[1], values[1]);
+            assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
+            assertEquals("codeUnitSize",       expectedValues[3], values[3]);
+        }
+
+        SmsMessageBase.TextEncodingDetails ted =
+                com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
+        assertEquals("msgCount",           expectedValues[0], ted.msgCount);
+        assertEquals("codeUnitCount",      expectedValues[1], ted.codeUnitCount);
+        assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+        assertEquals("codeUnitSize",       expectedValues[3], ted.codeUnitSize);
+
+        ted = com.android.internal.telephony.cdma.sms.BearerData.calcTextEncodingDetails(msgBody, use7bitOnly);
+        assertEquals("msgCount",           expectedValues[0], ted.msgCount);
+        assertEquals("codeUnitCount",      expectedValues[1], ted.codeUnitCount);
+        assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
+        assertEquals("codeUnitSize",       expectedValues[3], ted.codeUnitSize);
+    }
+}
diff --git a/tests/BatteryWaster/res/layout/battery_waster.xml b/tests/BatteryWaster/res/layout/battery_waster.xml
index e1cb6bf..57a5b55 100644
--- a/tests/BatteryWaster/res/layout/battery_waster.xml
+++ b/tests/BatteryWaster/res/layout/battery_waster.xml
@@ -25,11 +25,23 @@
         android:layout_height="wrap_content"
         android:layout_marginLeft="25dp"
         android:layout_marginTop="25dp"
+        android:saveEnabled="false"
         android:textSize="18sp"
         android:textColor="#ffffffff"
         android:text="@string/waste_away"
         />
 
+    <CheckBox android:id="@+id/checkbox_wake"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="25dp"
+        android:layout_marginTop="25dp"
+        android:saveEnabled="false"
+        android:textSize="18sp"
+        android:textColor="#ffffffff"
+        android:text="@string/wake_away"
+        />
+
     <ScrollView android:id="@+id/scroll"
         android:layout_width="match_parent"
         android:layout_height="0px"
diff --git a/tests/BatteryWaster/res/values/strings.xml b/tests/BatteryWaster/res/values/strings.xml
index 46c5fa1..a3b849a 100644
--- a/tests/BatteryWaster/res/values/strings.xml
+++ b/tests/BatteryWaster/res/values/strings.xml
@@ -18,5 +18,7 @@
 
     <string name="waste_away">Discharge my battery!</string>
 
+    <string name="wake_away">Keep my device awake!</string>
+
 </resources>
 
diff --git a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
index 8ea7e00..48c4520 100644
--- a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
+++ b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
@@ -39,8 +39,11 @@
     DateFormat mDateFormat;
     IntentFilter mFilter;
     PowerManager.WakeLock mWakeLock;
+    PowerManager.WakeLock mPartialWakeLock;
     SpinThread mThread;
 
+    boolean mWasting, mWaking;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -50,6 +53,7 @@
         setContentView(R.layout.battery_waster);
 
         findViewById(R.id.checkbox).setOnClickListener(mClickListener);
+        findViewById(R.id.checkbox_wake).setOnClickListener(mWakeClickListener);
         mLog = (TextView)findViewById(R.id.log);
 
         mDateFormat = DateFormat.getInstance();
@@ -63,13 +67,27 @@
         PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BatteryWaster");
         mWakeLock.setReferenceCounted(false);
+        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BatteryWaster");
+        mPartialWakeLock.setReferenceCounted(false);
     }
 
     @Override
     public void onPause() {
+        super.onPause();
         stopRunning();
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mWakeLock.isHeld()) {
+            mWakeLock.release();
+        }
+        if (mPartialWakeLock.isHeld()) {
+            mPartialWakeLock.release();
+        }
+    }
+
     View.OnClickListener mClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             CheckBox checkbox = (CheckBox)v;
@@ -81,23 +99,63 @@
         }
     };
 
+    View.OnClickListener mWakeClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            CheckBox checkbox = (CheckBox)v;
+            if (checkbox.isChecked()) {
+                mWaking = true;
+                updateWakeLock();
+            } else {
+                mWaking = false;
+                updateWakeLock();
+            }
+        }
+    };
+
     void startRunning() {
-        log("Start");
-        registerReceiver(mReceiver, mFilter);
-        mWakeLock.acquire();
-        if (mThread == null) {
-            mThread = new SpinThread();
-            mThread.start();
+        if (!mWasting) {
+            log("Start");
+            registerReceiver(mReceiver, mFilter);
+            mWasting = true;
+            updateWakeLock();
+            if (mThread == null) {
+                mThread = new SpinThread();
+                mThread.start();
+            }
         }
     }
 
     void stopRunning() {
-        log("Stop");
-        unregisterReceiver(mReceiver);
-        mWakeLock.release();
-        if (mThread != null) {
-            mThread.quit();
-            mThread = null;
+        if (mWasting) {
+            log("Stop");
+            unregisterReceiver(mReceiver);
+            mWasting = false;
+            updateWakeLock();
+            if (mThread != null) {
+                mThread.quit();
+                mThread = null;
+            }
+        }
+    }
+
+    void updateWakeLock() {
+        if (mWasting) {
+            if (!mWakeLock.isHeld()) {
+                mWakeLock.acquire();
+            }
+        } else {
+            if (mWakeLock.isHeld()) {
+                mWakeLock.release();
+            }
+        }
+        if (mWaking) {
+            if (!mPartialWakeLock.isHeld()) {
+                mPartialWakeLock.acquire();
+            }
+        } else {
+            if (mPartialWakeLock.isHeld()) {
+                mPartialWakeLock.release();
+            }
         }
     }
 
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 5855b56..31c1722 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1880,7 +1880,7 @@
             className.append(inClassName);
         }
     }
-    
+
     String8 rule("-keep class ");
     rule += className;
     rule += " { <init>(...); }";
@@ -1955,7 +1955,7 @@
             if (tag == "application") {
                 inApplication = true;
                 keepTag = true;
-                
+
                 String8 agent = getAttribute(tree, "http://schemas.android.com/apk/res/android",
                         "backupAgent", &error);
                 if (agent.length() > 0) {
@@ -1988,9 +1988,17 @@
     return NO_ERROR;
 }
 
+struct NamespaceAttributePair {
+    const char* ns;
+    const char* attr;
+
+    NamespaceAttributePair(const char* n, const char* a) : ns(n), attr(a) {}
+    NamespaceAttributePair() : ns(NULL), attr(NULL) {}
+};
+
 status_t
 writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
-        const char* startTag, const char* altTag)
+        const char* startTag, const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs)
 {
     status_t err;
     ResXMLTree tree;
@@ -2020,7 +2028,7 @@
             return NO_ERROR;
         }
     }
-    
+
     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
         if (code != ResXMLTree::START_TAG) {
             continue;
@@ -2031,16 +2039,21 @@
         if (strchr(tag.string(), '.')) {
             addProguardKeepRule(keep, tag, NULL,
                     layoutFile->getPrintableSource(), tree.getLineNumber());
-        } else if (altTag != NULL && tag == altTag) {
-            ssize_t classIndex = tree.indexOfAttribute(NULL, "class");
-            if (classIndex < 0) {
-                fprintf(stderr, "%s:%d: <view> does not have class attribute.\n",
-                        layoutFile->getPrintableSource().string(), tree.getLineNumber());
-            } else {
-                size_t len;
-                addProguardKeepRule(keep,
-                        String8(tree.getAttributeStringValue(classIndex, &len)), NULL,
-                        layoutFile->getPrintableSource(), tree.getLineNumber());
+        } else if (tagAttrPairs != NULL) {
+            ssize_t tagIndex = tagAttrPairs->indexOfKey(tag);
+            if (tagIndex >= 0) {
+                const NamespaceAttributePair& nsAttr = tagAttrPairs->valueAt(tagIndex);
+                ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
+                if (attrIndex < 0) {
+                    // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
+                    //        layoutFile->getPrintableSource().string(), tree.getLineNumber(),
+                    //        tag.string(), nsAttr.ns, nsAttr.attr);
+                } else {
+                    size_t len;
+                    addProguardKeepRule(keep,
+                                        String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
+                                        layoutFile->getPrintableSource(), tree.getLineNumber());
+                }
             }
         }
     }
@@ -2048,25 +2061,42 @@
     return NO_ERROR;
 }
 
+static void addTagAttrPair(KeyedVector<String8, NamespaceAttributePair>* dest,
+        const char* tag, const char* ns, const char* attr) {
+    dest->add(String8(tag), NamespaceAttributePair(ns, attr));
+}
+
 status_t
 writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
 {
     status_t err;
+
+    // tag:attribute pairs that should be checked in layout files.
+    KeyedVector<String8, NamespaceAttributePair> kLayoutTagAttrPairs;
+    addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
+    addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
+
+    // tag:attribute pairs that should be checked in xml files.
+    KeyedVector<String8, NamespaceAttributePair> kXmlTagAttrPairs;
+    addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
+    addTagAttrPair(&kXmlTagAttrPairs, "Header", RESOURCES_ANDROID_NAMESPACE, "fragment");
+
     const Vector<sp<AaptDir> >& dirs = assets->resDirs();
     const size_t K = dirs.size();
     for (size_t k=0; k<K; k++) {
         const sp<AaptDir>& d = dirs.itemAt(k);
         const String8& dirName = d->getLeaf();
         const char* startTag = NULL;
-        const char* altTag = NULL;
+        const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs = NULL;
         if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
-            altTag = "view";
+            tagAttrPairs = &kLayoutTagAttrPairs;
         } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
             startTag = "PreferenceScreen";
+            tagAttrPairs = &kXmlTagAttrPairs;
         } else {
             continue;
         }
-        
+
         const KeyedVector<String8,sp<AaptGroup> > groups = d->getFiles();
         const size_t N = groups.size();
         for (size_t i=0; i<N; i++) {
@@ -2074,7 +2104,7 @@
             const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
             const size_t M = files.size();
             for (size_t j=0; j<M; j++) {
-                err = writeProguardForXml(keep, files.valueAt(j), startTag, altTag);
+                err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
                 if (err < 0) {
                     return err;
                 }
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index abdc9d7..f4be839 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -191,11 +191,8 @@
      */
     void continueCall() throws SipException;
 
-    /** Puts the device to in-call mode. */
-    void setInCallMode();
-
     /** Puts the device to speaker mode. */
-    void setSpeakerMode();
+    void setSpeakerMode(boolean speakerMode);
 
     /** Toggles mute. */
     void toggleMute();
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 474bc4b..7161309 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -485,16 +485,9 @@
         return mMuted;
     }
 
-    public synchronized void setInCallMode() {
+    public synchronized void setSpeakerMode(boolean speakerMode) {
         ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
-                .setSpeakerphoneOn(false);
-        ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
-                .setMode(AudioManager.MODE_NORMAL);
-    }
-
-    public synchronized void setSpeakerMode() {
-        ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
-                .setSpeakerphoneOn(true);
+                .setSpeakerphoneOn(speakerMode);
     }
 
     public void sendDtmf(int code) {
@@ -587,8 +580,15 @@
                     Log.d(TAG, "   not sending");
                     audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
                 }
+            } else {
+                /* The recorder volume will be very low if the device is in
+                 * IN_CALL mode. Therefore, we have to set the mode to NORMAL
+                 * in order to have the normal microphone level.
+                 */
+                ((AudioManager) mContext.getSystemService
+                        (Context.AUDIO_SERVICE))
+                        .setMode(AudioManager.MODE_NORMAL);
             }
-            setInCallMode();
 
             AudioGroup audioGroup = new AudioGroup();
             audioStream.join(audioGroup);
@@ -614,7 +614,6 @@
                 mRtpSession = null;
             }
         }
-        setInCallMode();
     }
 
     private int getLocalMediaPort() {