Merge "Invalidate transitions when the start time or duration of an effect or overlay changes."
diff --git a/api/current.xml b/api/current.xml
index ba168be..c9c6f6f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2297,6 +2297,17 @@
  visibility="public"
 >
 </field>
+<field name="animationResolution"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843563"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="antialias"
  type="int"
  transient="false"
@@ -2473,6 +2484,17 @@
  visibility="public"
 >
 </field>
+<field name="baseline"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843565"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="baselineAlignBottom"
  type="int"
  transient="false"
@@ -5135,6 +5157,17 @@
  visibility="public"
 >
 </field>
+<field name="indeterminateProgressStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843561"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="indicatorLeft"
  type="int"
  transient="false"
@@ -7159,6 +7192,17 @@
  visibility="public"
 >
 </field>
+<field name="progressBarPadding"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843562"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="progressBarStyle"
  type="int"
  transient="false"
@@ -8468,6 +8512,17 @@
  visibility="public"
 >
 </field>
+<field name="state_accelerated"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843564"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="state_activated"
  type="int"
  transient="false"
@@ -14612,6 +14667,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Holo_Light_DialogWhenLarge"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973955"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Holo_Light_Dialog_Alert"
  type="int"
  transient="false"
@@ -19530,6 +19596,17 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCustomView"
+ return="android.view.View"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -21021,6 +21098,32 @@
 <parameter name="nonRoot" type="boolean">
 </parameter>
 </method>
+<method name="onActionModeFinished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
+<method name="onActionModeStarted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
 <method name="onActivityResult"
  return="void"
  abstract="false"
@@ -21656,19 +21759,6 @@
  visibility="protected"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onStop"
  return="void"
  abstract="false"
@@ -21769,6 +21859,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 <method name="openContextMenu"
  return="void"
  abstract="false"
@@ -21819,47 +21922,6 @@
 <parameter name="exitAnim" type="int">
 </parameter>
 </method>
-<method name="popBackStack"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-</method>
-<method name="popBackStack"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="popBackStack"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="public"
->
-<parameter name="id" type="int">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
 <method name="registerForContextMenu"
  return="void"
  abstract="false"
@@ -22545,17 +22607,6 @@
  visibility="protected"
 >
 </field>
-<field name="POP_BACK_STACK_INCLUSIVE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="RESULT_CANCELED"
  type="int"
  transient="false"
@@ -25368,6 +25419,32 @@
  visibility="public"
 >
 </method>
+<method name="onActionModeFinished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
+<method name="onActionModeStarted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
 <method name="onAttachedToWindow"
  return="void"
  abstract="false"
@@ -25718,19 +25795,6 @@
  visibility="protected"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onStop"
  return="void"
  abstract="false"
@@ -25794,6 +25858,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 <method name="openContextMenu"
  return="void"
  abstract="false"
@@ -28242,6 +28319,17 @@
 <parameter name="args" type="java.lang.String[]">
 </parameter>
 </method>
+<method name="executePendingTransactions"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="findFragmentById"
  return="android.app.Fragment"
  abstract="true"
@@ -28308,7 +28396,7 @@
 >
 </method>
 <method name="popBackStack"
- return="boolean"
+ return="void"
  abstract="true"
  native="false"
  synchronized="false"
@@ -28319,7 +28407,7 @@
 >
 </method>
 <method name="popBackStack"
- return="boolean"
+ return="void"
  abstract="true"
  native="false"
  synchronized="false"
@@ -28334,6 +28422,47 @@
 </parameter>
 </method>
 <method name="popBackStack"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="popBackStackImmediate"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="popBackStackImmediate"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="popBackStackImmediate"
  return="boolean"
  abstract="true"
  native="false"
@@ -212017,6 +212146,32 @@
 <parameter name="event" type="android.view.MotionEvent">
 </parameter>
 </method>
+<method name="onActionModeFinished"
+ 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>
+</method>
+<method name="onActionModeStarted"
+ 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>
+</method>
 <method name="onAttachedToWindow"
  return="void"
  abstract="true"
@@ -212151,19 +212306,6 @@
  visibility="public"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onWindowAttributesChanged"
  return="void"
  abstract="true"
@@ -212190,6 +212332,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 </interface>
 <interface name="WindowManager"
  abstract="true"
@@ -219249,6 +219404,19 @@
 <parameter name="data" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="setCurrentInputMethodSubtype"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="subtype" type="android.view.inputmethod.InputMethodSubtype">
+</parameter>
+</method>
 <method name="setInputMethod"
  return="void"
  abstract="false"
@@ -222201,6 +222369,101 @@
 </parameter>
 </method>
 </interface>
+<class name="WebResourceResponse"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WebResourceResponse"
+ type="android.webkit.WebResourceResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+<parameter name="encoding" type="java.lang.String">
+</parameter>
+<parameter name="data" type="java.io.InputStream">
+</parameter>
+</constructor>
+<method name="getData"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEncoding"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="java.io.InputStream">
+</parameter>
+</method>
+<method name="setEncoding"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="encoding" type="java.lang.String">
+</parameter>
+</method>
+<method name="setMimeType"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
+</class>
 <class name="WebSettings"
  extends="java.lang.Object"
  abstract="false"
@@ -225290,6 +225553,21 @@
 <parameter name="event" type="android.view.KeyEvent">
 </parameter>
 </method>
+<method name="shouldInterceptRequest"
+ return="android.webkit.WebResourceResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="url" type="java.lang.String">
+</parameter>
+</method>
 <method name="shouldOverrideKeyEvent"
  return="boolean"
  abstract="false"
@@ -234006,6 +234284,17 @@
  visibility="public"
 >
 </method>
+<method name="getBaselineAlignBottom"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDrawable"
  return="android.graphics.drawable.Drawable"
  abstract="false"
@@ -234078,6 +234367,32 @@
 <parameter name="alpha" type="int">
 </parameter>
 </method>
+<method name="setBaseline"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseline" type="int">
+</parameter>
+</method>
+<method name="setBaselineAlignBottom"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="aligned" type="boolean">
+</parameter>
+</method>
 <method name="setColorFilter"
  return="void"
  abstract="false"
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index f8eb514..1264215 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -264,7 +264,7 @@
     }
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
-    enc_meta->setInt32(kKeySampleRate, frameRateFps);
+    enc_meta->setInt32(kKeyFrameRate, frameRateFps);
     enc_meta->setInt32(kKeyBitRate, bitRateBps);
     enc_meta->setInt32(kKeyStride, width);
     enc_meta->setInt32(kKeySliceHeight, height);
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index a57b54a..246d661 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -138,14 +138,19 @@
      * Set the action bar into custom navigation mode, supplying a view
      * for custom navigation.
      * 
-     * Custom navigation views appear between the application icon and
+     * <p>Custom navigation views appear between the application icon and
      * any action buttons and may use any space available there. Common
      * use cases for custom navigation views might include an auto-suggesting
      * address bar for a browser or other navigation mechanisms that do not
-     * translate well to provided navigation modes.
+     * translate well to provided navigation modes.</p>
+     *
+     * <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
+     * the custom view to be displayed.</p>
      * 
      * @param view Custom navigation view to place in the ActionBar.
      * @param layoutParams How this custom view should layout in the bar.
+     *
+     * @see #setDisplayOptions(int, int)
      */
     public abstract void setCustomView(View view, LayoutParams layoutParams);
 
@@ -248,39 +253,47 @@
     public abstract void setStandardNavigationMode();
 
     /**
-     * Set the action bar's title. This will only be displayed in standard navigation mode.
+     * Set the action bar's title. This will only be displayed if
+     * {@link #DISPLAY_SHOW_TITLE} is set.
      *
      * @param title Title to set
      *
      * @see #setTitle(int)
+     * @see #setDisplayOptions(int, int)
      */
     public abstract void setTitle(CharSequence title);
 
     /**
-     * Set the action bar's title. This will only be displayed in standard navigation mode.
+     * Set the action bar's title. This will only be displayed if
+     * {@link #DISPLAY_SHOW_TITLE} is set.
      *
      * @param resId Resource ID of title string to set
      *
      * @see #setTitle(CharSequence)
+     * @see #setDisplayOptions(int, int)
      */
     public abstract void setTitle(int resId);
 
     /**
-     * Set the action bar's subtitle. This will only be displayed in standard navigation mode.
-     * Set to null to disable the subtitle entirely.
+     * Set the action bar's subtitle. This will only be displayed if
+     * {@link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the
+     * subtitle entirely.
      *
      * @param subtitle Subtitle to set
      *
      * @see #setSubtitle(int)
+     * @see #setDisplayOptions(int, int)
      */
     public abstract void setSubtitle(CharSequence subtitle);
 
     /**
-     * Set the action bar's subtitle. This will only be displayed in standard navigation mode.
+     * Set the action bar's subtitle. This will only be displayed if
+     * {@link #DISPLAY_SHOW_TITLE} is set.
      *
      * @param resId Resource ID of subtitle string to set
      *
      * @see #setSubtitle(CharSequence)
+     * @see #setDisplayOptions(int, int)
      */
     public abstract void setSubtitle(int resId);
 
@@ -317,9 +330,16 @@
     
     /**
      * @return The current custom navigation view.
+     * @deprecated Method has been renamed. Use {@link #getCustomView()}.
      */
+    @Deprecated
     public abstract View getCustomNavigationView();
-    
+
+    /**
+     * @return The current custom view.
+     */
+    public abstract View getCustomView();
+
     /**
      * Returns the current ActionBar title in standard mode.
      * Returns null if {@link #getNavigationMode()} would not return
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 33f88d8..5174f19 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2086,63 +2086,12 @@
     }
     
     /**
-     * Flag for {@link #popBackStack(String, int)}
-     * and {@link #popBackStack(int, int)}: If set, and the name or ID of
-     * a back stack entry has been supplied, then all matching entries will
-     * be consumed until one that doesn't match is found or the bottom of
-     * the stack is reached.  Otherwise, all entries up to but not including that entry
-     * will be removed.
-     */
-    public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
-
-    /**
-     * Pop the top state off the back stack.  Returns true if there was one
-     * to pop, else false.
-     * @deprecated use {@link #getFragmentManager}.
-     */
-    @Deprecated
-    public boolean popBackStack() {
-        return mFragments.popBackStack();
-    }
-
-    /**
-     * Pop the last fragment transition from the local activity's fragment
-     * back stack.  If there is nothing to pop, false is returned.
-     * @param name If non-null, this is the name of a previous back state
-     * to look for; if found, all states up to that state will be popped.  The
-     * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
-     * the named state itself is popped. If null, only the top state is popped.
-     * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
-     * @deprecated use {@link #getFragmentManager}.
-     */
-    @Deprecated
-    public boolean popBackStack(String name, int flags) {
-        return mFragments.popBackStack(name, flags);
-    }
-
-    /**
-     * Pop all back stack states up to the one with the given identifier.
-     * @param id Identifier of the stated to be popped. If no identifier exists,
-     * false is returned.
-     * The identifier is the number returned by
-     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.  The
-     * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
-     * the named state itself is popped.
-     * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
-     * @deprecated use {@link #getFragmentManager}.
-     */
-    @Deprecated
-    public boolean popBackStack(int id, int flags) {
-        return mFragments.popBackStack(id, flags);
-    }
-    
-    /**
      * Called when the activity has detected the user's press of the back
      * key.  The default implementation simply finishes the current activity,
      * but you can override this to do whatever you want.
      */
     public void onBackPressed() {
-        if (!mFragments.popBackStack()) {
+        if (!mFragments.popBackStackImmediate()) {
             finish();
         }
     }
@@ -4174,7 +4123,7 @@
     }
 
     /**
-     * Start a context mode.
+     * Start an action mode.
      *
      * @param callback Callback that will manage lifecycle events for this context mode
      * @return The ContextMode that was started, or null if it was canceled
@@ -4185,7 +4134,18 @@
         return mWindow.getDecorView().startActionMode(callback);
     }
 
-    public ActionMode onStartActionMode(ActionMode.Callback callback) {
+    /**
+     * Give the Activity a chance to control the UI for an action mode requested
+     * by the system.
+     *
+     * <p>Note: If you are looking for a notification callback that an action mode
+     * has been started for this activity, see {@link #onActionModeStarted(ActionMode)}.</p>
+     *
+     * @param callback The callback that should control the new action mode
+     * @return The new action mode, or <code>null</code> if the activity does not want to
+     *         provide special handling for this action mode. (It will be handled by the system.)
+     */
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         initActionBar();
         if (mActionBar != null) {
             return mActionBar.startActionMode(callback);
@@ -4193,6 +4153,24 @@
         return null;
     }
 
+    /**
+     * Notifies the Activity that an action mode has been started.
+     * Activity subclasses overriding this method should call the superclass implementation.
+     *
+     * @param mode The new action mode.
+     */
+    public void onActionModeStarted(ActionMode mode) {
+    }
+
+    /**
+     * Notifies the activity that an action mode has finished.
+     * Activity subclasses overriding this method should call the superclass implementation.
+     *
+     * @param mode The action mode that just finished.
+     */
+    public void onActionModeFinished(ActionMode mode) {
+    }
+
     // ------------------ Internal API ------------------
     
     final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 70e11df..3cead11 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -95,6 +95,7 @@
 import java.util.TimeZone;
 import java.util.regex.Pattern;
 
+import dalvik.system.CloseGuard;
 import dalvik.system.SamplingProfiler;
 
 final class SuperNotCalledException extends AndroidRuntimeException {
@@ -3726,6 +3727,11 @@
     public static final void main(String[] args) {
         SamplingProfilerIntegration.start();
 
+        // CloseGuard defaults to true and can be quite spammy.  We
+        // disable it here, but selectively enable it later (via
+        // StrictMode) on debug builds, but using DropBox, not logs.
+        CloseGuard.setEnabled(false);
+
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 129c29d..dda3107 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -106,9 +106,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
 
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
@@ -149,18 +146,9 @@
     private final static String TAG = "ApplicationContext";
     private final static boolean DEBUG = false;
 
-    private static final Object sSync = new Object();
-    private static AlarmManager sAlarmManager;
-    private static PowerManager sPowerManager;
-    private static ConnectivityManager sConnectivityManager;
-    private static ThrottleManager sThrottleManager;
-    private static WifiManager sWifiManager;
-    private static LocationManager sLocationManager;
-    private static CountryDetector sCountryDetector;
     private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
             new HashMap<String, SharedPreferencesImpl>();
 
-    private AudioManager mAudioManager;
     /*package*/ LoadedApk mPackageInfo;
     private Resources mResources;
     /*package*/ ActivityThread mMainThread;
@@ -170,24 +158,8 @@
     private int mThemeResource = 0;
     private Resources.Theme mTheme = null;
     private PackageManager mPackageManager;
-    private NotificationManager mNotificationManager = null;
-    private ActivityManager mActivityManager = null;
-    private WallpaperManager mWallpaperManager = null;
     private Context mReceiverRestrictedContext = null;
-    private SearchManager mSearchManager = null;
-    private SensorManager mSensorManager = null;
-    private StorageManager mStorageManager = null;
-    private Vibrator mVibrator = null;
-    private LayoutInflater mLayoutInflater = null;
-    private StatusBarManager mStatusBarManager = null;
-    private TelephonyManager mTelephonyManager = null;
-    private ClipboardManager mClipboardManager = null;
     private boolean mRestricted;
-    private AccountManager mAccountManager; // protected by mSync
-    private DropBoxManager mDropBoxManager = null;
-    private DevicePolicyManager mDevicePolicyManager = null;
-    private UiModeManager mUiModeManager = null;
-    private DownloadManager mDownloadManager = null;
 
     private final Object mSync = new Object();
 
@@ -200,6 +172,266 @@
 
     private static final String[] EMPTY_FILE_LIST = {};
 
+    /**
+     * Override this class when the system service constructor needs a
+     * ContextImpl.  Else, use StaticServiceFetcher below.
+     */
+    /*package*/ static class ServiceFetcher {
+        int mContextCacheIndex = -1;
+
+        /**
+         * Main entrypoint; only override if you don't need caching.
+         */
+        public Object getService(ContextImpl ctx) {
+            ArrayList<Object> cache = ctx.mServiceCache;
+            Object service;
+            synchronized (cache) {
+                if (cache.size() == 0) {
+                    // Initialize the cache vector on first access.
+                    // At this point sNextPerContextServiceCacheIndex
+                    // is the number of potential services that are
+                    // cached per-Context.
+                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
+                        cache.add(null);
+                    }
+                } else {
+                    service = cache.get(mContextCacheIndex);
+                    if (service != null) {
+                        return service;
+                    }
+                }
+                service = createService(ctx);
+                cache.set(mContextCacheIndex, service);
+                return service;
+            }
+        }
+
+        /**
+         * Override this to create a new per-Context instance of the
+         * service.  getService() will handle locking and caching.
+         */
+        public Object createService(ContextImpl ctx) {
+            throw new RuntimeException("Not implemented");
+        }
+    }
+
+    /**
+     * Override this class for services to be cached process-wide.
+     */
+    abstract static class StaticServiceFetcher extends ServiceFetcher {
+        private Object mCachedInstance;
+
+        @Override
+        public final Object getService(ContextImpl unused) {
+            synchronized (StaticServiceFetcher.this) {
+                Object service = mCachedInstance;
+                if (service != null) {
+                    return service;
+                }
+                return mCachedInstance = createStaticService();
+            }
+        }
+
+        public abstract Object createStaticService();
+    }
+
+    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
+            new HashMap<String, ServiceFetcher>();
+
+    private static int sNextPerContextServiceCacheIndex = 0;
+    private static void registerService(String serviceName, ServiceFetcher fetcher) {
+        if (!(fetcher instanceof StaticServiceFetcher)) {
+            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
+        }
+        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
+    }
+
+    // This one's defined separately and given a variable name so it
+    // can be re-used by getWallpaperManager(), avoiding a HashMap
+    // lookup.
+    private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new WallpaperManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }};
+
+    static {
+        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
+                public Object getService(ContextImpl ctx) {
+                    return AccessibilityManager.getInstance(ctx);
+                }});
+
+        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+                    IAccountManager service = IAccountManager.Stub.asInterface(b);
+                    return new AccountManager(ctx, service);
+                }});
+
+        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
+                }});
+
+        registerService(ALARM_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(ALARM_SERVICE);
+                    IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+                    return new AlarmManager(service);
+                }});
+
+        registerService(AUDIO_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new AudioManager(ctx);
+                }});
+
+        registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new ClipboardManager(ctx.getOuterContext(),
+                            ctx.mMainThread.getHandler());
+                }});
+
+        registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
+                    return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+                }});
+
+        registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
+                    return new CountryDetector(ICountryDetector.Stub.asInterface(b));
+                }});
+
+        registerService(DEVICE_POLICY_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+                }});
+
+        registerService(DOWNLOAD_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+                }});
+
+        registerService(DROPBOX_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    return createDropBoxManager();
+                }});
+
+        registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return InputMethodManager.getInstance(ctx);
+                }});
+
+        registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
+                public Object getService(ContextImpl ctx) {
+                    // TODO: why isn't this caching it?  It wasn't
+                    // before, so I'm preserving the old behavior and
+                    // using getService(), instead of createService()
+                    // which would do the caching.
+                    return new KeyguardManager();
+                }});
+
+        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
+                }});
+
+        registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
+                    return new LocationManager(ILocationManager.Stub.asInterface(b));
+                }});
+
+        registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    final Context outerContext = ctx.getOuterContext();
+                    return new NotificationManager(
+                        new ContextThemeWrapper(outerContext,
+                                outerContext.getApplicationInfo().targetSdkVersion >=
+                                    Build.VERSION_CODES.HONEYCOMB
+                                ? com.android.internal.R.style.Theme_Holo_Dialog
+                                : com.android.internal.R.style.Theme_Dialog),
+                        ctx.mMainThread.getHandler());
+                }});
+
+        // Note: this was previously cached in a static variable, but
+        // constructed using mMainThread.getHandler(), so converting
+        // it to be a regular Context-cached service...
+        registerService(POWER_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(POWER_SERVICE);
+                    IPowerManager service = IPowerManager.Stub.asInterface(b);
+                    return new PowerManager(service, ctx.mMainThread.getHandler());
+                }});
+
+        registerService(SEARCH_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new SearchManager(ctx.getOuterContext(),
+                            ctx.mMainThread.getHandler());
+                }});
+
+        registerService(SENSOR_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new SensorManager(ctx.mMainThread.getHandler().getLooper());
+                }});
+
+        registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new StatusBarManager(ctx.getOuterContext());
+                }});
+
+        registerService(STORAGE_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    try {
+                        return new StorageManager(ctx.mMainThread.getHandler().getLooper());
+                    } catch (RemoteException rex) {
+                        Log.e(TAG, "Failed to create StorageManager", rex);
+                        return null;
+                    }
+                }});
+
+        registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new TelephonyManager(ctx.getOuterContext());
+                }});
+
+        registerService(THROTTLE_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
+                    return new ThrottleManager(IThrottleManager.Stub.asInterface(b));
+                }});
+
+        registerService(UI_MODE_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new UiModeManager();
+                }});
+
+        registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return new Vibrator();
+                }});
+
+        registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
+
+        registerService(WIFI_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(WIFI_SERVICE);
+                    IWifiManager service = IWifiManager.Stub.asInterface(b);
+                    return new WifiManager(service, ctx.mMainThread.getHandler());
+                }});
+
+        registerService(WINDOW_SERVICE, new ServiceFetcher() {
+                public Object getService(ContextImpl ctx) {
+                    return WindowManagerImpl.getDefault();
+                }});
+    }
+
+    // The system service cache for the system services that are
+    // cached per-ContextImpl.  Package-scoped to avoid accessor
+    // methods.
+    final ArrayList<Object> mServiceCache = new ArrayList<Object>();
+
     @Override
     public AssetManager getAssets() {
         return mResources.getAssets();
@@ -895,273 +1127,12 @@
 
     @Override
     public Object getSystemService(String name) {
-        if (WINDOW_SERVICE.equals(name)) {
-            return WindowManagerImpl.getDefault();
-        } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
-            synchronized (mSync) {
-                LayoutInflater inflater = mLayoutInflater;
-                if (inflater != null) {
-                    return inflater;
-                }
-                mLayoutInflater = inflater =
-                    PolicyManager.makeNewLayoutInflater(getOuterContext());
-                return inflater;
-            }
-        } else if (ACTIVITY_SERVICE.equals(name)) {
-            return getActivityManager();
-        } else if (INPUT_METHOD_SERVICE.equals(name)) {
-            return InputMethodManager.getInstance(this);
-        } else if (ALARM_SERVICE.equals(name)) {
-            return getAlarmManager();
-        } else if (ACCOUNT_SERVICE.equals(name)) {
-            return getAccountManager();
-        } else if (POWER_SERVICE.equals(name)) {
-            return getPowerManager();
-        } else if (CONNECTIVITY_SERVICE.equals(name)) {
-            return getConnectivityManager();
-        } else if (THROTTLE_SERVICE.equals(name)) {
-            return getThrottleManager();
-        } else if (WIFI_SERVICE.equals(name)) {
-            return getWifiManager();
-        } else if (NOTIFICATION_SERVICE.equals(name)) {
-            return getNotificationManager();
-        } else if (KEYGUARD_SERVICE.equals(name)) {
-            return new KeyguardManager();
-        } else if (ACCESSIBILITY_SERVICE.equals(name)) {
-            return AccessibilityManager.getInstance(this);
-        } else if (LOCATION_SERVICE.equals(name)) {
-            return getLocationManager();
-        } else if (COUNTRY_DETECTOR.equals(name)) {
-            return getCountryDetector();
-        } else if (SEARCH_SERVICE.equals(name)) {
-            return getSearchManager();
-        } else if (SENSOR_SERVICE.equals(name)) {
-            return getSensorManager();
-        } else if (STORAGE_SERVICE.equals(name)) {
-            return getStorageManager();
-        } else if (VIBRATOR_SERVICE.equals(name)) {
-            return getVibrator();
-        } else if (STATUS_BAR_SERVICE.equals(name)) {
-            synchronized (mSync) {
-                if (mStatusBarManager == null) {
-                    mStatusBarManager = new StatusBarManager(getOuterContext());
-                }
-                return mStatusBarManager;
-            }
-        } else if (AUDIO_SERVICE.equals(name)) {
-            return getAudioManager();
-        } else if (TELEPHONY_SERVICE.equals(name)) {
-            return getTelephonyManager();
-        } else if (CLIPBOARD_SERVICE.equals(name)) {
-            return getClipboardManager();
-        } else if (WALLPAPER_SERVICE.equals(name)) {
-            return getWallpaperManager();
-        } else if (DROPBOX_SERVICE.equals(name)) {
-            return getDropBoxManager();
-        } else if (DEVICE_POLICY_SERVICE.equals(name)) {
-            return getDevicePolicyManager();
-        } else if (UI_MODE_SERVICE.equals(name)) {
-            return getUiModeManager();
-        } else if (DOWNLOAD_SERVICE.equals(name)) {
-            return getDownloadManager();
-        }
-
-        return null;
-    }
-
-    private AccountManager getAccountManager() {
-        synchronized (mSync) {
-            if (mAccountManager == null) {
-                IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
-                IAccountManager service = IAccountManager.Stub.asInterface(b);
-                mAccountManager = new AccountManager(this, service);
-            }
-            return mAccountManager;
-        }
-    }
-
-    private ActivityManager getActivityManager() {
-        synchronized (mSync) {
-            if (mActivityManager == null) {
-                mActivityManager = new ActivityManager(getOuterContext(),
-                        mMainThread.getHandler());
-            }
-        }
-        return mActivityManager;
-    }
-
-    private AlarmManager getAlarmManager() {
-        synchronized (sSync) {
-            if (sAlarmManager == null) {
-                IBinder b = ServiceManager.getService(ALARM_SERVICE);
-                IAlarmManager service = IAlarmManager.Stub.asInterface(b);
-                sAlarmManager = new AlarmManager(service);
-            }
-        }
-        return sAlarmManager;
-    }
-
-    private PowerManager getPowerManager() {
-        synchronized (sSync) {
-            if (sPowerManager == null) {
-                IBinder b = ServiceManager.getService(POWER_SERVICE);
-                IPowerManager service = IPowerManager.Stub.asInterface(b);
-                sPowerManager = new PowerManager(service, mMainThread.getHandler());
-            }
-        }
-        return sPowerManager;
-    }
-
-    private ConnectivityManager getConnectivityManager()
-    {
-        synchronized (sSync) {
-            if (sConnectivityManager == null) {
-                IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
-                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-                sConnectivityManager = new ConnectivityManager(service);
-            }
-        }
-        return sConnectivityManager;
-    }
-
-    private ThrottleManager getThrottleManager()
-    {
-        synchronized (sSync) {
-            if (sThrottleManager == null) {
-                IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
-                IThrottleManager service = IThrottleManager.Stub.asInterface(b);
-                sThrottleManager = new ThrottleManager(service);
-            }
-        }
-        return sThrottleManager;
-    }
-
-    private WifiManager getWifiManager()
-    {
-        synchronized (sSync) {
-            if (sWifiManager == null) {
-                IBinder b = ServiceManager.getService(WIFI_SERVICE);
-                IWifiManager service = IWifiManager.Stub.asInterface(b);
-                sWifiManager = new WifiManager(service, mMainThread.getHandler());
-            }
-        }
-        return sWifiManager;
-    }
-
-    private NotificationManager getNotificationManager() {
-        synchronized (mSync) {
-            if (mNotificationManager == null) {
-                final Context outerContext = getOuterContext();
-                mNotificationManager = new NotificationManager(
-                        new ContextThemeWrapper(outerContext,
-                                outerContext.getApplicationInfo().targetSdkVersion >=
-                                    Build.VERSION_CODES.HONEYCOMB
-                                ? com.android.internal.R.style.Theme_Holo_Dialog
-                                : com.android.internal.R.style.Theme_Dialog),
-                        mMainThread.getHandler());
-            }
-        }
-        return mNotificationManager;
+        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
+        return fetcher == null ? null : fetcher.getService(this);
     }
 
     private WallpaperManager getWallpaperManager() {
-        synchronized (mSync) {
-            if (mWallpaperManager == null) {
-                mWallpaperManager = new WallpaperManager(getOuterContext(),
-                        mMainThread.getHandler());
-            }
-        }
-        return mWallpaperManager;
-    }
-
-    private TelephonyManager getTelephonyManager() {
-        synchronized (mSync) {
-            if (mTelephonyManager == null) {
-                mTelephonyManager = new TelephonyManager(getOuterContext());
-            }
-        }
-        return mTelephonyManager;
-    }
-
-    private ClipboardManager getClipboardManager() {
-        synchronized (mSync) {
-            if (mClipboardManager == null) {
-                mClipboardManager = new ClipboardManager(getOuterContext(),
-                        mMainThread.getHandler());
-            }
-        }
-        return mClipboardManager;
-    }
-
-    private LocationManager getLocationManager() {
-        synchronized (sSync) {
-            if (sLocationManager == null) {
-                IBinder b = ServiceManager.getService(LOCATION_SERVICE);
-                ILocationManager service = ILocationManager.Stub.asInterface(b);
-                sLocationManager = new LocationManager(service);
-            }
-        }
-        return sLocationManager;
-    }
-
-    private CountryDetector getCountryDetector() {
-        synchronized (sSync) {
-            if (sCountryDetector == null) {
-                IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
-                ICountryDetector service = ICountryDetector.Stub.asInterface(b);
-                sCountryDetector = new CountryDetector(service);
-            }
-        }
-        return sCountryDetector;
-    }
-
-    private SearchManager getSearchManager() {
-        synchronized (mSync) {
-            if (mSearchManager == null) {
-                mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
-            }
-        }
-        return mSearchManager;
-    }
-
-    private SensorManager getSensorManager() {
-        synchronized (mSync) {
-            if (mSensorManager == null) {
-                mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
-            }
-        }
-        return mSensorManager;
-    }
-
-    private StorageManager getStorageManager() {
-        synchronized (mSync) {
-            if (mStorageManager == null) {
-                try {
-                    mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
-                } catch (RemoteException rex) {
-                    Log.e(TAG, "Failed to create StorageManager", rex);
-                    mStorageManager = null;
-                }
-            }
-        }
-        return mStorageManager;
-    }
-
-    private Vibrator getVibrator() {
-        synchronized (mSync) {
-            if (mVibrator == null) {
-                mVibrator = new Vibrator();
-            }
-        }
-        return mVibrator;
-    }
-
-    private AudioManager getAudioManager()
-    {
-        if (mAudioManager == null) {
-            mAudioManager = new AudioManager(this);
-        }
-        return mAudioManager;
+        return (WallpaperManager) WALLPAPER_FETCHER.getService(this);
     }
 
     /* package */ static DropBoxManager createDropBoxManager() {
@@ -1177,43 +1148,6 @@
         return new DropBoxManager(service);
     }
 
-    private DropBoxManager getDropBoxManager() {
-        synchronized (mSync) {
-            if (mDropBoxManager == null) {
-                mDropBoxManager = createDropBoxManager();
-            }
-        }
-        return mDropBoxManager;
-    }
-
-    private DevicePolicyManager getDevicePolicyManager() {
-        synchronized (mSync) {
-            if (mDevicePolicyManager == null) {
-                mDevicePolicyManager = DevicePolicyManager.create(this,
-                        mMainThread.getHandler());
-            }
-        }
-        return mDevicePolicyManager;
-    }
-
-    private UiModeManager getUiModeManager() {
-        synchronized (mSync) {
-            if (mUiModeManager == null) {
-                mUiModeManager = new UiModeManager();
-            }
-        }
-        return mUiModeManager;
-    }
-
-    private DownloadManager getDownloadManager() {
-        synchronized (mSync) {
-            if (mDownloadManager == null) {
-                mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
-            }
-        }
-        return mDownloadManager;
-    }
-
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 526129a..64a4d7a 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -867,13 +867,19 @@
         }
     }
 
-    public ActionMode onStartActionMode(ActionMode.Callback callback) {
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         if (mActionBar != null) {
             return mActionBar.startActionMode(callback);
         }
         return null;
     }
 
+    public void onActionModeStarted(ActionMode mode) {
+    }
+
+    public void onActionModeFinished(ActionMode mode) {
+    }
+
     /**
      * @return The activity associated with this dialog, or null if there is no associated activity.
      */
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 01414fa..6e18533 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -33,10 +33,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /**
  * The download manager is a system service that handles long-running HTTP downloads. Clients may
@@ -281,46 +278,32 @@
      */
     public static final String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
 
-    // this array must contain all public columns
-    private static final String[] COLUMNS = new String[] {
-        COLUMN_ID,
-        COLUMN_MEDIAPROVIDER_URI,
-        Downloads.Impl.COLUMN_DESTINATION,
-        COLUMN_TITLE,
-        COLUMN_DESCRIPTION,
-        COLUMN_URI,
-        COLUMN_MEDIA_TYPE,
-        COLUMN_TOTAL_SIZE_BYTES,
-        COLUMN_LOCAL_URI,
-        COLUMN_STATUS,
-        COLUMN_REASON,
-        COLUMN_BYTES_DOWNLOADED_SO_FAR,
-        COLUMN_LAST_MODIFIED_TIMESTAMP,
-        COLUMN_LOCAL_FILENAME,
-    };
-
-    // columns to request from DownloadProvider
-    private static final String[] UNDERLYING_COLUMNS = new String[] {
+    /**
+     * columns to request from DownloadProvider.
+     * @hide
+     */
+    public static final String[] UNDERLYING_COLUMNS = new String[] {
         Downloads.Impl._ID,
+        Downloads.Impl._DATA + " AS " + COLUMN_LOCAL_FILENAME,
         Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
         Downloads.Impl.COLUMN_DESTINATION,
         Downloads.Impl.COLUMN_TITLE,
         Downloads.Impl.COLUMN_DESCRIPTION,
         Downloads.Impl.COLUMN_URI,
-        Downloads.Impl.COLUMN_MIME_TYPE,
-        Downloads.Impl.COLUMN_TOTAL_BYTES,
         Downloads.Impl.COLUMN_STATUS,
-        Downloads.Impl.COLUMN_CURRENT_BYTES,
-        Downloads.Impl.COLUMN_LAST_MODIFICATION,
         Downloads.Impl.COLUMN_FILE_NAME_HINT,
-        Downloads.Impl._DATA,
+        Downloads.Impl.COLUMN_MIME_TYPE + " AS " + COLUMN_MEDIA_TYPE,
+        Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + COLUMN_TOTAL_SIZE_BYTES,
+        Downloads.Impl.COLUMN_LAST_MODIFICATION + " AS " + COLUMN_LAST_MODIFIED_TIMESTAMP,
+        Downloads.Impl.COLUMN_CURRENT_BYTES + " AS " + COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        /* add the following 'computed' columns to the cursor.
+         * they are not 'returned' by the database, but their inclusion
+         * eliminates need to have lot of methods in CursorTranslator
+         */
+        "'placeholder' AS " + COLUMN_LOCAL_URI,
+        "'placeholder' AS " + COLUMN_REASON
     };
 
-    private static final Set<String> LONG_COLUMNS = new HashSet<String>(
-            Arrays.asList(COLUMN_ID, COLUMN_TOTAL_SIZE_BYTES, COLUMN_STATUS, COLUMN_REASON,
-                          COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_LAST_MODIFIED_TIMESTAMP,
-                          Downloads.Impl.COLUMN_DESTINATION));
-
     /**
      * This class contains all the information necessary to request a new download. The URI is the
      * only required parameter.
@@ -871,11 +854,7 @@
      * @return the number of downloads actually removed
      */
     public int remove(long... ids) {
-        if (ids == null || ids.length == 0) {
-            // called with nothing to remove!
-            throw new IllegalArgumentException("input param 'ids' can't be null");
-        }
-        return mResolver.delete(mBaseUri, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
+        return markRowDeleted(ids);
     }
 
     /**
@@ -1032,117 +1011,32 @@
         }
 
         @Override
-        public int getColumnIndex(String columnName) {
-            return Arrays.asList(COLUMNS).indexOf(columnName);
-        }
-
-        @Override
-        public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
-            int index = getColumnIndex(columnName);
-            if (index == -1) {
-                throw new IllegalArgumentException("No such column: " + columnName);
-            }
-            return index;
-        }
-
-        @Override
-        public String getColumnName(int columnIndex) {
-            int numColumns = COLUMNS.length;
-            if (columnIndex < 0 || columnIndex >= numColumns) {
-                throw new IllegalArgumentException("Invalid column index " + columnIndex + ", "
-                                                   + numColumns + " columns exist");
-            }
-            return COLUMNS[columnIndex];
-        }
-
-        @Override
-        public String[] getColumnNames() {
-            String[] returnColumns = new String[COLUMNS.length];
-            System.arraycopy(COLUMNS, 0, returnColumns, 0, COLUMNS.length);
-            return returnColumns;
-        }
-
-        @Override
-        public int getColumnCount() {
-            return COLUMNS.length;
-        }
-
-        @Override
-        public byte[] getBlob(int columnIndex) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public double getDouble(int columnIndex) {
-            return getLong(columnIndex);
-        }
-
-        private boolean isLongColumn(String column) {
-            return LONG_COLUMNS.contains(column);
-        }
-
-        @Override
-        public float getFloat(int columnIndex) {
-            return (float) getDouble(columnIndex);
-        }
-
-        @Override
         public int getInt(int columnIndex) {
             return (int) getLong(columnIndex);
         }
 
         @Override
         public long getLong(int columnIndex) {
-            return translateLong(getColumnName(columnIndex));
-        }
-
-        @Override
-        public short getShort(int columnIndex) {
-            return (short) getLong(columnIndex);
+            if (getColumnName(columnIndex).equals(COLUMN_REASON)) {
+                return getReason(super.getInt(getColumnIndex(Downloads.Impl.COLUMN_STATUS)));
+            } else if (getColumnName(columnIndex).equals(COLUMN_STATUS)) {
+                return translateStatus(super.getInt(getColumnIndex(Downloads.Impl.COLUMN_STATUS)));
+            } else {
+                return super.getLong(columnIndex);
+            }
         }
 
         @Override
         public String getString(int columnIndex) {
-            return translateString(getColumnName(columnIndex));
-        }
-
-        private String translateString(String column) {
-            if (isLongColumn(column)) {
-                return Long.toString(translateLong(column));
-            }
-            if (column.equals(COLUMN_TITLE)) {
-                return getUnderlyingString(Downloads.Impl.COLUMN_TITLE);
-            }
-            if (column.equals(COLUMN_DESCRIPTION)) {
-                return getUnderlyingString(Downloads.Impl.COLUMN_DESCRIPTION);
-            }
-            if (column.equals(COLUMN_URI)) {
-                return getUnderlyingString(Downloads.Impl.COLUMN_URI);
-            }
-            if (column.equals(COLUMN_MEDIA_TYPE)) {
-                return getUnderlyingString(Downloads.Impl.COLUMN_MIME_TYPE);
-            }
-            if (column.equals(COLUMN_LOCAL_FILENAME)) {
-                return getUnderlyingString(Downloads.Impl._DATA);
-            }
-            if (column.equals(COLUMN_MEDIAPROVIDER_URI)) {
-                return getUnderlyingString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
-            }
-
-            assert column.equals(COLUMN_LOCAL_URI);
-            return getLocalUri();
+            return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() :
+                    super.getString(columnIndex);
         }
 
         private String getLocalUri() {
-            long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
-            if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
-                // return client-provided file URI for external download
-                return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
-            }
-
-            if (destinationType == Downloads.Impl.DESTINATION_EXTERNAL) {
-                // return stored destination for legacy external download
-                String localPath = getUnderlyingString(Downloads.Impl._DATA);
+            long destinationType = getLong(getColumnIndex(Downloads.Impl.COLUMN_DESTINATION));
+            if (destinationType == Downloads.Impl.DESTINATION_FILE_URI ||
+                    destinationType == Downloads.Impl.DESTINATION_EXTERNAL) {
+                String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
                 if (localPath == null) {
                     return null;
                 }
@@ -1150,38 +1044,10 @@
             }
 
             // return content URI for cache download
-            long downloadId = getUnderlyingLong(Downloads.Impl._ID);
+            long downloadId = getLong(getColumnIndex(Downloads.Impl._ID));
             return ContentUris.withAppendedId(mBaseUri, downloadId).toString();
         }
 
-        private long translateLong(String column) {
-            if (!isLongColumn(column)) {
-                // mimic behavior of underlying cursor -- most likely, throw NumberFormatException
-                return Long.valueOf(translateString(column));
-            }
-
-            if (column.equals(COLUMN_ID)) {
-                return getUnderlyingLong(Downloads.Impl._ID);
-            }
-            if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
-                return getUnderlyingLong(Downloads.Impl.COLUMN_TOTAL_BYTES);
-            }
-            if (column.equals(COLUMN_STATUS)) {
-                return translateStatus((int) getUnderlyingLong(Downloads.Impl.COLUMN_STATUS));
-            }
-            if (column.equals(COLUMN_REASON)) {
-                return getReason((int) getUnderlyingLong(Downloads.Impl.COLUMN_STATUS));
-            }
-            if (column.equals(COLUMN_BYTES_DOWNLOADED_SO_FAR)) {
-                return getUnderlyingLong(Downloads.Impl.COLUMN_CURRENT_BYTES);
-            }
-            if (column.equals(Downloads.Impl.COLUMN_DESTINATION)) {
-                return getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
-            }
-            assert column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP);
-            return getUnderlyingLong(Downloads.Impl.COLUMN_LAST_MODIFICATION);
-        }
-
         private long getReason(int status) {
             switch (translateStatus(status)) {
                 case STATUS_FAILED:
@@ -1249,14 +1115,6 @@
             }
         }
 
-        private long getUnderlyingLong(String column) {
-            return super.getLong(super.getColumnIndex(column));
-        }
-
-        private String getUnderlyingString(String column) {
-            return super.getString(super.getColumnIndex(column));
-        }
-
         private int translateStatus(int status) {
             switch (status) {
                 case Downloads.Impl.STATUS_PENDING:
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 9970418..d3a4f33 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -22,6 +22,7 @@
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -99,6 +100,20 @@
     public abstract FragmentTransaction openTransaction();
 
     /**
+     * After a {@link FragmentTransaction} is committed with
+     * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
+     * is scheduled to be executed asynchronously on the process's main thread.
+     * If you want to immediately executing any such pending operations, you
+     * can call this function (only from the main thread) to do so.  Note that
+     * all callbacks and other related behavior will be done from within this
+     * call, so be careful about where this is called from.
+     *
+     * @return Returns true if there were any pending transactions to be
+     * executed.
+     */
+    public abstract boolean executePendingTransactions();
+
+    /**
      * Finds a fragment that was identified by the given id either when inflated
      * from XML or as the container ID when added in a transaction.  This first
      * searches through fragments that are currently added to the manager's
@@ -132,7 +147,15 @@
      * Pop the top state off the back stack.  Returns true if there was one
      * to pop, else false.
      */
-    public abstract boolean popBackStack();
+    public abstract void popBackStack();
+
+    /**
+     * Like {@link #popBackStack()}, but performs the operation immediately
+     * inside of the call.  This is like calling {@link #executePendingTransactions()}
+     * afterwards.
+     * @return Returns true if there was something popped, else false.
+     */
+    public abstract boolean popBackStackImmediate();
 
     /**
      * Pop the last fragment transition from the manager's fragment
@@ -143,7 +166,15 @@
      * the named state itself is popped. If null, only the top state is popped.
      * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
      */
-    public abstract boolean popBackStack(String name, int flags);
+    public abstract void popBackStack(String name, int flags);
+
+    /**
+     * Like {@link #popBackStack(String, int)}, but performs the operation immediately
+     * inside of the call.  This is like calling {@link #executePendingTransactions()}
+     * afterwards.
+     * @return Returns true if there was something popped, else false.
+     */
+    public abstract boolean popBackStackImmediate(String name, int flags);
 
     /**
      * Pop all back stack states up to the one with the given identifier.
@@ -155,7 +186,15 @@
      * the named state itself is popped.
      * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
      */
-    public abstract boolean popBackStack(int id, int flags);
+    public abstract void popBackStack(int id, int flags);
+
+    /**
+     * Like {@link #popBackStack(int, int)}, but performs the operation immediately
+     * inside of the call.  This is like calling {@link #executePendingTransactions()}
+     * afterwards.
+     * @return Returns true if there was something popped, else false.
+     */
+    public abstract boolean popBackStackImmediate(int id, int flags);
 
     /**
      * Return the number of entries currently in the back stack.
@@ -300,17 +339,58 @@
     }
 
     @Override
-    public boolean popBackStack() {
+    public boolean executePendingTransactions() {
+        return execPendingActions();
+    }
+
+    @Override
+    public void popBackStack() {
+        enqueueAction(new Runnable() {
+            @Override public void run() {
+                popBackStackState(mActivity.mHandler, null, -1, 0);
+            }
+        }, false);
+    }
+
+    @Override
+    public boolean popBackStackImmediate() {
+        checkStateLoss();
+        executePendingTransactions();
         return popBackStackState(mActivity.mHandler, null, -1, 0);
     }
 
     @Override
-    public boolean popBackStack(String name, int flags) {
+    public void popBackStack(final String name, final int flags) {
+        enqueueAction(new Runnable() {
+            @Override public void run() {
+                popBackStackState(mActivity.mHandler, name, -1, flags);
+            }
+        }, false);
+    }
+
+    @Override
+    public boolean popBackStackImmediate(String name, int flags) {
+        checkStateLoss();
+        executePendingTransactions();
         return popBackStackState(mActivity.mHandler, name, -1, flags);
     }
 
     @Override
-    public boolean popBackStack(int id, int flags) {
+    public void popBackStack(final int id, final int flags) {
+        if (id < 0) {
+            throw new IllegalArgumentException("Bad id: " + id);
+        }
+        enqueueAction(new Runnable() {
+            @Override public void run() {
+                popBackStackState(mActivity.mHandler, null, id, flags);
+            }
+        }, false);
+    }
+
+    @Override
+    public boolean popBackStackImmediate(int id, int flags) {
+        checkStateLoss();
+        executePendingTransactions();
         if (id < 0) {
             throw new IllegalArgumentException("Bad id: " + id);
         }
@@ -849,16 +929,20 @@
         return null;
     }
     
+    private void checkStateLoss() {
+        if (mStateSaved) {
+            throw new IllegalStateException(
+                    "Can not perform this action after onSaveInstanceState");
+        }
+        if (mNoTransactionsBecause != null) {
+            throw new IllegalStateException(
+                    "Can not perform this action inside of " + mNoTransactionsBecause);
+        }
+    }
+
     public void enqueueAction(Runnable action, boolean allowStateLoss) {
         if (!allowStateLoss) {
-            if (mStateSaved) {
-                throw new IllegalStateException(
-                        "Can not perform this action after onSaveInstanceState");
-            }
-            if (mNoTransactionsBecause != null) {
-                throw new IllegalStateException(
-                        "Can not perform this action inside of " + mNoTransactionsBecause);
-            }
+            checkStateLoss();
         }
         synchronized (this) {
             if (mActivity == null) {
@@ -934,17 +1018,23 @@
     /**
      * Only call from main thread!
      */
-    public void execPendingActions() {
+    public boolean execPendingActions() {
         if (mExecutingActions) {
-            throw new IllegalStateException("Recursive entry to execPendingActions");
+            throw new IllegalStateException("Recursive entry to executePendingTransactions");
         }
         
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            throw new IllegalStateException("Must be called from main thread of process");
+        }
+
+        boolean didSomething = false;
+
         while (true) {
             int numActions;
             
             synchronized (this) {
                 if (mPendingActions == null || mPendingActions.size() == 0) {
-                    return;
+                    return didSomething;
                 }
                 
                 numActions = mPendingActions.size();
@@ -961,6 +1051,7 @@
                 mTmpActions[i].run();
             }
             mExecutingActions = false;
+            didSomething = true;
         }
     }
     
@@ -984,19 +1075,14 @@
         if (mBackStack == null) {
             return false;
         }
-        if (name == null && id < 0 && (flags&Activity.POP_BACK_STACK_INCLUSIVE) == 0) {
+        if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
             int last = mBackStack.size()-1;
             if (last < 0) {
                 return false;
             }
             final BackStackRecord bss = mBackStack.remove(last);
-            enqueueAction(new Runnable() {
-                public void run() {
-                    if (DEBUG) Log.v(TAG, "Popping back stack state: " + bss);
-                    bss.popFromBackStack(true);
-                    reportBackStackChanged();
-                }
-            }, false);
+            bss.popFromBackStack(true);
+            reportBackStackChanged();
         } else {
             int index = -1;
             if (name != null || id >= 0) {
@@ -1016,7 +1102,7 @@
                 if (index < 0) {
                     return false;
                 }
-                if ((flags&Activity.POP_BACK_STACK_INCLUSIVE) != 0) {
+                if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
                     index--;
                     // Consume all following entries that match.
                     while (index >= 0) {
@@ -1038,16 +1124,12 @@
             for (int i=mBackStack.size()-1; i>index; i--) {
                 states.add(mBackStack.remove(i));
             }
-            enqueueAction(new Runnable() {
-                public void run() {
-                    final int LAST = states.size()-1;
-                    for (int i=0; i<=LAST; i++) {
-                        if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
-                        states.get(i).popFromBackStack(i == LAST);
-                    }
-                    reportBackStackChanged();
-                }
-            }, false);
+            final int LAST = states.size()-1;
+            for (int i=0; i<=LAST; i++) {
+                if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
+                states.get(i).popFromBackStack(i == LAST);
+            }
+            reportBackStackChanged();
         }
         return true;
     }
@@ -1084,6 +1166,10 @@
     }
     
     Parcelable saveAllState() {
+        // Make sure all pending operations have now been executed to get
+        // our state update-to-date.
+        execPendingActions();
+
         mStateSaved = true;
 
         if (mActive == null || mActive.size() <= 0) {
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index 4c5d28e..af1b294 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -42,7 +42,7 @@
  */
 public class ProgressDialog extends AlertDialog {
     
-    /** Creates a ProgressDialog with a ciruclar, spinning progress
+    /** Creates a ProgressDialog with a circular, spinning progress
      * bar. This is the default.
      */
     public static final int STYLE_SPINNER = 0;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 41bb364..7efb7fd 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1081,7 +1081,7 @@
                 mConnectionPool.close();
             }
         } finally {
-            unlock();            
+            unlock();
         }
     }
 
@@ -1772,8 +1772,7 @@
      */
     public int updateWithOnConflict(String table, ContentValues values,
             String whereClause, String[] whereArgs, int conflictAlgorithm) {
-        int setValuesSize = values.size();
-        if (values == null || setValuesSize == 0) {
+        if (values == null || values.size() == 0) {
             throw new IllegalArgumentException("Empty values");
         }
 
@@ -1784,6 +1783,7 @@
         sql.append(" SET ");
 
         // move all bind args to one array
+        int setValuesSize = values.size();
         int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
         Object[] bindArgs = new Object[bindArgsSize];
         int i = 0;
@@ -2118,7 +2118,7 @@
 
             int maxCacheSz = (mConnectionNum == 0) ? mMaxSqlCacheSize :
                     mParentConnObj.mMaxSqlCacheSize;
-            
+
             if (SQLiteDebug.DEBUG_SQL_CACHE) {
                 boolean printWarning = (mConnectionNum == 0)
                         ? (!mCacheFullWarning && mCompiledQueries.size() == maxCacheSz)
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
index 43fb5f1..95cecd2 100644
--- a/core/java/android/net/http/Connection.java
+++ b/core/java/android/net/http/Connection.java
@@ -437,8 +437,7 @@
             ret = false;
             String error;
             if (errorId < 0) {
-                error = mContext.getText(
-                        EventHandler.errorStringResources[-errorId]).toString();
+                error = ErrorStrings.getString(errorId, mContext);
             } else {
                 Throwable cause = e.getCause();
                 error = cause != null ? cause.toString() : e.getMessage();
diff --git a/core/java/android/net/http/ErrorStrings.java b/core/java/android/net/http/ErrorStrings.java
new file mode 100644
index 0000000..8383681
--- /dev/null
+++ b/core/java/android/net/http/ErrorStrings.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.net.http;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Localized strings for the error codes defined in EventHandler.
+ *
+ * {@hide}
+ */
+public class ErrorStrings {
+    private ErrorStrings() { /* Utility class, don't instantiate. */ }
+
+    private static final String LOGTAG = "Http";
+
+    /**
+     * Get the localized error message resource for the given error code.
+     * If the code is unknown, we'll return a generic error message.
+     */
+    public static String getString(int errorCode, Context context) {
+        return context.getText(getResource(errorCode)).toString();
+    }
+
+    /**
+     * Get the localized error message resource for the given error code.
+     * If the code is unknown, we'll return a generic error message.
+     */
+    public static int getResource(int errorCode) {
+        switch(errorCode) {
+            case EventHandler.OK:
+                return com.android.internal.R.string.httpErrorOk;
+
+            case EventHandler.ERROR:
+                return com.android.internal.R.string.httpError;
+
+            case EventHandler.ERROR_LOOKUP:
+                return com.android.internal.R.string.httpErrorLookup;
+
+            case EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME:
+                return com.android.internal.R.string.httpErrorUnsupportedAuthScheme;
+
+            case EventHandler.ERROR_AUTH:
+                return com.android.internal.R.string.httpErrorAuth;
+
+            case EventHandler.ERROR_PROXYAUTH:
+                return com.android.internal.R.string.httpErrorProxyAuth;
+
+            case EventHandler.ERROR_CONNECT:
+                return com.android.internal.R.string.httpErrorConnect;
+
+            case EventHandler.ERROR_IO:
+                return com.android.internal.R.string.httpErrorIO;
+
+            case EventHandler.ERROR_TIMEOUT:
+                return com.android.internal.R.string.httpErrorTimeout;
+
+            case EventHandler.ERROR_REDIRECT_LOOP:
+                return com.android.internal.R.string.httpErrorRedirectLoop;
+
+            case EventHandler.ERROR_UNSUPPORTED_SCHEME:
+                return com.android.internal.R.string.httpErrorUnsupportedScheme;
+
+            case EventHandler.ERROR_FAILED_SSL_HANDSHAKE:
+                return com.android.internal.R.string.httpErrorFailedSslHandshake;
+
+            case EventHandler.ERROR_BAD_URL:
+                return com.android.internal.R.string.httpErrorBadUrl;
+
+            case EventHandler.FILE_ERROR:
+                return com.android.internal.R.string.httpErrorFile;
+
+            case EventHandler.FILE_NOT_FOUND_ERROR:
+                return com.android.internal.R.string.httpErrorFileNotFound;
+
+            case EventHandler.TOO_MANY_REQUESTS_ERROR:
+                return com.android.internal.R.string.httpErrorTooManyRequests;
+
+            default:
+                Log.w(LOGTAG, "Using generic message for unknown error code: " + errorCode);
+                return com.android.internal.R.string.httpError;
+        }
+    }
+}
diff --git a/core/java/android/net/http/EventHandler.java b/core/java/android/net/http/EventHandler.java
index 2aa05eb..3fd471d 100644
--- a/core/java/android/net/http/EventHandler.java
+++ b/core/java/android/net/http/EventHandler.java
@@ -68,25 +68,6 @@
     /** Too many requests queued */
     public static final int TOO_MANY_REQUESTS_ERROR = -15;
 
-    final static int[] errorStringResources = {
-        com.android.internal.R.string.httpErrorOk,
-        com.android.internal.R.string.httpError,
-        com.android.internal.R.string.httpErrorLookup,
-        com.android.internal.R.string.httpErrorUnsupportedAuthScheme,
-        com.android.internal.R.string.httpErrorAuth,
-        com.android.internal.R.string.httpErrorProxyAuth,
-        com.android.internal.R.string.httpErrorConnect,
-        com.android.internal.R.string.httpErrorIO,
-        com.android.internal.R.string.httpErrorTimeout,
-        com.android.internal.R.string.httpErrorRedirectLoop,
-        com.android.internal.R.string.httpErrorUnsupportedScheme,
-        com.android.internal.R.string.httpErrorFailedSslHandshake,
-        com.android.internal.R.string.httpErrorBadUrl,
-        com.android.internal.R.string.httpErrorFile,
-        com.android.internal.R.string.httpErrorFileNotFound,
-        com.android.internal.R.string.httpErrorTooManyRequests
-    };
-
     /**
      * Called after status line has been sucessfully processed.
      * @param major_version HTTP version advertised by server.  major
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index a47c66a..47a7696 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -169,7 +169,12 @@
                 is = getInputStream();
                 if (is == null) return null;
                 byte[] buf = new byte[maxBytes];
-                return new String(buf, 0, Math.max(0, is.read(buf)));
+                int readBytes = 0;
+                int n = 0;
+                while (n >= 0 && (readBytes += n) < maxBytes) {
+                    n = is.read(buf, readBytes, maxBytes - readBytes);
+                }
+                return new String(buf, 0, readBytes);
             } catch (IOException e) {
                 return null;
             } finally {
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 22876c0..97f015b 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -106,6 +106,8 @@
     private static final String TAG = "StrictMode";
     private static final boolean LOG_V = false;
 
+    private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
+
     // Only log a duplicate stack trace to the logs every second.
     private static final long MIN_LOG_INTERVAL_MS = 1000;
 
@@ -605,7 +607,7 @@
 
     // Sets up CloseGuard in Dalvik/libcore
     private static void setCloseGuardEnabled(boolean enabled) {
-        if (!(CloseGuard.getReporter() instanceof AndroidBlockGuardPolicy)) {
+        if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) {
             CloseGuard.setReporter(new AndroidCloseGuardReporter());
         }
         CloseGuard.setEnabled(enabled);
@@ -693,7 +695,8 @@
     public static boolean conditionallyEnableDebugLogging() {
         // For debug builds, log event loop stalls to dropbox for analysis.
         // Similar logic also appears in ActivityThread.java for system apps.
-        if ("user".equals(Build.TYPE)) {
+        if (IS_USER_BUILD) {
+            setCloseGuardEnabled(false);
             return false;
         }
         StrictMode.setThreadPolicyMask(
@@ -705,6 +708,7 @@
                 StrictMode.DETECT_VM_CLOSABLE_LEAKS |
                 StrictMode.PENALTY_DROPBOX |
                 StrictMode.PENALTY_LOG;
+        setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
         return true;
     }
 
@@ -1238,6 +1242,11 @@
             mContainerState = threadState;
         }
 
+        // Empty constructor for the NO_OP_SPAN
+        protected Span() {
+            mContainerState = null;
+        }
+
         /**
          * To be called when the critical span is complete (i.e. the
          * animation is done animating).  This can be called on any
@@ -1284,6 +1293,13 @@
         }
     }
 
+    // The no-op span that's used in user builds.
+    private static final Span NO_OP_SPAN = new Span() {
+            public void finish() {
+                // Do nothing.
+            }
+        };
+
     /**
      * Linked lists of active spans and a freelist.
      *
@@ -1325,6 +1341,9 @@
      * @hide
      */
     public static Span enterCriticalSpan(String name) {
+        if (IS_USER_BUILD) {
+            return NO_OP_SPAN;
+        }
         if (name == null || name.isEmpty()) {
             throw new IllegalArgumentException("name must be non-null and non-empty");
         }
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0ce69ad..39f3cee 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -23,6 +23,7 @@
 
 import android.app.Fragment;
 import android.app.FragmentBreadCrumbs;
+import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.app.ListActivity;
 import android.content.Context;
@@ -902,7 +903,8 @@
     }
 
     private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
-        getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+        getFragmentManager().popBackStack(BACK_STACK_PREFS,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
         Fragment f = Fragment.instantiate(this, fragmentName, args);
         FragmentTransaction transaction = getFragmentManager().openTransaction();
         transaction.setTransition(direction == 0 ? FragmentTransaction.TRANSIT_NONE
@@ -934,7 +936,8 @@
         if (mCurHeader == header) {
             // This is the header we are currently displaying.  Just make sure
             // to pop the stack up to its root state.
-            getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+            getFragmentManager().popBackStack(BACK_STACK_PREFS,
+                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
         } else {
             int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
             switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
@@ -1061,14 +1064,14 @@
             setResult(resultCode, resultData);
             finish();
         } else {
+            // XXX be smarter about popping the stack.
+            onBackPressed();
             if (caller != null) {
                 if (caller.getTargetFragment() != null) {
                     caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
                             resultCode, resultData);
                 }
             }
-            // XXX be smarter about popping the stack.
-            onBackPressed();
         }
     }
     
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a54f342..dd0f477 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -79,7 +79,7 @@
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
             CharSequence nonLocalizedLabel, int labelRes,
-            int icon, IBinder transferFrom, boolean createIfNeeded);
+            int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppWillBeHidden(IBinder token);
     void setAppVisibility(IBinder token, boolean visible);
     void startAppFreezingScreen(IBinder token, int configChanges);
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 99da43b..602c765 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -405,6 +405,11 @@
     
     /**
      * Sets how this item should display in the presence of an Action Bar.
+     * The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
+     * {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
+     * be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
+     * SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
+     * it should be shown with a text label.
      *
      * @param actionEnum How the item should display. One of
      * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 026f1a0..e6eb46e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1258,6 +1258,7 @@
     static final int VIEW_STATE_ENABLED = 1 << 3;
     static final int VIEW_STATE_PRESSED = 1 << 4;
     static final int VIEW_STATE_ACTIVATED = 1 << 5;
+    static final int VIEW_STATE_ACCELERATED = 1 << 6;
 
     static final int[] VIEW_STATE_IDS = new int[] {
         R.attr.state_window_focused,    VIEW_STATE_WINDOW_FOCUSED,
@@ -1266,9 +1267,14 @@
         R.attr.state_enabled,           VIEW_STATE_ENABLED,
         R.attr.state_pressed,           VIEW_STATE_PRESSED,
         R.attr.state_activated,         VIEW_STATE_ACTIVATED,
+        R.attr.state_accelerated,       VIEW_STATE_ACCELERATED,
     };
 
     static {
+        if ((VIEW_STATE_IDS.length/2) != R.styleable.ViewDrawableStates.length) {
+            throw new IllegalStateException(
+                    "VIEW_STATE_IDs array length does not match ViewDrawableStates style array");
+        }
         int[] orderedIds = new int[VIEW_STATE_IDS.length];
         for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) {
             int viewState = R.styleable.ViewDrawableStates[i];
@@ -6298,12 +6304,7 @@
             }
             final AttachInfo ai = mAttachInfo;
             final ViewParent p = mParent;
-            if (p != null && ai != null && ai.mHardwareAccelerated) {
-                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                // with a null dirty rect, which tells the ViewRoot to redraw everything
-                p.invalidateChild(this, null);
-                return;
-            }
+
             if (p != null && ai != null) {
                 final Rect r = ai.mTmpInvalRect;
                 r.set(0, 0, mRight - mLeft, mBottom - mTop);
@@ -7176,6 +7177,8 @@
         //System.out.println("Attached! " + this);
         mAttachInfo = info;
         mWindowAttachCount++;
+        // We will need to evaluate the drawable state at least once.
+        mPrivateFlags |= DRAWABLE_STATE_DIRTY;
         if (mFloatingTreeObserver != null) {
             info.mTreeObserver.merge(mFloatingTreeObserver);
             mFloatingTreeObserver = null;
@@ -7190,6 +7193,10 @@
         if (vis != GONE) {
             onWindowVisibilityChanged(vis);
         }
+        if ((mPrivateFlags&DRAWABLE_STATE_DIRTY) != 0) {
+            // If nobody has evaluated the drawable state yet, then do it now.
+            refreshDrawableState();
+        }
     }
 
     void dispatchDetachedFromWindow() {
@@ -8562,6 +8569,12 @@
         if ((privateFlags & SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED;
         if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED;
         if ((privateFlags & ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED;
+        if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) {
+            // This is set if HW acceleration is requested, even if the current
+            // process doesn't allow it.  This is just to allow app preview
+            // windows to better match their app.
+            viewStateIndex |= VIEW_STATE_ACCELERATED;
+        }
 
         drawableState = VIEW_STATE_SETS[viewStateIndex];
 
@@ -10503,6 +10516,7 @@
         Surface mSurface;
 
         boolean mHardwareAccelerated;
+        boolean mHardwareAccelerationRequested;
         HardwareRenderer mHardwareRenderer;
         
         /**
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e04916f..1972692 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -467,19 +467,25 @@
     }
 
     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
-        // Only enable hardware acceleration if we are not in the system process
-        // The window manager creates ViewRoots to display animated preview windows
-        // of launching apps and we don't want those to be hardware accelerated
-        if (!HardwareRenderer.sRendererDisabled) {
-            // Try to enable hardware acceleration if requested
-            if (attrs != null &&
-                    (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
+        mAttachInfo.mHardwareAccelerated = false;
+        mAttachInfo.mHardwareAccelerationRequested = false;
+        
+        // Try to enable hardware acceleration if requested
+        if (attrs != null &&
+                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
+            // Only enable hardware acceleration if we are not in the system process
+            // The window manager creates ViewRoots to display animated preview windows
+            // of launching apps and we don't want those to be hardware accelerated
+            if (!HardwareRenderer.sRendererDisabled) {
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
                 }                
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
-                mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareRenderer != null;
+                mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
+                        = mAttachInfo.mHardwareRenderer != null;
+            } else if (HardwareRenderer.isAvailable()) {
+                mAttachInfo.mHardwareAccelerationRequested = true;
             }
         }
     }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9fadc58..5385cd9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -313,12 +313,31 @@
         public boolean onSearchRequested();
 
         /**
-         * Called when an action mode is being started.
+         * Called when an action mode is being started for this window. Gives the
+         * callback an opportunity to handle the action mode in its own unique and
+         * beautiful way. If this method returns null the system can choose a way
+         * to present the mode or choose not to start the mode at all.
          *
          * @param callback Callback to control the lifecycle of this action mode
-         * @return The ActionMode that was started, or null if it was canceled
+         * @return The ActionMode that was started, or null if the system should present it
          */
-        public ActionMode onStartActionMode(ActionMode.Callback callback);
+        public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);
+
+        /**
+         * Called when an action mode has been started. The appropriate mode callback
+         * method will have already been invoked.
+         *
+         * @param mode The new mode that has just been started.
+         */
+        public void onActionModeStarted(ActionMode mode);
+
+        /**
+         * Called when an action mode has been finished. The appropriate mode callback
+         * method will have already been invoked.
+         *
+         * @param mode The mode that was just finished.
+         */
+        public void onActionModeFinished(ActionMode mode);
     }
 
     public Window(Context context) {
@@ -428,6 +447,10 @@
             mHardwareAccelerated = hardwareAccelerated;
         }
 
+        public boolean isHardwareAccelerated() {
+            return mHardwareAccelerated;
+        }
+        
         public final void addView(View view, ViewGroup.LayoutParams params) {
             // Let this throw an exception on a bad params.
             WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c657a1c..f9e7d18 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -65,6 +65,14 @@
      */
     public void removeViewImmediate(View view);
     
+    /**
+     * Return true if this window manager is configured to request hardware
+     * accelerated windows.  This does <em>not</em> guarantee that they will
+     * actually be accelerated, since that depends on the device supporting them.
+     * @hide
+     */
+    public boolean isHardwareAccelerated();
+    
     public static class LayoutParams extends ViewGroup.LayoutParams
             implements Parcelable {
         /**
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 0973599..07953d6 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -80,6 +80,10 @@
         return mWindowManager;
     }
     
+    public boolean isHardwareAccelerated() {
+        return false;
+    }
+    
     public void addView(View view)
     {
         addView(view, new WindowManager.LayoutParams(
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 4deff5e..5a9cd97 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -473,6 +473,7 @@
      *        no data is found in the resource.
      * @param labelRes The resource ID the application would like to use as its name.
      * @param icon The resource ID the application would like to use as its icon.
+     * @param windowFlags Window layout flags.
      * 
      * @return Optionally you can return the View that was used to create the
      *         window, for easy removal in removeStartingWindow.
@@ -481,7 +482,7 @@
      */
     public View addStartingWindow(IBinder appToken, String packageName,
             int theme, CharSequence nonLocalizedLabel,
-            int labelRes, int icon);
+            int labelRes, int icon, int windowFlags);
 
     /**
      * Called when the first window of an application has been displayed, while
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1d75b42..5e7a133 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1432,6 +1432,17 @@
         }
     }
 
+    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
+        synchronized (mH) {
+            try {
+                return mService.setCurrentInputMethodSubtype(subtype);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+                return false;
+            }
+        }
+    }
+
     public boolean switchToLastInputMethod(IBinder imeToken) {
         synchronized (mH) {
             try {
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index cce7914..d3c0ffd 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -26,6 +26,7 @@
 import android.net.ParseException;
 import android.net.Uri;
 import android.net.WebAddress;
+import android.net.http.ErrorStrings;
 import android.net.http.SslCertificate;
 import android.os.Handler;
 import android.os.Message;
@@ -323,16 +324,20 @@
      * native callback
      * Report an error to an activity.
      * @param errorCode The HTTP error code.
-     * @param description A String description.
+     * @param description Optional human-readable description. If no description
+     *     is given, we'll use a standard localized error message.
+     * @param failingUrl The URL that was being loaded when the error occurred.
      * TODO: Report all errors including resource errors but include some kind
      * of domain identifier. Change errorCode to an enum for a cleaner
      * interface.
      */
-    private void reportError(final int errorCode, final String description,
-            final String failingUrl) {
+    private void reportError(int errorCode, String description, String failingUrl) {
         // As this is called for the main resource and loading will be stopped
         // after, reset the state variables.
         resetLoadingStates();
+        if (description == null || description.isEmpty()) {
+            description = ErrorStrings.getString(errorCode, mContext);
+        }
         mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
     }
 
@@ -649,23 +654,6 @@
     }
 
     /**
-     * Called by JNI.
-     * Read from an InputStream into a supplied byte[]
-     * This method catches any exceptions so they don't crash the JVM.
-     * @param inputStream InputStream to read from.
-     * @param output Bytearray that gets the output.
-     * @return the number of bytes read, or -i if then end of stream has been reached
-     */
-    private static int readFromStream(InputStream inputStream, byte[] output) {
-        try {
-            return inputStream.read(output);
-        } catch(java.io.IOException e) {
-            // If we get an exception, return end of stream
-            return -1;
-        }
-    }
-
-    /**
      * Get the InputStream for an Android resource
      * There are three different kinds of android resources:
      * - file:///android_res
@@ -854,8 +842,6 @@
                 this, url, loaderHandle, synchronous, isMainFramePage,
                 mainResource, userGesture, postDataIdentifier, username, password);
 
-        mCallbackProxy.onLoadResource(url);
-
         if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
             // send an error message, so that loadListener can be deleted
             // after this is returned. This is important as LoadListener's 
@@ -867,7 +853,11 @@
             return loadListener;
         }
 
-        FrameLoader loader = new FrameLoader(loadListener, mSettings, method);
+        // Note that we are intentionally skipping
+        // inputStreamForAndroidResource.  This is so that FrameLoader will use
+        // the various StreamLoader classes to handle assets.
+        FrameLoader loader = new FrameLoader(loadListener, mSettings, method,
+                mCallbackProxy.shouldInterceptRequest(url));
         loader.setHeaders(headers);
         loader.setPostData(postData);
         // Set the load mode to the mode used for the current page.
@@ -884,6 +874,15 @@
         return !synchronous ? loadListener : null;
     }
 
+    // Called by jni from the chrome network stack.
+    private WebResourceResponse shouldInterceptRequest(String url) {
+        InputStream androidResource = inputStreamForAndroidResource(url);
+        if (androidResource != null) {
+            return new WebResourceResponse(null, null, androidResource);
+        }
+        return mCallbackProxy.shouldInterceptRequest(url);
+    }
+
     /**
      * Set the progress for the browser activity.  Called by native code.
      * Uses a delay so it does not happen too often.
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 0078e7a..160fc2e 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -1008,13 +1008,17 @@
         sendMessage(obtainMessage(UPDATE_VISITED, isReload ? 1 : 0, 0, url));
     }
 
-    public void onLoadResource(String url) {
-        // Do an unsynchronized quick check to avoid posting if no callback has
-        // been set.
+    WebResourceResponse shouldInterceptRequest(String url) {
         if (mWebViewClient == null) {
-            return;
+            return null;
         }
-        sendMessage(obtainMessage(LOAD_RESOURCE, url));
+        // Note: This method does _not_ send a message.
+        WebResourceResponse r =
+                mWebViewClient.shouldInterceptRequest(mWebView, url);
+        if (r == null) {
+            sendMessage(obtainMessage(LOAD_RESOURCE, url));
+        }
+        return r;
     }
 
     public void onUnhandledKeyEvent(KeyEvent event) {
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 021b53c..951dab3 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.net.http.ErrorStrings;
 import android.net.http.EventHandler;
 import android.net.http.RequestHandle;
 import android.os.Build;
@@ -37,6 +38,7 @@
     private String mReferrer;
     private String mContentType;
     private final String mUaprofHeader;
+    private final WebResourceResponse mInterceptResponse;
 
     private static final int URI_PROTOCOL = 0x100;
 
@@ -53,12 +55,13 @@
     private static final String LOGTAG = "webkit";
     
     FrameLoader(LoadListener listener, WebSettings settings,
-            String method) {
+            String method, WebResourceResponse interceptResponse) {
         mListener = listener;
         mHeaders = null;
         mMethod = method;
         mCacheMode = WebSettings.LOAD_NORMAL;
         mSettings = settings;
+        mInterceptResponse = interceptResponse;
         mUaprofHeader = mListener.getContext().getResources().getString(
                 com.android.internal.R.string.config_useragentprofile_url, Build.MODEL);
     }
@@ -99,7 +102,17 @@
     public boolean executeLoad() {
         String url = mListener.url();
 
-        if (URLUtil.isNetworkUrl(url)){
+        // Process intercepted requests first as they could be any url.
+        if (mInterceptResponse != null) {
+            if (mListener.isSynchronous()) {
+                mInterceptResponse.loader(mListener).load();
+            } else {
+                WebViewWorker.getHandler().obtainMessage(
+                        WebViewWorker.MSG_ADD_STREAMLOADER,
+                        mInterceptResponse.loader(mListener)).sendToTarget();
+            }
+            return true;
+        } else if (URLUtil.isNetworkUrl(url)){
             if (mSettings.getBlockNetworkLoads()) {
                 mListener.error(EventHandler.ERROR_BAD_URL,
                         mListener.getContext().getString(
@@ -247,8 +260,7 @@
             error = EventHandler.ERROR_BAD_URL;
         }
         if (!ret) {
-            mListener.error(error, mListener.getContext().getText(
-                    EventHandler.errorStringResources[Math.abs(error)]).toString());
+            mListener.error(error, ErrorStrings.getString(error, mListener.getContext()));
             return false;
         }
         return true;
@@ -303,9 +315,8 @@
                     // it has gone.
                     // Generate a file not found error
                     int err = EventHandler.FILE_NOT_FOUND_ERROR;
-                    mListener.error(err, mListener.getContext().getText(
-                            EventHandler.errorStringResources[Math.abs(err)])
-                            .toString());
+                    mListener.error(err,
+                            ErrorStrings.getString(err, mListener.getContext()));
                 }
                 return true;
             }
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 33f5655..a29299d 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -836,8 +836,7 @@
             mRequestHandle.handleSslErrorResponse(proceed);
         }
         if (!proceed) {
-            // Commit whatever data we have and tear down the loader.
-            commitLoad();
+            mBrowserFrame.stopLoading();
             tearDown();
         }
     }
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
new file mode 100644
index 0000000..e786838
--- /dev/null
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -0,0 +1,116 @@
+/*
+ * 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 android.webkit;
+
+import android.net.http.Headers;
+
+import java.io.InputStream;
+
+/**
+ * A WebResourceResponse is return by
+ * {@link WebViewClient#shouldInterceptRequest} and
+ * contains the response information for a particular resource.
+ */
+public class WebResourceResponse {
+
+    private class Loader extends StreamLoader {
+        Loader(LoadListener loadListener) {
+            super(loadListener);
+            mDataStream = mInputStream;
+        }
+        @Override
+        protected boolean setupStreamAndSendStatus() {
+            mLoadListener.status(1, 1, mDataStream != null ? 200 : 404, "");
+            return true;
+        }
+        @Override
+        protected void buildHeaders(Headers headers) {
+            headers.setContentType(mMimeType);
+            headers.setContentEncoding(mEncoding);
+        }
+    }
+
+    // Accessed by jni, do not rename without modifying the jni code.
+    private String mMimeType;
+    private String mEncoding;
+    private InputStream mInputStream;
+
+    /**
+     * Construct a response with the given mime type, encoding, and data.
+     * @param mimeType The mime type of the data (i.e. text/html).
+     * @param encoding The encoding of the bytes read from data.
+     * @param data An InputStream for reading custom data.  The implementation
+     *             must implement {@link InputStream#read(byte[])}.
+     */
+    public WebResourceResponse(String mimeType, String encoding,
+            InputStream data) {
+        mMimeType = mimeType;
+        mEncoding = encoding;
+        mInputStream = data;
+    }
+
+    /**
+     * Set the mime type of the response data (i.e. text/html).
+     * @param mimeType
+     */
+    public void setMimeType(String mimeType) {
+        mMimeType = mimeType;
+    }
+
+    /**
+     * @see #setMimeType
+     */
+    public String getMimeType() {
+        return mMimeType;
+    }
+
+    /**
+     * Set the encoding of the response data (i.e. utf-8).  This will be used to
+     * decode the raw bytes from the input stream.
+     * @param encoding
+     */
+    public void setEncoding(String encoding) {
+        mEncoding = encoding;
+    }
+
+    /**
+     * @see #setEncoding
+     */
+    public String getEncoding() {
+        return mEncoding;
+    }
+
+    /**
+     * Set the input stream containing the data for this resource.
+     * @param data An InputStream for reading custom data.  The implementation
+     *             must implement {@link InputStream#read(byte[])}.
+     */
+    public void setData(InputStream data) {
+        mInputStream = data;
+    }
+
+    /**
+     * @see #setData
+     */
+    public InputStream getData() {
+        return mInputStream;
+    }
+
+    StreamLoader loader(LoadListener listener) {
+        return new Loader(listener);
+    }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 14dbfe2..06800d5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2384,7 +2384,6 @@
 
     Rect sendOurVisibleRect() {
         if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent;
-
         Rect rect = new Rect();
         calcOurContentVisibleRect(rect);
         // Rect.equals() checks for null input.
@@ -2937,7 +2936,8 @@
             postInvalidate();  // So we draw again
             if (oldX != mScrollX || oldY != mScrollY) {
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
-            } else {
+            } else if (mScroller.getStartX() != mScrollX
+                    || mScroller.getStartY() != mScrollY) {
                 abortAnimation();
                 mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
                 WebViewCore.resumePriority();
@@ -2970,6 +2970,7 @@
         if ((dx | dy) == 0) {
             return false;
         }
+        abortAnimation();
         if (animate) {
             //        Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
             mScroller.startScroll(mScrollX, mScrollY, dx, dy,
@@ -2977,7 +2978,6 @@
             awakenScrollBars(mScroller.getDuration());
             invalidate();
         } else {
-            abortAnimation(); // just in case
             scrollTo(x, y);
         }
         return true;
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 1f8eeba..db605de 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -78,6 +78,26 @@
     }
 
     /**
+     * Notify the host application of a resource request and allow the
+     * application to return the data.  If the return value is null, the WebView
+     * will continue to load the resource as usual.  Otherwise, the return
+     * response and data will be used.  NOTE: This method is called by the
+     * network thread so clients should exercise caution when accessing private
+     * data.
+     *
+     * @param view The {@link android.webkit.WebView} that is requesting the
+     *             resource.
+     * @param url The raw url of the resource.
+     * @return A {@link android.webkit.WebResourceResponse} containing the
+     *         response information or null if the WebView should load the
+     *         resource itself.
+     */
+    public WebResourceResponse shouldInterceptRequest(WebView view,
+            String url) {
+        return null;
+    }
+
+    /**
      * Notify the host application that there have been an excessive number of
      * HTTP redirects. As the host application if it would like to continue
      * trying to load the resource. The default behavior is to send the cancel
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 0fcd26c..8c515db 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -283,7 +283,9 @@
      */
     /* package */ static boolean isSupportedMediaMimeType(String mimeType) {
         int fileType = MediaFile.getFileTypeForMimeType(mimeType);
-        return MediaFile.isAudioFileType(fileType) || MediaFile.isVideoFileType(fileType);
+        return MediaFile.isAudioFileType(fileType)
+            || MediaFile.isVideoFileType(fileType)
+            || MediaFile.isPlayListFileType(fileType);
     }
 
     /**
diff --git a/core/java/android/webkit/ZoomControlEmbedded.java b/core/java/android/webkit/ZoomControlEmbedded.java
index c29e72b..e505614 100644
--- a/core/java/android/webkit/ZoomControlEmbedded.java
+++ b/core/java/android/webkit/ZoomControlEmbedded.java
@@ -40,13 +40,15 @@
 
             mZoomButtonsController.setVisible(true);
 
-            WebSettings settings = mWebView.getSettings();
-            int count = settings.getDoubleTapToastCount();
-            if (mZoomManager.isInZoomOverview() && count > 0) {
-                settings.setDoubleTapToastCount(--count);
-                Toast.makeText(mWebView.getContext(),
-                        com.android.internal.R.string.double_tap_toast,
-                        Toast.LENGTH_LONG).show();
+            if (mZoomManager.isDoubleTapEnabled()) {
+                WebSettings settings = mWebView.getSettings();
+                int count = settings.getDoubleTapToastCount();
+                if (mZoomManager.isInZoomOverview() && count > 0) {
+                    settings.setDoubleTapToastCount(--count);
+                    Toast.makeText(mWebView.getContext(),
+                            com.android.internal.R.string.double_tap_toast,
+                            Toast.LENGTH_LONG).show();
+                }
             }
         }
     }
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index c788a53..69db6b2 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -510,6 +510,11 @@
         }
     }
 
+    public boolean isDoubleTapEnabled() {
+        WebSettings settings = mWebView.getSettings();
+        return settings != null && settings.getUseWideViewPort();
+    }
+
     /**
      * The double tap gesture can result in different behaviors depending on the
      * content that is tapped.
@@ -528,7 +533,7 @@
      */
     public void handleDoubleTap(float lastTouchX, float lastTouchY) {
         WebSettings settings = mWebView.getSettings();
-        if (settings == null || settings.getUseWideViewPort() == false) {
+        if (!isDoubleTapEnabled()) {
             return;
         }
 
@@ -808,7 +813,9 @@
                 setZoomOverviewWidth(Math.min(WebView.sMaxViewportWidth,
                     Math.max((int) (viewWidth * mInvDefaultScale),
                             Math.max(drawData.mMinPrefWidth, drawData.mViewSize.x))));
-            } else {
+            } else if (drawData.mContentSize.x > 0) {
+                // The webkitDraw for layers will not populate contentSize, and it'll be
+                // ignored for zoom overview width update.
                 final int contentWidth = Math.max(drawData.mContentSize.x, drawData.mMinPrefWidth);
                 final int newZoomOverviewWidth = Math.min(WebView.sMaxViewportWidth, contentWidth);
                 if (newZoomOverviewWidth != mZoomOverviewWidth) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index ab5ff3d..30b1e5d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2893,8 +2893,8 @@
     void reportScrollStateChange(int newState) {
         if (newState != mLastScrollState) {
             if (mOnScrollListener != null) {
-                mOnScrollListener.onScrollStateChanged(this, newState);
                 mLastScrollState = newState;
+                mOnScrollListener.onScrollStateChanged(this, newState);
             }
         }
     }
@@ -3431,12 +3431,13 @@
     public void smoothScrollBy(int distance, int duration) {
         if (mFlingRunnable == null) {
             mFlingRunnable = new FlingRunnable();
-        } else {
-            mFlingRunnable.endFling();
         }
         // No sense starting to scroll if we're not going anywhere
         if (distance != 0) {
+            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
             mFlingRunnable.startScroll(distance, duration);
+        } else {
+            mFlingRunnable.endFling();
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index bad74d4..555d993 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -34,6 +34,7 @@
 import android.util.Log;
 import android.view.RemotableViewMethod;
 import android.view.View;
+import android.view.ViewDebug;
 import android.widget.RemoteViews.RemoteView;
 
 
@@ -84,7 +85,8 @@
 
     private boolean mCropToPadding;
 
-    private boolean mBaselineAligned = false;
+    private int mBaseline = -1;
+    private boolean mBaselineAlignBottom = false;
 
     private static final ScaleType[] sScaleTypeArray = {
         ScaleType.MATRIX,
@@ -118,9 +120,12 @@
             setImageDrawable(d);
         }
 
-        mBaselineAligned = a.getBoolean(
+        mBaselineAlignBottom = a.getBoolean(
                 com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);
-        
+
+        mBaseline = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.ImageView_baseline, -1);
+
         setAdjustViewBounds(
             a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,
             false));
@@ -180,7 +185,7 @@
             super.invalidateDrawable(dr);
         }
     }
-    
+
     @Override
     protected boolean onSetAlpha(int alpha) {
         if (getBackground() == null) {
@@ -878,9 +883,63 @@
         }
     }
 
+    /**
+     * <p>Return the offset of the widget's text baseline from the widget's top
+     * boundary. </p>
+     *
+     * @return the offset of the baseline within the widget's bounds or -1
+     *         if baseline alignment is not supported.
+     */
     @Override
+    @ViewDebug.ExportedProperty(category = "layout")
     public int getBaseline() {
-        return mBaselineAligned ? getMeasuredHeight() : -1;
+        if (mBaselineAlignBottom) {
+            return getMeasuredHeight();
+        } else {
+            return mBaseline;
+        }
+    }
+
+    /**
+     * <p>Set the offset of the widget's text baseline from the widget's top
+     * boundary.  This value is overridden by the {@link #setBaselineAlignBottom}
+     * property.</p>
+     *
+     * @param baseline The baseline to use, or -1 if none is to be provided.
+     *
+     * @see #setBaseline
+     * @attr ref android.R.styleable#ImageView_baseline
+     */
+    public void setBaseline(int baseline) {
+        if (mBaseline != baseline) {
+            mBaseline = baseline;
+            requestLayout();
+        }
+    }
+
+    /**
+     * Set whether to set the baseline of this view to the bottom of the view.
+     * Setting this value overrides any calls to setBaseline.
+     *
+     * @param aligned If true, the image view will be baseline aligned with
+     *      based on its bottom edge.
+     *
+     * @attr ref android.R.styleable#ImageView_baselineAlignBottom
+     */
+    public void setBaselineAlignBottom(boolean aligned) {
+        if (mBaselineAlignBottom != aligned) {
+            mBaselineAlignBottom = aligned;
+            requestLayout();
+        }
+    }
+
+    /**
+     * Return whether this view's baseline will be considered the bottom of the view.
+     *
+     * @see #setBaselineAlignBottom(boolean)
+     */
+    public boolean getBaselineAlignBottom() {
+        return mBaselineAlignBottom;
     }
 
     /**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b7048fc..63fb3e9 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -154,6 +154,8 @@
 
     private boolean mInDrawing;
 
+    private int mAnimationResolution;
+
     /**
      * Create a new progress bar with range 0...100 and initial progress of 0.
      * @param context the application environment
@@ -167,12 +169,19 @@
     }
 
     public ProgressBar(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public ProgressBar(Context context, AttributeSet attrs, int defStyle, int styleRes) {
         super(context, attrs, defStyle);
         mUiThreadId = Thread.currentThread().getId();
         initProgressBar();
 
         TypedArray a =
-            context.obtainStyledAttributes(attrs, R.styleable.ProgressBar, defStyle, 0);
+            context.obtainStyledAttributes(attrs, R.styleable.ProgressBar, defStyle, styleRes);
         
         mNoInvalidate = true;
         
@@ -222,6 +231,9 @@
         setIndeterminate(mOnlyIndeterminate || a.getBoolean(
                 R.styleable.ProgressBar_indeterminate, mIndeterminate));
 
+        mAnimationResolution = a.getInteger(R.styleable.ProgressBar_animationResolution,
+                ANIMATION_RESOLUTION);
+
         a.recycle();
     }
 
@@ -852,9 +864,9 @@
                 } finally {
                     mInDrawing = false;
                 }
-                if (SystemClock.uptimeMillis() - mLastDrawTime >= ANIMATION_RESOLUTION) {
+                if (SystemClock.uptimeMillis() - mLastDrawTime >= mAnimationResolution) {
                     mLastDrawTime = SystemClock.uptimeMillis();
-                    postInvalidateDelayed(ANIMATION_RESOLUTION);
+                    postInvalidateDelayed(mAnimationResolution);
                 }
             }
             d.draw(canvas);
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 26eb57c..52d9c08 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -664,7 +664,7 @@
                 itemId = factory.getItemId(position);
             } catch (Exception e) {
                 // Print the error
-                Log.e(TAG, "Error in updateRemoteViewsInfo(" + position + "): " +
+                Log.e(TAG, "Error in updateRemoteViews(" + position + "): " +
                         e.getMessage());
                 e.printStackTrace();
 
@@ -673,6 +673,14 @@
                 return;
             }
 
+            if (remoteViews == null) {
+                // If a null view was returned, we break early to prevent it from getting
+                // into our cache and causing problems later. The effect is that the child  at this
+                // position will remain as a loading view until it is updated.
+                Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + " null RemoteViews " +
+                        "returned from RemoteViewsFactory.");
+                return;
+            }
             synchronized (mCache) {
                 // Cache the RemoteViews we loaded
                 mCache.insert(position, remoteViews, itemId);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 7c38714..432dd4a 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -118,6 +118,8 @@
 
     private static HolographicHelper sHolographicHelper;
     private ImageView mHighlight;
+    private ImageView mClickFeedback;
+    private boolean mClickFeedbackIsValid = false;
     private StackSlider mStackSlider;
     private boolean mFirstLayoutHappened = false;
     private int mStackMode;
@@ -145,6 +147,12 @@
         mHighlight = new ImageView(getContext());
         mHighlight.setLayoutParams(new LayoutParams(mHighlight));
         addViewInLayout(mHighlight, -1, new LayoutParams(mHighlight));
+
+        mClickFeedback = new ImageView(getContext());
+        mClickFeedback.setLayoutParams(new LayoutParams(mClickFeedback));
+        addViewInLayout(mClickFeedback, -1, new LayoutParams(mClickFeedback));
+        mClickFeedback.setVisibility(INVISIBLE);
+
         mStackSlider = new StackSlider();
 
         if (sHolographicHelper == null) {
@@ -310,6 +318,34 @@
             }
         }
         mTransitionIsSetup = false;
+        mClickFeedbackIsValid = false;
+    }
+
+    void updateClickFeedback() {
+        if (!mClickFeedbackIsValid) {
+            View v = getViewAtRelativeIndex(0);
+            if (v != null) {
+                mClickFeedback.setImageBitmap(sHolographicHelper.createOutline(v,
+                        HolographicHelper.CLICK_FEEDBACK));
+                mClickFeedback.setTranslationX(v.getTranslationX());
+                mClickFeedback.setTranslationY(v.getTranslationY());
+            }
+            mClickFeedbackIsValid = true;
+        }
+    }
+
+    @Override
+    void showTapFeedback(View v) {
+        updateClickFeedback();
+        mClickFeedback.setVisibility(VISIBLE);
+        mClickFeedback.bringToFront();
+        invalidate();
+    }
+
+    @Override
+    void hideTapFeedback(View v) {
+        mClickFeedback.setVisibility(INVISIBLE);
+        invalidate();
     }
 
     private void updateChildTransforms() {
@@ -1010,23 +1046,36 @@
         private final Paint mHolographicPaint = new Paint();
         private final Paint mErasePaint = new Paint();
         private final Paint mBlurPaint = new Paint();
+        private static final int RES_OUT = 0;
+        private static final int CLICK_FEEDBACK = 1;
+        private float mDensity;
 
         HolographicHelper(Context context) {
             initializePaints(context);
         }
 
         void initializePaints(Context context) {
-            final float density = context.getResources().getDisplayMetrics().density;
+            mDensity = context.getResources().getDisplayMetrics().density;
 
-            mHolographicPaint.setColor(0xff6699ff);
             mHolographicPaint.setFilterBitmap(true);
             mHolographicPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
             mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
             mErasePaint.setFilterBitmap(true);
-            mBlurPaint.setMaskFilter(new BlurMaskFilter(2*density, BlurMaskFilter.Blur.NORMAL));
         }
 
         Bitmap createOutline(View v) {
+            return createOutline(v, RES_OUT);
+        }
+
+        Bitmap createOutline(View v, int type) {
+            if (type == RES_OUT) {
+                mHolographicPaint.setColor(0xff6699ff);
+                mBlurPaint.setMaskFilter(new BlurMaskFilter(2*mDensity, BlurMaskFilter.Blur.NORMAL));
+            } else if (type == CLICK_FEEDBACK) {
+                mHolographicPaint.setColor(0x886699ff);
+                mBlurPaint.setMaskFilter(new BlurMaskFilter(4*mDensity, BlurMaskFilter.Blur.NORMAL));
+            }
+
             if (v.getMeasuredWidth() == 0 || v.getMeasuredHeight() == 0) {
                 return null;
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5320b10..fbc8549 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -305,6 +305,8 @@
     int mTextSelectHandleRes;
     int mTextEditPasteWindowLayout;
     int mTextEditNoPasteWindowLayout;
+    Drawable mEditTextMultilineBackground;
+    Drawable mEditTextSingleLineBackground;
 
     Drawable mSelectHandleLeft;
     Drawable mSelectHandleRight;
@@ -751,6 +753,10 @@
                 mTextEditNoPasteWindowLayout = a.getResourceId(attr, 0);
                 break;
 
+            case com.android.internal.R.styleable.TextView_multilineBackground:
+                mEditTextMultilineBackground = a.getDrawable(attr);
+                break;
+
             case com.android.internal.R.styleable.TextView_textLineHeight:
                 int lineHeight = a.getDimensionPixelSize(attr, 0);
                 if (lineHeight != 0) {
@@ -765,6 +771,7 @@
         }
         a.recycle();
 
+        mEditTextSingleLineBackground = getBackground();
         BufferType bufferType = BufferType.EDITABLE;
 
         final int variation =
@@ -3869,7 +3876,7 @@
         // - ExtractEditText does not call onFocus when it is displayed. Fixing this issue would
         //   allow to test for hasSelection in onFocusChanged, which would trigger a
         //   startTextSelectionMode here. TODO
-        if (selectionController != null && hasSelection()) {
+        if (this instanceof ExtractEditText && selectionController != null && hasSelection()) {
             startSelectionActionMode();
         }
 
@@ -5042,6 +5049,7 @@
     }
 
     public void beginBatchEdit() {
+        mInBatchEditControllers = true;
         final InputMethodState ims = mInputMethodState;
         if (ims != null) {
             int nesting = ++ims.mBatchEditNesting;
@@ -5064,6 +5072,7 @@
     }
     
     public void endBatchEdit() {
+        mInBatchEditControllers = false;
         final InputMethodState ims = mInputMethodState;
         if (ims != null) {
             int nesting = --ims.mBatchEditNesting;
@@ -6190,12 +6199,14 @@
             if (applyTransformation) {
                 setTransformationMethod(SingleLineTransformationMethod.getInstance());
             }
+            setBackgroundDrawable(mEditTextSingleLineBackground);
         } else {
             setMaxLines(Integer.MAX_VALUE);
             setHorizontallyScrolling(false);
             if (applyTransformation) {
                 setTransformationMethod(null);
             }
+            setBackgroundDrawable(mEditTextMultilineBackground);
         }
     }
     
@@ -6991,26 +7002,21 @@
                 // Restore previous selection
                 Selection.setSelection((Spannable)mText, prevStart, prevEnd);
 
-                if (mSelectionModifierCursorController != null &&
-                        !mSelectionModifierCursorController.isShowing()) {
+                if (hasSelectionController() && !getSelectionController().isShowing()) {
                     // If the anchors aren't showing, revive them.
-                    mSelectionModifierCursorController.show();
-                } else {
-                    // Tapping inside the selection displays the cut/copy/paste context menu
-                    // as long as the anchors are already showing.
-                    showContextMenu();
+                    getSelectionController().show();
                 }
                 return;
             } else {
                 // Tapping outside stops selection mode, if any
                 stopSelectionActionMode();
 
-                if (mInsertionPointCursorController != null) {
-                    mInsertionPointCursorController.show();
+                if (hasInsertionController()) {
+                    getInsertionController().show();
                 }
             }
-        } else if (hasSelection() && mSelectionModifierCursorController != null) {
-            mSelectionModifierCursorController.show();
+        } else if (hasSelection() && hasSelectionController()) {
+            getSelectionController().show();
         }
     }
 
@@ -7043,11 +7049,12 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
-        if (mInsertionPointCursorController != null) {
-            mInsertionPointCursorController.onTouchEvent(event);
+
+        if (hasInsertionController()) {
+            getInsertionController().onTouchEvent(event);
         }
-        if (mSelectionModifierCursorController != null) {
-            mSelectionModifierCursorController.onTouchEvent(event);
+        if (hasSelectionController()) {
+            getSelectionController().onTouchEvent(event);
         }
 
         if (action == MotionEvent.ACTION_DOWN) {
@@ -7129,21 +7136,17 @@
                     || windowParams.type > WindowManager.LayoutParams.LAST_SUB_WINDOW;
         }
 
-        if (windowSupportsHandles && isTextEditable() && mCursorVisible && mLayout != null &&
-                !mTextIsSelectable) {
-            if (mInsertionPointCursorController == null) {
-                mInsertionPointCursorController = new InsertionPointCursorController();
-            }
-        } else {
-            hideInsertionPointCursorController();
+        // TODO Add an extra android:cursorController flag to disable the controller?
+        mInsertionControllerEnabled = windowSupportsHandles && isTextEditable() && mCursorVisible &&
+                mLayout != null && !mTextIsSelectable;
+        mSelectionControllerEnabled = windowSupportsHandles && textCanBeSelected() &&
+                mLayout != null;
+
+        if (!mInsertionControllerEnabled) {
             mInsertionPointCursorController = null;
         }
 
-        if (windowSupportsHandles && textCanBeSelected() && mLayout != null) {
-            if (mSelectionModifierCursorController == null) {
-                mSelectionModifierCursorController = new SelectionModifierCursorController();
-            }
-        } else {
+        if (!mSelectionControllerEnabled) {
             // Stop selection mode if the controller becomes unavailable.
             if (mSelectionModifierCursorController != null) {
                 stopSelectionActionMode();
@@ -8348,6 +8351,10 @@
                 return true;
             }
 
+            if (isInBatchEditMode()) {
+                return false;
+            }
+
             final int extendedPaddingTop = getExtendedPaddingTop();
             final int extendedPaddingBottom = getExtendedPaddingBottom();
             final int compoundPaddingLeft = getCompoundPaddingLeft();
@@ -8387,7 +8394,7 @@
             mPositionY = y - TextView.this.mScrollY;
             if (isPositionVisible()) {
                 int[] coords = null;
-                if (mContainer.isShowing()){
+                if (mContainer.isShowing()) {
                     coords = mTempCoords;
                     TextView.this.getLocationInWindow(coords);
                     final int containerPositionX = coords[0] + mPositionX;
@@ -8626,6 +8633,10 @@
         }
 
         public void show() {
+            if (isInBatchEditMode()) {
+                return;
+            }
+
             mIsShowing = true;
             updatePosition();
             mStartHandle.show();
@@ -8689,6 +8700,10 @@
         }
 
         public void updatePosition() {
+            if (!isShowing()) {
+                return;
+            }
+
             final int selectionStart = getSelectionStart();
             final int selectionEnd = getSelectionEnd();
 
@@ -8913,8 +8928,62 @@
         }
     }
 
+    /**
+     * @return True if this view supports insertion handles.
+     */
+    boolean hasInsertionController() {
+        return mInsertionControllerEnabled;
+    }
 
-    @ViewDebug.ExportedProperty(category = "text")
+    /**
+     * @return True if this view supports selection handles.
+     */
+    boolean hasSelectionController() {
+        return mSelectionControllerEnabled;
+    }
+
+    CursorController getInsertionController() {
+        if (!mInsertionControllerEnabled) {
+            return null;
+        }
+
+        if (mInsertionPointCursorController == null) {
+            mInsertionPointCursorController = new InsertionPointCursorController();
+
+            final ViewTreeObserver observer = getViewTreeObserver();
+            if (observer != null) {
+                observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
+            }
+        }
+
+        return mInsertionPointCursorController;
+    }
+
+    CursorController getSelectionController() {
+        if (!mSelectionControllerEnabled) {
+            return null;
+        }
+
+        if (mSelectionModifierCursorController == null) {
+            mSelectionModifierCursorController = new SelectionModifierCursorController();
+
+            final ViewTreeObserver observer = getViewTreeObserver();
+            if (observer != null) {
+                observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
+            }
+        }
+
+        return mSelectionModifierCursorController;
+    }
+
+    boolean isInBatchEditMode() {
+        final InputMethodState ims = mInputMethodState;
+        if (ims != null) {
+            return ims.mBatchEditNesting > 0;
+        }
+        return mInBatchEditControllers;
+    }
+
     private CharSequence            mText;
     private CharSequence            mTransformed;
     private BufferType              mBufferType = BufferType.NORMAL;
@@ -8942,10 +9011,14 @@
     private Blink                   mBlink;
     private boolean                 mCursorVisible = true;
 
-    // Cursor Controllers. Null when disabled.
+    // Cursor Controllers.
     private CursorController        mInsertionPointCursorController;
     private CursorController        mSelectionModifierCursorController;
     private ActionMode              mSelectionActionMode;
+    private boolean                 mInsertionControllerEnabled;
+    private boolean                 mSelectionControllerEnabled;
+    private boolean                 mInBatchEditControllers;
+
     // These are needed to desambiguate a long click. If the long click comes from ones of these, we
     // select from the current cursor position. Otherwise, select from long pressed position.
     private boolean                 mDPadCenterIsDown = false;
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index cd1cae6..86523ac 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -212,6 +212,10 @@
     }
 
     public View getCustomNavigationView() {
+        return getCustomView();
+    }
+
+    public View getCustomView() {
         return mActionView.getCustomNavigationView();
     }
 
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index b0778dd..0891acc 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -32,51 +32,51 @@
 import java.util.Stack;
 
 /**
- * An asynchronous channel between two handlers.
+ * <p>An asynchronous channel between two handlers.</p>
  *
- * The handlers maybe in the same process or in another process. There
+ * <p>The handlers maybe in the same process or in another process. There
  * are two protocol styles that can be used with an AysncChannel. The
  * first is a simple request/reply protocol where the server does
- * not need to know which client is issuing the request.
+ * not need to know which client is issuing the request.</p>
  *
- * In a simple request/reply protocol the client/source sends requests to the
+ * <p>In a simple request/reply protocol the client/source sends requests to the
  * server/destination. And the server uses the replyToMessage methods.
  * In this usage model there is no need for the destination to
- * use the connect methods. The typical sequence of operations is:
- *
- *   1) Client calls AsyncChannel#connect
- *   2) Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
-
- *   3) Client calls AsyncChannel#sendMessage(msgX)
- *   4) Server receives and processes msgX
- *   5) Server optionally calls AsyncChannel#replyToMessage(msgY)
- *      and if sent Client receives and processes msgY
- *   6) Loop to step 3 until done
- *
- *   7) When done Client calls {@link AsyncChannel#disconnect(int)}
- *   8) Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel
- *
- * A second usage model is where the server/destination needs to know
+ * use the connect methods. The typical sequence of operations is:</p>
+ *<ol>
+ *   <li>Client calls AsyncChannel#connect</li>
+ *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li><code>comm-loop:</code></li>
+ *   <li>Client calls AsyncChannel#sendMessage(msgX)</li>
+ *   <li>Server receives and processes msgX</li>
+ *   <li>Server optionally calls AsyncChannel#replyToMessage(msgY)
+ *       and if sent Client receives and processes msgY</li>
+ *   <li>Loop to <code>comm-loop</code> until done</li>
+ *   <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li>
+ *   <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *</ol>
+ *<br/>
+ * <p>A second usage model is where the server/destination needs to know
  * which client it's connected too. For example the server needs to
  * send unsolicited messages back to the client. Or the server keeps
  * different state for each client. In this model the server will also
- * use the connect methods. The typical sequence of operation is:
- *
- *   1)  Client calls AsyncChannel#connect
- *   2)  Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
- *   3)  Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)
- *   4)  Server receives CMD_CHANNEL_FULL_CONNECTION
- *   5)  Server calls AsyncChannel#connect
- *   6)  Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel
- *   7)  Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)
- *   8)  Client receives CMD_CHANNEL_FULLY_CONNECTED
- *
- *   9)  Client/Server uses AsyncChannel#sendMessage/replyToMessage
- *       to communicate and perform work
- *   10) Loop to step 9 until done
- *
- *   11) When done Client/Server calls {@link AsyncChannel#disconnect(int)}
- *   12) Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel
+ * use the connect methods. The typical sequence of operation is:</p>
+ *<ol>
+ *   <li>Client calls AsyncChannel#connect</li>
+ *   <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ *   <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
+ *   <li>Server calls AsyncChannel#connect</li>
+ *   <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ *   <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
+ *   <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
+ *   <li><code>comm-loop:</code></li>
+ *   <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
+ *       to communicate and perform work</li>
+ *   <li>Loop to <code>comm-loop</code> until done</li>
+ *   <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li>
+ *   <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ *</ol>
  */
 public class AsyncChannel {
     /** Log tag */
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/HierarchicalStateMachine.java
index 7920b72..f43f459 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/HierarchicalStateMachine.java
@@ -28,64 +28,66 @@
 /**
  * {@hide}
  *
- * A hierarchical state machine is a state machine which processes messages
- * and can have states arranged hierarchically. A state is a <code>HierarchicalState</code>
- * object and must implement <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
+ * <p>A hierarchical state machine is a state machine which processes messages
+ * and can have states arranged hierarchically.</p>
+ * 
+ * <p>A state is a <code>HierarchicalState</code> object and must implement
+ * <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
  * The enter/exit methods are equivalent to the construction and destruction
  * in Object Oriented programming and are used to perform initialization and
  * cleanup of the state respectively. The <code>getName</code> method returns the
  * name of the state the default implementation returns the class name it may be
  * desirable to have this return the name of the state instance name instead.
- * In particular if a particular state class has multiple instances.
+ * In particular if a particular state class has multiple instances.</p>
  *
- * When a state machine is created <code>addState</code> is used to build the
+ * <p>When a state machine is created <code>addState</code> is used to build the
  * hierarchy and <code>setInitialState</code> is used to identify which of these
  * is the initial state. After construction the programmer calls <code>start</code>
  * which initializes the state machine and calls <code>enter</code> for all of the initial
  * state's hierarchy, starting at its eldest parent. For example given the simple
  * state machine below after start is called mP1.enter will have been called and
- * then mS1.enter.
+ * then mS1.enter.</p>
 <code>
         mP1
        /   \
       mS2   mS1 ----> initial state
 </code>
- * After the state machine is created and started, messages are sent to a state
+ * <p>After the state machine is created and started, messages are sent to a state
  * machine using <code>sendMessage</code> and the messages are created using
  * <code>obtainMessage</code>. When the state machine receives a message the
  * current state's <code>processMessage</code> is invoked. In the above example
  * mS1.processMessage will be invoked first. The state may use <code>transitionTo</code>
- * to change the current state to a new state
+ * to change the current state to a new state</p>
  *
- * Each state in the state machine may have a zero or one parent states and if
+ * <p>Each state in the state machine may have a zero or one parent states and if
  * a child state is unable to handle a message it may have the message processed
  * by its parent by returning false or NOT_HANDLED. If a message is never processed
  * <code>unhandledMessage</code> will be invoked to give one last chance for the state machine
- * to process the message.
+ * to process the message.</p>
  *
- * When all processing is completed a state machine may choose to call
+ * <p>When all processing is completed a state machine may choose to call
  * <code>transitionToHaltingState</code>. When the current <code>processingMessage</code>
  * returns the state machine will transfer to an internal <code>HaltingState</code>
  * and invoke <code>halting</code>. Any message subsequently received by the state
- * machine will cause <code>haltedProcessMessage</code> to be invoked.
+ * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
  *
- * If it is desirable to completely stop the state machine call <code>quit</code>. This
+ * <p>If it is desirable to completely stop the state machine call <code>quit</code>. This
  * will exit the current state and its parent and then exit from the controlling thread
- * and no further messages will be processed.
+ * and no further messages will be processed.</p>
  *
- * In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
- * an <code>enter</code> method and <code>exit</exit> method which may be overridden.
+ * <p>In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
+ * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
  *
- * Since the states are arranged in a hierarchy transitioning to a new state
+ * <p>Since the states are arranged in a hierarchy transitioning to a new state
  * causes current states to be exited and new states to be entered. To determine
  * the list of states to be entered/exited the common parent closest to
  * the current state is found. We then exit from the current state and its
  * parent's up to but not including the common parent state and then enter all
  * of the new states below the common parent down to the destination state.
  * If there is no common parent all states are exited and then the new states
- * are entered.
+ * are entered.</p>
  *
- * Two other methods that states can use are <code>deferMessage</code> and
+ * <p>Two other methods that states can use are <code>deferMessage</code> and
  * <code>sendMessageAtFrontOfQueue</code>. The <code>sendMessageAtFrontOfQueue</code> sends
  * a message but places it on the front of the queue rather than the back. The
  * <code>deferMessage</code> causes the message to be saved on a list until a
@@ -93,10 +95,10 @@
  * will be put on the front of the state machine queue with the oldest message
  * at the front. These will then be processed by the new current state before
  * any other messages that are on the queue or might be added later. Both of
- * these are protected and may only be invoked from within a state machine.
+ * these are protected and may only be invoked from within a state machine.</p>
  *
- * To illustrate some of these properties we'll use state machine with an 8
- * state hierarchy:
+ * <p>To illustrate some of these properties we'll use state machine with an 8
+ * state hierarchy:</p>
 <code>
           mP0
          /   \
@@ -106,22 +108,21 @@
      /  \    \
     mS3  mS4  mS5  ---> initial state
 </code>
- *
- * After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
+ * <p>After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
  * So the order of calling processMessage when a message is received is mS5,
  * mS1, mP1, mP0 assuming each processMessage indicates it can't handle this
- * message by returning false or NOT_HANDLED.
+ * message by returning false or NOT_HANDLED.</p>
  *
- * Now assume mS5.processMessage receives a message it can handle, and during
+ * <p>Now assume mS5.processMessage receives a message it can handle, and during
  * the handling determines the machine should change states. It could call
  * transitionTo(mS4) and return true or HANDLED. Immediately after returning from
  * processMessage the state machine runtime will find the common parent,
  * which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then
  * mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
- * when the next message is received mS4.processMessage will be invoked.
+ * when the next message is received mS4.processMessage will be invoked.</p>
  *
- * Now for some concrete examples, here is the canonical HelloWorld as an HSM.
- * It responds with "Hello World" being printed to the log for every message.
+ * <p>Now for some concrete examples, here is the canonical HelloWorld as an HSM.
+ * It responds with "Hello World" being printed to the log for every message.</p>
 <code>
 class HelloWorld extends HierarchicalStateMachine {
     Hsm1(String name) {
@@ -150,79 +151,76 @@
     hw.sendMessage(hw.obtainMessage());
 }
 </code>
- *
- * A more interesting state machine is one with four states
- * with two independent parent states.
+ * <p>A more interesting state machine is one with four states
+ * with two independent parent states.</p>
 <code>
         mP1      mP2
        /   \
       mS2   mS1
 </code>
- *
- * Here is a description of this state machine using pseudo code.
- *
- *
- * state mP1 {
- *      enter { log("mP1.enter"); }
- *      exit { log("mP1.exit");  }
- *      on msg {
- *          CMD_2 {
- *              send(CMD_3);
- *              defer(msg);
- *              transitonTo(mS2);
- *              return HANDLED;
- *          }
- *          return NOT_HANDLED;
- *      }
- * }
- *
- * INITIAL
- * state mS1 parent mP1 {
- *      enter { log("mS1.enter"); }
- *      exit  { log("mS1.exit");  }
- *      on msg {
- *          CMD_1 {
- *              transitionTo(mS1);
- *              return HANDLED;
- *          }
- *          return NOT_HANDLED;
- *      }
- * }
- *
- * state mS2 parent mP1 {
- *      enter { log("mS2.enter"); }
- *      exit  { log("mS2.exit");  }
- *      on msg {
- *          CMD_2 {
- *              send(CMD_4);
- *              return HANDLED;
- *          }
- *          CMD_3 {
- *              defer(msg);
- *              transitionTo(mP2);
- *              return HANDLED;
- *          }
- *          return NOT_HANDLED;
- *      }
- * }
- *
- * state mP2 {
- *      enter {
- *          log("mP2.enter");
- *          send(CMD_5);
- *      }
- *      exit { log("mP2.exit"); }
- *      on msg {
- *          CMD_3, CMD_4 { return HANDLED; }
- *          CMD_5 {
- *              transitionTo(HaltingState);
- *              return HANDLED;
- *          }
- *          return NOT_HANDLED;
- *      }
- * }
- *
- * The implementation is below and also in HierarchicalStateMachineTest:
+ * <p>Here is a description of this state machine using pseudo code.</p>
+ <code>
+state mP1 {
+     enter { log("mP1.enter"); }
+     exit { log("mP1.exit");  }
+     on msg {
+         CMD_2 {
+             send(CMD_3);
+             defer(msg);
+             transitonTo(mS2);
+             return HANDLED;
+         }
+         return NOT_HANDLED;
+     }
+}
+
+INITIAL
+state mS1 parent mP1 {
+     enter { log("mS1.enter"); }
+     exit  { log("mS1.exit");  }
+     on msg {
+         CMD_1 {
+             transitionTo(mS1);
+             return HANDLED;
+         }
+         return NOT_HANDLED;
+     }
+}
+
+state mS2 parent mP1 {
+     enter { log("mS2.enter"); }
+     exit  { log("mS2.exit");  }
+     on msg {
+         CMD_2 {
+             send(CMD_4);
+             return HANDLED;
+         }
+         CMD_3 {
+             defer(msg);
+             transitionTo(mP2);
+             return HANDLED;
+         }
+         return NOT_HANDLED;
+     }
+}
+
+state mP2 {
+     enter {
+         log("mP2.enter");
+         send(CMD_5);
+     }
+     exit { log("mP2.exit"); }
+     on msg {
+         CMD_3, CMD_4 { return HANDLED; }
+         CMD_5 {
+             transitionTo(HaltingState);
+             return HANDLED;
+         }
+         return NOT_HANDLED;
+     }
+}
+</code>
+ * <p>The implementation is below and also in HierarchicalStateMachineTest:</p>
 <code>
 class Hsm1 extends HierarchicalStateMachine {
     private static final String TAG = "hsm1";
@@ -368,49 +366,47 @@
     P2 mP2 = new P2();
 }
 </code>
- *
- * If this is executed by sending two messages CMD_1 and CMD_2
- * (Note the synchronize is only needed because we use hsm.wait())
- *
- * Hsm1 hsm = makeHsm1();
- * synchronize(hsm) {
- *      hsm.sendMessage(obtainMessage(hsm.CMD_1));
- *      hsm.sendMessage(obtainMessage(hsm.CMD_2));
- *      try {
- *           // wait for the messages to be handled
- *           hsm.wait();
- *      } catch (InterruptedException e) {
- *           Log.e(TAG, "exception while waiting " + e.getMessage());
- *      }
- * }
- *
- *
- * The output is:
- *
- * D/hsm1    ( 1999): makeHsm1 E
- * D/hsm1    ( 1999): ctor E
- * D/hsm1    ( 1999): ctor X
- * D/hsm1    ( 1999): mP1.enter
- * D/hsm1    ( 1999): mS1.enter
- * D/hsm1    ( 1999): makeHsm1 X
- * D/hsm1    ( 1999): mS1.processMessage what=1
- * D/hsm1    ( 1999): mS1.exit
- * D/hsm1    ( 1999): mS1.enter
- * D/hsm1    ( 1999): mS1.processMessage what=2
- * D/hsm1    ( 1999): mP1.processMessage what=2
- * D/hsm1    ( 1999): mS1.exit
- * D/hsm1    ( 1999): mS2.enter
- * D/hsm1    ( 1999): mS2.processMessage what=2
- * D/hsm1    ( 1999): mS2.processMessage what=3
- * D/hsm1    ( 1999): mS2.exit
- * D/hsm1    ( 1999): mP1.exit
- * D/hsm1    ( 1999): mP2.enter
- * D/hsm1    ( 1999): mP2.processMessage what=3
- * D/hsm1    ( 1999): mP2.processMessage what=4
- * D/hsm1    ( 1999): mP2.processMessage what=5
- * D/hsm1    ( 1999): mP2.exit
- * D/hsm1    ( 1999): halting
- *
+ * <p>If this is executed by sending two messages CMD_1 and CMD_2
+ * (Note the synchronize is only needed because we use hsm.wait())</p>
+<code>
+Hsm1 hsm = makeHsm1();
+synchronize(hsm) {
+     hsm.sendMessage(obtainMessage(hsm.CMD_1));
+     hsm.sendMessage(obtainMessage(hsm.CMD_2));
+     try {
+          // wait for the messages to be handled
+          hsm.wait();
+     } catch (InterruptedException e) {
+          Log.e(TAG, "exception while waiting " + e.getMessage());
+     }
+}
+</code>
+ * <p>The output is:</p>
+<code>
+D/hsm1    ( 1999): makeHsm1 E
+D/hsm1    ( 1999): ctor E
+D/hsm1    ( 1999): ctor X
+D/hsm1    ( 1999): mP1.enter
+D/hsm1    ( 1999): mS1.enter
+D/hsm1    ( 1999): makeHsm1 X
+D/hsm1    ( 1999): mS1.processMessage what=1
+D/hsm1    ( 1999): mS1.exit
+D/hsm1    ( 1999): mS1.enter
+D/hsm1    ( 1999): mS1.processMessage what=2
+D/hsm1    ( 1999): mP1.processMessage what=2
+D/hsm1    ( 1999): mS1.exit
+D/hsm1    ( 1999): mS2.enter
+D/hsm1    ( 1999): mS2.processMessage what=2
+D/hsm1    ( 1999): mS2.processMessage what=3
+D/hsm1    ( 1999): mS2.exit
+D/hsm1    ( 1999): mP1.exit
+D/hsm1    ( 1999): mP2.enter
+D/hsm1    ( 1999): mP2.processMessage what=3
+D/hsm1    ( 1999): mP2.processMessage what=4
+D/hsm1    ( 1999): mP2.processMessage what=5
+D/hsm1    ( 1999): mP2.exit
+D/hsm1    ( 1999): halting
+</code>
  */
 public class HierarchicalStateMachine {
 
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 7d8e624..7592e8b 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -57,7 +57,7 @@
     void updateStatusIcon(in IBinder token, String packageName, int iconId);
     void setIMEButtonVisible(in IBinder token, boolean visible);
     InputMethodSubtype getCurrentInputMethodSubtype();
+    boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
     boolean switchToLastInputMethod(in IBinder token);
-    
     boolean setInputMethodEnabled(String id, boolean enabled);
 }
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 1d103ed..1406e4e 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -110,8 +110,10 @@
         if (isShowing()) {
             mPopup.dismiss();
         }
-        mTreeObserver.removeGlobalOnLayoutListener(this);
-        mTreeObserver = null;
+        if (mTreeObserver != null) {
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+            mTreeObserver = null;
+        }
     }
 
     public boolean isShowing() {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 7a64da0..e18f58f 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -26,7 +26,6 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.TypedArray;
@@ -41,10 +40,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.ProgressBar;
 import android.widget.Spinner;
 import android.widget.SpinnerAdapter;
 import android.widget.TextView;
@@ -94,9 +95,15 @@
     private HorizontalScrollView mTabScrollView;
     private LinearLayout mTabLayout;
     private View mCustomNavView;
+    private ProgressBar mProgressView;
+    private ProgressBar mIndeterminateProgressView;
+
+    private int mProgressBarPadding;
     
     private int mTitleStyleRes;
     private int mSubtitleStyleRes;
+    private int mProgressStyle;
+    private int mIndeterminateProgressStyle;
 
     private boolean mShowMenu;
     private boolean mUserTitle;
@@ -185,6 +192,11 @@
         
         mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
         mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
+        mProgressStyle = a.getResourceId(R.styleable.ActionBar_progressBarStyle, 0);
+        mIndeterminateProgressStyle = a.getResourceId(
+                R.styleable.ActionBar_indeterminateProgressStyle, 0);
+
+        mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_progressBarPadding, 0);
 
         setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT));
 
@@ -208,7 +220,7 @@
             Context context = getContext();
             if (context instanceof Activity) {
               Activity activity = (Activity) context;
-              activity.onOptionsItemSelected(mLogoNavItem);
+              activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
             }
           }
         });
@@ -216,6 +228,20 @@
         mHomeLayout.setFocusable(true);
     }
 
+    public void initProgress() {
+        mProgressView = new ProgressBar(mContext, null, 0, mProgressStyle);
+        mProgressView.setId(R.id.progress_horizontal);
+        mProgressView.setMax(10000);
+        addView(mProgressView);
+    }
+
+    public void initIndeterminateProgress() {
+        mIndeterminateProgressView = new ProgressBar(mContext, null, 0,
+                mIndeterminateProgressStyle);
+        mIndeterminateProgressView.setId(R.id.progress_circular);
+        addView(mIndeterminateProgressView);
+    }
+
     @Override
     public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
         // No starting an action mode for an action bar child! (Where would it go?)
@@ -665,6 +691,13 @@
             break;
         }
 
+        if (mIndeterminateProgressView != null &&
+                mIndeterminateProgressView.getVisibility() != GONE) {
+            availableWidth = measureChildView(mIndeterminateProgressView, availableWidth,
+                    childSpecHeight, 0);
+            rightOfCenter -= mIndeterminateProgressView.getMeasuredWidth();
+        }
+
         if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
             final LayoutParams lp = generateLayoutParams(mCustomNavView.getLayoutParams());
             final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
@@ -726,6 +759,12 @@
         if (mContextView != null) {
             mContextView.setHeight(getMeasuredHeight());
         }
+
+        if (mProgressView != null && mProgressView.getVisibility() != GONE) {
+            mProgressView.measure(MeasureSpec.makeMeasureSpec(
+                    contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST));
+        }
     }
 
     private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
@@ -764,6 +803,7 @@
             if (mTabScrollView != null) {
                 x += positionChild(mTabScrollView, x, y, contentHeight);
             }
+            break;
         }
 
         int menuLeft = r - l - getPaddingRight();
@@ -772,6 +812,12 @@
             menuLeft -= mMenuView.getMeasuredWidth();
         }
 
+        if (mIndeterminateProgressView != null &&
+                mIndeterminateProgressView.getVisibility() != GONE) {
+            positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight);
+            menuLeft -= mIndeterminateProgressView.getMeasuredWidth();
+        }
+
         if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
             LayoutParams lp = mCustomNavView.getLayoutParams();
             final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
@@ -830,6 +876,13 @@
             }
             x += positionChild(mCustomNavView, xpos, ypos, contentHeight);
         }
+
+        if (mProgressView != null) {
+            mProgressView.bringToFront();
+            final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2;
+            mProgressView.layout(mProgressBarPadding, -halfProgressHeight,
+                    mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight);
+        }
     }
 
     private int positionChild(View child, int x, int y, int contentHeight) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1018ddb..e50233e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1194,6 +1194,7 @@
     REG_JNI(register_android_text_AndroidBidi),
     REG_JNI(register_android_text_KeyCharacterMap),
     REG_JNI(register_android_os_Process),
+    REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_view_Display),
     REG_JNI(register_android_nio_utils),
@@ -1251,7 +1252,6 @@
     REG_JNI(register_android_os_ParcelFileDescriptor),
     REG_JNI(register_android_os_Power),
     REG_JNI(register_android_os_StatFs),
-    REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_UEventObserver),
     REG_JNI(register_android_net_LocalSocketImpl),
     REG_JNI(register_android_net_NetworkUtils),
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 63550fb..f653b36 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -4,6 +4,7 @@
 #define LOG_TAG "EmojiFactory_jni"
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/String16.h>
 
 #include "EmojiFactory.h"
 #include <nativehelper/JNIHelp.h>
diff --git a/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png
index 192df6d2..079de61 100644
--- a/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png b/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png
index 223416d..2272b41 100644
--- a/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png
index 1a59124..16b7349 100644
--- a/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png b/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png
index f119c6a..7229343 100644
--- a/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png
index 3c6c5ed..894dfcf 100644
--- a/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png b/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png
index cab3888..f553ba6 100644
--- a/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_16_inner_holo.png b/core/res/res/drawable-hdpi/spinner_16_inner_holo.png
new file mode 100644
index 0000000..ff363f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_16_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_16_outer_holo.png b/core/res/res/drawable-hdpi/spinner_16_outer_holo.png
new file mode 100644
index 0000000..a5a0b98
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_16_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_20_inner_holo.png b/core/res/res/drawable-hdpi/spinner_20_inner_holo.png
new file mode 100644
index 0000000..16742e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_20_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_20_outer_holo.png b/core/res/res/drawable-hdpi/spinner_20_outer_holo.png
new file mode 100644
index 0000000..d6aa73b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_20_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_48_inner_holo.png b/core/res/res/drawable-hdpi/spinner_48_inner_holo.png
new file mode 100644
index 0000000..ee3f4c2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_48_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_48_outer_holo.png b/core/res/res/drawable-hdpi/spinner_48_outer_holo.png
new file mode 100644
index 0000000..7c59e2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_48_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_76_inner_holo.png b/core/res/res/drawable-hdpi/spinner_76_inner_holo.png
new file mode 100644
index 0000000..a1ef44c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_76_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_76_outer_holo.png b/core/res/res/drawable-hdpi/spinner_76_outer_holo.png
new file mode 100644
index 0000000..69e3ab7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_76_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_active_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_active_holo_dark.9.png
new file mode 100644
index 0000000..a38c03a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_active_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_active_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_active_holo_light.9.png
new file mode 100644
index 0000000..6a88a69
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_active_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
index 7ec2192..87d9c21 100644
--- a/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
index c03e4f6..720ee78 100644
--- a/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..4275da07
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..3ec9c1f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
index 6642717..227bde2 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
index 9572752..6ddfab0 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_dark.9.png
deleted file mode 100644
index 0ad248c..0000000
--- a/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_light.9.png
deleted file mode 100644
index b7a07c4..0000000
--- a/core/res/res/drawable-hdpi/textfield_disabled_selected_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_active_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_active_holo_dark.9.png
new file mode 100644
index 0000000..7528479
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_active_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_active_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_active_holo_light.9.png
new file mode 100644
index 0000000..4c7d9e7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_active_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png
new file mode 100644
index 0000000..09ca253
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png
new file mode 100644
index 0000000..0a7d3a1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..54a1519
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..06ca0d4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png
new file mode 100644
index 0000000..9015299
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png
new file mode 100644
index 0000000..b355cb3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed.9.png b/core/res/res/drawable-hdpi/textfield_pressed.9.png
deleted file mode 100644
index a42d87f..0000000
--- a/core/res/res/drawable-hdpi/textfield_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_pressed_holo_dark.9.png
deleted file mode 100644
index a271ac9b..0000000
--- a/core/res/res/drawable-hdpi/textfield_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_pressed_holo_light.9.png
deleted file mode 100644
index 521722d..0000000
--- a/core/res/res/drawable-hdpi/textfield_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_selected_holo_dark.9.png
deleted file mode 100644
index a271ac9b..0000000
--- a/core/res/res/drawable-hdpi/textfield_selected_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_selected_holo_light.9.png
deleted file mode 100644
index 521722d..0000000
--- a/core/res/res/drawable-hdpi/textfield_selected_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/textfield_pressed.9.png b/core/res/res/drawable-ldpi/textfield_pressed.9.png
deleted file mode 100644
index 1433365..0000000
--- a/core/res/res/drawable-ldpi/textfield_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png
index 316af64..0376e53 100644
--- a/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png b/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png
index e286136..e825119 100644
--- a/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png
index 0502669..e525eaf 100644
--- a/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png b/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png
index 1ba9e34..0532f0e 100644
--- a/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png
index a2fe2b3..99f8f06 100644
--- a/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png b/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png
index 3b264ab..198d7d9 100644
--- a/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_16_inner_holo.png b/core/res/res/drawable-mdpi/spinner_16_inner_holo.png
new file mode 100644
index 0000000..2703553
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_16_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_16_outer_holo.png b/core/res/res/drawable-mdpi/spinner_16_outer_holo.png
new file mode 100644
index 0000000..87d2c87
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_16_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_20_inner_holo.png b/core/res/res/drawable-mdpi/spinner_20_inner_holo.png
new file mode 100644
index 0000000..3c97355
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_20_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_20_outer_holo.png b/core/res/res/drawable-mdpi/spinner_20_outer_holo.png
new file mode 100644
index 0000000..96155e3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_20_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_48_inner_holo.png b/core/res/res/drawable-mdpi/spinner_48_inner_holo.png
new file mode 100644
index 0000000..26dcfbf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_48_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_48_outer_holo.png b/core/res/res/drawable-mdpi/spinner_48_outer_holo.png
new file mode 100644
index 0000000..49dad0c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_48_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_76_inner_holo.png b/core/res/res/drawable-mdpi/spinner_76_inner_holo.png
new file mode 100644
index 0000000..ebccabd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_76_inner_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_76_outer_holo.png b/core/res/res/drawable-mdpi/spinner_76_outer_holo.png
new file mode 100644
index 0000000..37d3f58
--- /dev/null
+++ b/core/res/res/drawable-mdpi/spinner_76_outer_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_active_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_active_holo_dark.9.png
new file mode 100644
index 0000000..d37c8b2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_active_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_active_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_active_holo_light.9.png
new file mode 100644
index 0000000..16f2197
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_active_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
index 3a5f36d..c98c951 100644
--- a/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
index b8cc76f..7691f81 100644
--- a/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..500ede3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..99f7f38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
index a1f0c71..fab86ac 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
index 71e3103..876eb794 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_dark.9.png
deleted file mode 100644
index ac6d406..0000000
--- a/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_light.9.png
deleted file mode 100644
index bb6e953..0000000
--- a/core/res/res/drawable-mdpi/textfield_disabled_selected_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png
new file mode 100644
index 0000000..2646899
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png
new file mode 100644
index 0000000..374d457
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png
new file mode 100644
index 0000000..65c87ba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png
new file mode 100644
index 0000000..724b3fd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..5f0ad56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..df03a15
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png
new file mode 100644
index 0000000..2cc7f62
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png
new file mode 100644
index 0000000..a2d9d8a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_pressed.9.png b/core/res/res/drawable-mdpi/textfield_pressed.9.png
deleted file mode 100644
index c909ad2..0000000
--- a/core/res/res/drawable-mdpi/textfield_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_pressed_holo_dark.9.png
deleted file mode 100644
index 7667d95..0000000
--- a/core/res/res/drawable-mdpi/textfield_pressed_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_pressed_holo_light.9.png
deleted file mode 100644
index 269affd..0000000
--- a/core/res/res/drawable-mdpi/textfield_pressed_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_selected_holo_dark.9.png
deleted file mode 100644
index 7667d95..0000000
--- a/core/res/res/drawable-mdpi/textfield_selected_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_selected_holo_light.9.png
deleted file mode 100644
index 269affd..0000000
--- a/core/res/res/drawable-mdpi/textfield_selected_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/edit_text.xml b/core/res/res/drawable/edit_text.xml
index 315278d..e9ba84b 100644
--- a/core/res/res/drawable/edit_text.xml
+++ b/core/res/res/drawable/edit_text.xml
@@ -15,11 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/textfield_default" />
-    <item android:state_window_focused="false" android:state_enabled="false"
-        android:drawable="@drawable/textfield_disabled" />
-    <item android:state_pressed="true" android:drawable="@drawable/textfield_pressed" />
+    <item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_default" />
+    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_disabled" />
     <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_selected" />
     <item android:state_enabled="true" android:drawable="@drawable/textfield_default" />
     <item android:state_focused="true" android:drawable="@drawable/textfield_disabled_selected" />
diff --git a/core/res/res/drawable/edit_text_holo_dark.xml b/core/res/res/drawable/edit_text_holo_dark.xml
index b7d24ff..63ccd1d 100644
--- a/core/res/res/drawable/edit_text_holo_dark.xml
+++ b/core/res/res/drawable/edit_text_holo_dark.xml
@@ -15,14 +15,11 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/textfield_default_holo_dark" />
-    <item android:state_window_focused="false" android:state_enabled="false"
-        android:drawable="@drawable/textfield_disabled_holo_dark" />
-    <item android:state_pressed="true" android:drawable="@drawable/textfield_pressed_holo_dark" />
-    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_selected_holo_dark" />
+    <item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_dark" />
+    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_disabled_holo_dark" />
+    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_active_holo_dark" />
     <item android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_dark" />
-    <item android:state_focused="true" android:drawable="@drawable/textfield_disabled_selected_holo_dark" />
+    <item android:state_focused="true" android:drawable="@drawable/textfield_disabled_focused_holo_dark" />
     <item android:drawable="@drawable/textfield_disabled_holo_dark" />
 </selector>
 
diff --git a/core/res/res/drawable/edit_text_holo_light.xml b/core/res/res/drawable/edit_text_holo_light.xml
index dae39e3..324acda 100644
--- a/core/res/res/drawable/edit_text_holo_light.xml
+++ b/core/res/res/drawable/edit_text_holo_light.xml
@@ -15,14 +15,11 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/textfield_default_holo_light" />
-    <item android:state_window_focused="false" android:state_enabled="false"
-        android:drawable="@drawable/textfield_disabled_holo_light" />
-    <item android:state_pressed="true" android:drawable="@drawable/textfield_pressed_holo_light" />
-    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_selected_holo_light" />
+    <item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_light" />
+    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_disabled_holo_light" />
+    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_active_holo_light" />
     <item android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_light" />
-    <item android:state_focused="true" android:drawable="@drawable/textfield_disabled_selected_holo_light" />
+    <item android:state_focused="true" android:drawable="@drawable/textfield_disabled_focused_holo_light" />
     <item android:drawable="@drawable/textfield_disabled_holo_light" />
 </selector>
 
diff --git a/core/res/res/drawable/edit_text_multiline_holo_dark.xml b/core/res/res/drawable/edit_text_multiline_holo_dark.xml
new file mode 100644
index 0000000..67d2748
--- /dev/null
+++ b/core/res/res/drawable/edit_text_multiline_holo_dark.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="false" android:state_enabled="true"  android:drawable="@drawable/textfield_multiline_default_holo_dark" />
+    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_multiline_disabled_holo_dark" />
+    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_active_holo_dark" />
+    <item android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_dark" />
+    <item android:state_focused="true" android:drawable="@drawable/textfield_multiline_disabled_focused_holo_dark" />
+    <item android:drawable="@drawable/textfield_multiline_disabled_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/edit_text_multiline_holo_light.xml b/core/res/res/drawable/edit_text_multiline_holo_light.xml
new file mode 100644
index 0000000..08b3ec6
--- /dev/null
+++ b/core/res/res/drawable/edit_text_multiline_holo_light.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="false" android:state_enabled="true"  android:drawable="@drawable/textfield_multiline_default_holo_light" />
+    <item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_multiline_disabled_holo_light" />
+    <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_active_holo_light" />
+    <item android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_light" />
+    <item android:state_focused="true" android:drawable="@drawable/textfield_multiline_disabled_focused_holo_light" />
+    <item android:drawable="@drawable/textfield_multiline_disabled_holo_light" />
+</selector>
diff --git a/core/res/res/drawable/progress_large_holo.xml b/core/res/res/drawable/progress_large_holo.xml
new file mode 100644
index 0000000..5865780
--- /dev/null
+++ b/core/res/res/drawable/progress_large_holo.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_76_outer_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="1080" />
+    </item>
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_76_inner_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="720"
+             android:toDegrees="0" />
+    </item>
+</layer-list>
diff --git a/core/res/res/drawable/progress_medium_holo.xml b/core/res/res/drawable/progress_medium_holo.xml
new file mode 100644
index 0000000..6772f58
--- /dev/null
+++ b/core/res/res/drawable/progress_medium_holo.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_48_outer_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="1080" />
+    </item>
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_48_inner_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="720"
+             android:toDegrees="0" />
+    </item>
+</layer-list>
diff --git a/core/res/res/drawable/progress_small_holo.xml b/core/res/res/drawable/progress_small_holo.xml
new file mode 100644
index 0000000..1d3b62b
--- /dev/null
+++ b/core/res/res/drawable/progress_small_holo.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_16_outer_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="1080" />
+    </item>
+    <item>
+        <rotate
+             android:drawable="@drawable/spinner_16_inner_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="720"
+             android:toDegrees="0" />
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/anim/navigation_in.xml b/core/res/res/drawable/screen_background_selector_dark.xml
similarity index 70%
rename from packages/SystemUI/res/anim/navigation_in.xml
rename to core/res/res/drawable/screen_background_selector_dark.xml
index 630fd72..2a81669 100644
--- a/packages/SystemUI/res/anim/navigation_in.xml
+++ b/core/res/res/drawable/screen_background_selector_dark.xml
@@ -14,9 +14,8 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_accelerated="false"
+            android:drawable="@android:drawable/screen_background_dark" />
+    <item android:drawable="@android:drawable/background_holo_dark" />
+</selector>
diff --git a/packages/SystemUI/res/anim/navigation_in.xml b/core/res/res/drawable/screen_background_selector_light.xml
similarity index 70%
copy from packages/SystemUI/res/anim/navigation_in.xml
copy to core/res/res/drawable/screen_background_selector_light.xml
index 630fd72..6992cad 100644
--- a/packages/SystemUI/res/anim/navigation_in.xml
+++ b/core/res/res/drawable/screen_background_selector_light.xml
@@ -14,9 +14,8 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_accelerated="false"
+            android:drawable="@android:drawable/screen_background_light" />
+    <item android:drawable="@android:drawable/background_holo_light" />
+</selector>
diff --git a/core/res/res/layout/progress_dialog.xml b/core/res/res/layout/progress_dialog.xml
index 298173a..08e720f 100644
--- a/core/res/res/layout/progress_dialog.xml
+++ b/core/res/res/layout/progress_dialog.xml
@@ -33,7 +33,7 @@
         android:paddingBottom="10dip">
 
         <ProgressBar android:id="@android:id/progress"
-            style="@android:style/Widget.ProgressBar"
+            style="?android:attr/progressBarStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:max="10000"
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
index cdf58fe..8f9b03d 100644
--- a/core/res/res/values-large/themes.xml
+++ b/core/res/res/values-large/themes.xml
@@ -19,4 +19,6 @@
 <resources>
     <style name="Theme.Holo.DialogWhenLarge" parent="@android:style/Theme.Holo.Dialog">
     </style>
+    <style name="Theme.Holo.Light.DialogWhenLarge" parent="@android:style/Theme.Holo.Light.Dialog">
+    </style>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d6684fe..55b3258 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -34,9 +34,11 @@
         <!-- Color that matches (as closely as possible) the window background. -->
         <attr name="colorBackground" format="color" />
         <!-- This is a hint for a solid color that can be used for caching
-             rendered views.  This will be the color of the background when
-             there is a solid background color; it will be null when the
-             background is a texture or translucent. -->
+             rendered views.  This should be the color of the background when
+             there is a solid background color; it should be null when the
+             background is a texture or translucent.  When a device is able
+             to use accelerated drawing (thus setting state_accelerated), the
+             cache hint is ignored and always assumed to be transparent. -->
         <attr name="colorBackgroundCacheHint" format="color" />
         <!-- Default disabled alpha for widgets that set enabled/disabled alpha programmatically. -->
         <attr name="disabledAlpha" format="float" />
@@ -140,6 +142,8 @@
         <attr name="editTextColor" format="reference|color" />
         <!-- EditText background drawable. -->
         <attr name="editTextBackground" format="reference" />
+        <!-- EditText background drawable for multiline EditText. -->
+        <attr name="editTextMultilineBackground" format="reference" />
 
         <!-- A styled string, specifying the style to be used for showing
              inline candidate text when composing with an input method.  The
@@ -227,8 +231,13 @@
         <!-- ============= -->
         <eat-comment />
 
-        <!-- Drawable to use as the overall window background.  There are a
-             few special considerations you should use when settings this
+        <!-- Drawable to use as the overall window background.  As of
+             {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this may
+             be a selector that uses state_accelerated to pick a non-solid
+             color when running on devices that can draw such a bitmap
+             with complex compositing on top at 60fps.
+             
+             <p>There are a few special considerations to use when setting this
              drawable:
              <ul>
              <li> This information will be used to infer the pixel format
@@ -2048,6 +2057,9 @@
         <attr name="baselineAlignBottom" format="boolean" />
          <!-- If true, the image will be cropped to fit within its padding. -->
         <attr name="cropToPadding" format="boolean" />
+        <!-- The offset of the baseline within this view. See {see android.view.View#getBaseline}
+             for details -->
+        <attr name="baseline" format="dimension" />
     </declare-styleable>
     <declare-styleable name="ToggleButton">
         <!-- The text for the button when it is checked. -->
@@ -2165,6 +2177,8 @@
         <attr name="minHeight" format="dimension" />
         <attr name="maxHeight" />
         <attr name="interpolator" format="reference" />
+        <!-- Timeout between frames of animation in milliseconds -->
+        <attr name="animationResolution" format="integer" />
     </declare-styleable>
 
     <declare-styleable name="SeekBar">
@@ -2496,7 +2510,8 @@
         <attr name="textLineHeight" />
         <!-- Indicates that a non-editable text can be selected. -->
         <attr name="textIsSelectable" />
-
+        <!--  A specific background drawable used by multi-line EditText only. -->
+        <attr name="multilineBackground" format="reference"/>
     </declare-styleable>
     <!-- An <code>input-extras</code> is a container for extra data to supply to
          an input method.  Contains
@@ -3394,16 +3409,24 @@
              marked it as being of interest.  This is an alternative representation of
              state_checked for when the state should be propagated down the view hierarchy. -->
         <attr name="state_activated" format="boolean" />
-        <!--  State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
         <attr name="state_active" format="boolean" />
-        <!--  State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
         <attr name="state_single" format="boolean" />
-        <!--  State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
         <attr name="state_first" format="boolean" />
-        <!--  State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
         <attr name="state_middle" format="boolean" />
-        <!--  State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}.-->
         <attr name="state_last" format="boolean" />
+        <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable},
+             indicating that the Drawable is in a view that is hardware accelerated.
+             This means that the device can at least render a full-screen scaled
+             bitmap with one layer of text and bitmaps composited on top of it
+             at 60fps.  When this is set, the colorBackgroundCacheHint will be
+             ignored even if it specifies a solid color, since that optimization
+             is not needed. -->
+        <attr name="state_accelerated" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewDrawableStates">
         <attr name="state_pressed" />
@@ -3412,6 +3435,7 @@
         <attr name="state_window_focused" />
         <attr name="state_enabled" />
         <attr name="state_activated" />
+        <attr name="state_accelerated" />
     </declare-styleable>
     <!-- State array representing a menu item that is currently checked. -->
     <declare-styleable name="MenuItemCheckedState">
@@ -4379,6 +4403,12 @@
         <attr name="height" />
         <!-- Specifies a drawable to use for the 'home as up' indicator. -->
         <attr name="homeAsUpIndicator" format="reference" />
+        <!-- Specifies a style resource to use for an embedded progress bar. -->
+        <attr name="progressBarStyle" />
+        <!-- Specifies a style resource to use for an indeterminate progress spinner. -->
+        <attr name="indeterminateProgressStyle" format="reference" />
+        <!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
+        <attr name="progressBarPadding" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 28df995..ad4e7a2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1372,6 +1372,11 @@
   <public type="attr" name="textEditNoPasteWindowLayout" />
   <public type="attr" name="textIsSelectable" />
   <public type="attr" name="windowEnableSplitTouch" />
+  <public type="attr" name="indeterminateProgressStyle" />
+  <public type="attr" name="progressBarPadding" />
+  <public type="attr" name="animationResolution" />
+  <public type="attr" name="state_accelerated" />
+  <public type="attr" name="baseline" />
 
   <public type="anim" name="animator_fade_in" />
   <public type="anim" name="animator_fade_out" />
@@ -1439,6 +1444,7 @@
   <public type="style" name="Widget.FragmentBreadCrumbs" />
 
   <public type="style" name="Theme.Holo.DialogWhenLarge" />
+  <public type="style" name="Theme.Holo.Light.DialogWhenLarge" />
   
   <public type="string" name="selectTextMode" />
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 457175b4..dc67f45 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -155,12 +155,6 @@
         <item name="windowExitAnimation">@anim/shrink_fade_out_from_bottom</item>
     </style>
 
-    <!-- {@hide} -->
-    <style name="Animation.SlidingCard">
-        <item name="windowEnterAnimation">@anim/slide_in_up</item>
-        <item name="windowExitAnimation">@anim/slide_out_down</item>
-    </style>
-
     <!-- Window animations that are applied to input method overlay windows. -->
     <style name="Animation.InputMethod">
         <item name="windowEnterAnimation">@anim/input_method_enter</item>
@@ -428,6 +422,7 @@
         <item name="android:focusableInTouchMode">true</item>
         <item name="android:clickable">true</item>
         <item name="android:background">?android:attr/editTextBackground</item>
+        <item name="android:multilineBackground">?android:attr/editTextMultilineBackground</item>
         <item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
         <item name="android:textColor">?android:attr/editTextColor</item>
         <item name="android:gravity">center_vertical</item>
@@ -920,6 +915,8 @@
         <item name="android:paddingBottom">0dip</item>
         <item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Title</item>
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Subtitle</item>
+        <item name="android:progressBarStyle">@android:style/Widget.ProgressBar.Horizontal</item>
+        <item name="android:indeterminateProgressStyle">@android:style/Widget.ProgressBar.Small</item>
     </style>
 
     <style name="Widget.ActionMode">
@@ -1356,30 +1353,34 @@
     </style>
 
     <style name="Widget.Holo.ProgressBar" parent="Widget.ProgressBar">
+        <item name="android:indeterminateDrawable">@android:drawable/progress_medium_holo</item>
+        <item name="android:animationResolution">33</item>
     </style>
 
     <style name="Widget.Holo.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal">
         <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_dark</item>
-        <item name="android:minHeight">16dip</item>
-        <item name="android:maxHeight">16dip</item>
+        <item name="android:minHeight">24dip</item>
+        <item name="android:maxHeight">24dip</item>
     </style>
 
-    <style name="Widget.Holo.ProgressBar.Small" parent="Widget.ProgressBar.Horizontal">
+    <style name="Widget.Holo.ProgressBar.Small" parent="Widget.ProgressBar.Small">
+        <item name="android:indeterminateDrawable">@android:drawable/progress_small_holo</item>
     </style>
 
-    <style name="Widget.Holo.ProgressBar.Small.Title" parent="Widget.ProgressBar.Small.Title">
+    <style name="Widget.Holo.ProgressBar.Small.Title">
     </style>
 
     <style name="Widget.Holo.ProgressBar.Large" parent="Widget.ProgressBar.Large">
+        <item name="android:indeterminateDrawable">@android:drawable/progress_large_holo</item>
     </style>
 
-    <style name="Widget.Holo.ProgressBar.Inverse" parent="Widget.ProgressBar.Inverse">
+    <style name="Widget.Holo.ProgressBar.Inverse">
     </style>
 
-    <style name="Widget.Holo.ProgressBar.Small.Inverse" parent="Widget.ProgressBar.Small.Inverse">
+    <style name="Widget.Holo.ProgressBar.Small.Inverse">
     </style>
 
-    <style name="Widget.Holo.ProgressBar.Large.Inverse" parent="Widget.ProgressBar.Large.Inverse">
+    <style name="Widget.Holo.ProgressBar.Large.Inverse">
     </style>
 
     <style name="Widget.Holo.SeekBar">
@@ -1540,6 +1541,9 @@
         <item name="android:background">@null</item>
         <item name="android:divider">?android:attr/dividerVertical</item>
         <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
+        <item name="android:progressBarStyle">@android:style/Widget.Holo.ProgressBar.Horizontal</item>
+        <item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.ProgressBar</item>
+        <item name="android:progressBarPadding">32dip</item>
     </style>
 
     <!-- Light widget styles -->
@@ -1645,29 +1649,29 @@
     <style name="Widget.Holo.Light.PopupWindow" parent="Widget.PopupWindow">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar" parent="Widget.ProgressBar">
+    <style name="Widget.Holo.Light.ProgressBar" parent="Widget.Holo.ProgressBar">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal">
+    <style name="Widget.Holo.Light.ProgressBar.Horizontal" parent="Widget.Holo.ProgressBar.Horizontal">
         <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_light</item>
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Small" parent="Widget.ProgressBar.Small">
+    <style name="Widget.Holo.Light.ProgressBar.Small" parent="Widget.Holo.ProgressBar.Small">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Small.Title" parent="Widget.ProgressBar.Small.Title">
+    <style name="Widget.Holo.Light.ProgressBar.Small.Title" parent="Widget.Holo.ProgressBar.Small.Title">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Large" parent="Widget.ProgressBar.Large">
+    <style name="Widget.Holo.Light.ProgressBar.Large" parent="Widget.Holo.ProgressBar.Large">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Inverse" parent="Widget.ProgressBar.Inverse">
+    <style name="Widget.Holo.Light.ProgressBar.Inverse" parent="Widget.Holo.ProgressBar.Inverse">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Small.Inverse" parent="Widget.ProgressBar.Small.Inverse">
+    <style name="Widget.Holo.Light.ProgressBar.Small.Inverse" parent="Widget.Holo.ProgressBar.Small.Inverse">
     </style>
 
-    <style name="Widget.Holo.Light.ProgressBar.Large.Inverse" parent="Widget.ProgressBar.Large.Inverse">
+    <style name="Widget.Holo.Light.ProgressBar.Large.Inverse" parent="Widget.Holo.ProgressBar.Large.Inverse">
     </style>
 
     <style name="Widget.Holo.Light.SeekBar" parent="Widget.Holo.SeekBar">
@@ -1794,6 +1798,8 @@
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
         <item name="android:background">@null</item>
         <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
+        <item name="android:progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
+        <item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.Light.ProgressBar.Small</item>
     </style>
 
     <!-- Animation Styles -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index c8cce81..dd7c8e48 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -72,6 +72,7 @@
         
         <item name="editTextColor">?android:attr/textColorPrimaryInverse</item>
         <item name="editTextBackground">@android:drawable/edit_text</item>
+        <item name="editTextMultilineBackground">@android:drawable/edit_text</item>
         
         <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
         
@@ -123,7 +124,7 @@
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
         
         <!-- Window attributes -->
-        <item name="windowBackground">@android:drawable/screen_background_dark</item>
+        <item name="windowBackground">@android:drawable/screen_background_selector_dark</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -279,7 +280,7 @@
          default theme, you should try to assume little more than that the
          background will be a light color. -->
     <style name="Theme.Light">
-        <item name="windowBackground">@drawable/screen_background_light</item>
+        <item name="windowBackground">@android:drawable/screen_background_selector_light</item>
         <item name="colorBackground">@android:color/background_light</item>
         <item name="colorForeground">@color/bright_foreground_light</item>
         <item name="colorForegroundInverse">@android:color/bright_foreground_light_inverse</item>
@@ -685,6 +686,7 @@
         
         <item name="editTextColor">?android:attr/textColorPrimary</item>
         <item name="editTextBackground">@android:drawable/edit_text_holo_dark</item>
+        <item name="editTextMultilineBackground">@android:drawable/edit_text_multiline_holo_dark</item>
         
         <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
         
@@ -736,7 +738,6 @@
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
         
         <!-- Window attributes -->
-        <item name="windowBackground">?android:attr/colorBackground</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -918,10 +919,11 @@
         <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.Holo.Light.SearchResult.Subtitle</item>
         
         <item name="textAppearanceButton">@android:style/TextAppearance.Holo.Light.Widget.Button</item>
-        
+
         <item name="editTextColor">?android:attr/textColorPrimary</item>
         <item name="editTextBackground">@android:drawable/edit_text_holo_light</item>
-        
+        <item name="editTextMultilineBackground">@android:drawable/edit_text_multiline_holo_light</item>
+
         <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
         
         <item name="textCheckMark">@android:drawable/indicator_check_mark_light</item>
@@ -972,7 +974,6 @@
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
         
         <!-- Window attributes -->
-        <item name="windowBackground">?android:attr/colorBackground</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -1031,15 +1032,15 @@
         <item name="imageWellStyle">@android:style/Widget.Holo.ImageWell</item>
         <item name="listViewStyle">@android:style/Widget.Holo.ListView</item>
         <item name="listViewWhiteStyle">@android:style/Widget.Holo.ListView.White</item>
-        <item name="popupWindowStyle">@android:style/Widget.Holo.PopupWindow</item>
-        <item name="progressBarStyle">@android:style/Widget.Holo.ProgressBar</item>
-        <item name="progressBarStyleHorizontal">@android:style/Widget.Holo.ProgressBar.Horizontal</item>
-        <item name="progressBarStyleSmall">@android:style/Widget.Holo.ProgressBar.Small</item>
-        <item name="progressBarStyleSmallTitle">@android:style/Widget.Holo.ProgressBar.Small.Title</item>
-        <item name="progressBarStyleLarge">@android:style/Widget.Holo.ProgressBar.Large</item>
-        <item name="progressBarStyleInverse">@android:style/Widget.Holo.ProgressBar.Inverse</item>
-        <item name="progressBarStyleSmallInverse">@android:style/Widget.Holo.ProgressBar.Small.Inverse</item>
-        <item name="progressBarStyleLargeInverse">@android:style/Widget.Holo.ProgressBar.Large.Inverse</item>
+        <item name="popupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow</item>
+        <item name="progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar</item>
+        <item name="progressBarStyleHorizontal">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
+        <item name="progressBarStyleSmall">@android:style/Widget.Holo.Light.ProgressBar.Small</item>
+        <item name="progressBarStyleSmallTitle">@android:style/Widget.Holo.Light.ProgressBar.Small.Title</item>
+        <item name="progressBarStyleLarge">@android:style/Widget.Holo.Light.ProgressBar.Large</item>
+        <item name="progressBarStyleInverse">@android:style/Widget.Holo.Light.ProgressBar.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@android:style/Widget.Holo.Light.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@android:style/Widget.Holo.Light.ProgressBar.Large.Inverse</item>
         <item name="seekBarStyle">@android:style/Widget.Holo.SeekBar</item>
         <item name="ratingBarStyle">@android:style/Widget.Holo.RatingBar</item>
         <item name="ratingBarStyleIndicator">@android:style/Widget.Holo.RatingBar.Indicator</item>
@@ -1220,6 +1221,12 @@
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
     </style>
 
+    <!-- Theme for a window that will be displayed either full-screen on
+         smaller screens (small, normal) or as a dialog on larger screens
+         (large, xlarge) -->
+    <style name="Theme.Holo.Light.DialogWhenLarge" parent="@android:style/Theme.Holo.Light">
+    </style>
+
     <!-- Holo light theme for alert dialog windows, which is used by the
          {@link android.app.AlertDialog} class.  This is basically a dialog
          but sets the background to empty so it can do two-tone backgrounds.
diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
new file mode 100755
index 0000000..2b0e4af
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <accesspoint>
+    <ssid>opennet</ssid>
+    <security>NONE</security>
+  </accesspoint>
+    <accesspoint>
+    <ssid>GoogleGuest</ssid>
+    <security>NONE</security>
+  </accesspoint>
+  <accesspoint>
+    <ssid>securenetdhcp</ssid>
+    <security>PSK</security>
+    <password>androidwifi</password>
+  </accesspoint>
+  <accesspoint>
+    <ssid>botnet</ssid>
+    <security>EAP</security>
+    <eap>PEAP</eap>
+    <phase2>MSCHAPV2</phase2>
+    <identity>donut</identity>
+    <password>android</password>
+  </accesspoint>
+</resources>
+
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
new file mode 100644
index 0000000..863fbe6
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -0,0 +1,262 @@
+/*
+ * 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.connectivitymanagertest;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+
+import android.util.Log;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Help class to process configurations of access points saved in an XML file.
+ * The configurations of an access point is included in tag
+ * <accesspoint></accesspoint>. The supported configuration includes: ssid,
+ * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert,
+ * in which each is included in the corresponding tags. All access points have to be
+ * enclosed in tags of <resources></resources>.
+ *
+ * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2.
+ * <resources>
+ *   <accesspoint>
+ *   <ssid>testnet</ssid>
+ *   <security>EAP</security>
+ *   <eap>PEAP</eap>
+ *   <phase2>MSCHAP2</phase2>
+ *   <identity>donut</identity</identity>
+ *   <password>abcdefgh</password>
+ *   </accesspoint>
+ * </resources>
+ */
+public class AccessPointParserHelper {
+    private static final String KEYSTORE_SPACE = "keystore://";
+    private static final String TAG = "AccessPointParserHelper";
+    static final int NONE = 0;
+    static final int WEP = 1;
+    static final int PSK = 2;
+    static final int EAP = 3;
+
+    List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
+
+    private int getSecurityType (String security) {
+        if (security.equalsIgnoreCase("NONE")) {
+            return NONE;
+        } else if (security.equalsIgnoreCase("WEP")) {
+            return WEP;
+        } else if (security.equalsIgnoreCase("PSK")) {
+            return PSK;
+        } else if (security.equalsIgnoreCase("EAP")) {
+            return EAP;
+        } else {
+            return -1;
+        }
+    }
+
+    private boolean validateEapValue(String value) {
+        if (value.equalsIgnoreCase("PEAP") ||
+                value.equalsIgnoreCase("TLS") ||
+                value.equalsIgnoreCase("TTLS")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    DefaultHandler mHandler = new DefaultHandler() {
+
+        boolean ssid = false;
+        boolean security = false;
+        boolean password = false;
+        boolean ip = false;
+        boolean subnetmask = false;
+        boolean gateway = false;
+        boolean dns = false;
+        boolean eap = false;
+        boolean phase2 = false;
+        boolean identity = false;
+        boolean anonymousidentity = false;
+        boolean cacert = false;
+        boolean usercert = false;
+        WifiConfiguration config = null;
+        int securityType = NONE;
+
+        @Override
+        public void startElement(String uri, String localName, String tagName,
+                Attributes attributes) throws SAXException {
+            if (tagName.equalsIgnoreCase("accesspoint")) {
+                config = new WifiConfiguration();
+            }
+            if (tagName.equalsIgnoreCase("ssid")) {
+                ssid = true;
+            }
+            if (tagName.equalsIgnoreCase("security")) {
+                security = true;
+            }
+            if (tagName.equalsIgnoreCase("password")) {
+                password = true;
+            }
+            if (tagName.equalsIgnoreCase("eap")) {
+                eap = true;
+            }
+            if (tagName.equalsIgnoreCase("phase2")) {
+                phase2 = true;
+            }
+            if (tagName.equalsIgnoreCase("identity")) {
+                identity = true;
+            }
+            if (tagName.equalsIgnoreCase("anonymousidentity")) {
+                anonymousidentity = true;
+            }
+            if (tagName.equalsIgnoreCase("cacert")) {
+                cacert = true;
+            }
+            if (tagName.equalsIgnoreCase("usercert")) {
+                usercert = true;
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String tagName) throws SAXException {
+            Log.v(TAG, "endElement: " + tagName);
+            if (tagName.equalsIgnoreCase("accesspoint")) {
+                networks.add(config);
+            }
+        }
+
+        @Override
+        public void characters(char ch[], int start, int length) throws SAXException {
+            if (ssid) {
+                config.SSID = new String(ch, start, length);
+                Log.v(TAG, "ssid: " + config.SSID);
+                ssid = false;
+            }
+            if (security) {
+                String securityStr = (new String(ch, start, length)).toUpperCase();
+                Log.v(TAG, "security: " + securityStr);
+                securityType = getSecurityType(securityStr);
+                Log.v(TAG, "securityType = " + securityType);
+                switch (securityType) {
+                    case NONE:
+                        config.allowedKeyManagement.set(KeyMgmt.NONE);
+                        break;
+                    case WEP:
+                        config.allowedKeyManagement.set(KeyMgmt.NONE);
+                        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+                        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+                        break;
+                    case PSK:
+                        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+                        break;
+                    case EAP:
+                        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+                        config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+                        break;
+                    default:
+                        throw new SAXException();
+                }
+                security = false;
+            }
+            if (password) {
+                String passwordStr = new String(ch, start, length);
+                int len = passwordStr.length();
+                if (len == 0) {
+                    throw new SAXException();
+                }
+                Log.v(TAG, "passwordStr:" + passwordStr);
+                if (securityType == WEP) {
+                    if ((len == 10 || len == 26 || len == 58) &&
+                            passwordStr.matches("[0-9A-Fa-f]*")) {
+                        config.wepKeys[0] = passwordStr;
+                    } else {
+                        config.wepKeys[0] = '"' + passwordStr + '"';
+                    }
+                } else if (securityType == PSK) {
+                    if (passwordStr.matches("[0-9A-Fa-f]{64}")) {
+                        config.preSharedKey = passwordStr;
+                    } else {
+                        config.preSharedKey = '"' + passwordStr + '"';
+                    }
+                } else if (securityType == EAP) {
+                    config.password.setValue(passwordStr);
+                } else {
+                    throw new SAXException();
+                }
+                password = false;
+            }
+            if (eap) {
+                String eapValue = new String(ch, start, length);
+                if (!validateEapValue(eapValue)) {
+                    throw new SAXException();
+                }
+                config.eap.setValue(eapValue);
+                eap = false;
+            }
+            if (phase2) {
+                String phase2Value = new String(ch, start, length);
+                config.phase2.setValue("auth=" + phase2Value);
+                phase2 = false;
+            }
+            if (identity) {
+                String identityValue = new String(ch, start, length);
+                config.identity.setValue(identityValue);
+                identity = false;
+            }
+            if (anonymousidentity) {
+                String anonyId = new String(ch, start, length);
+                config.anonymous_identity.setValue(anonyId);
+                anonymousidentity = false;
+            }
+            if (cacert) {
+                String cacertValue = new String(ch, start, length);
+                // need to install the credentail to "keystore://"
+                config.ca_cert.setValue(KEYSTORE_SPACE);
+                cacert = false;
+            }
+            if (usercert) {
+                String usercertValue = new String(ch, start, length);
+                config.client_cert.setValue(KEYSTORE_SPACE);
+                usercert = false;
+            }
+        }
+    };
+
+    public AccessPointParserHelper() {
+    }
+
+    /**
+     * Process the accesspoint.xml file
+     * @return List of WifiConfiguration
+     * @throws Exception when parsing the XML file
+     */
+    public List<WifiConfiguration> processAccessPoint(InputStream in) throws Exception {
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        SAXParser saxParser = factory.newSAXParser();
+        saxParser.parse(in, mHandler);
+        return networks;
+    }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index e42b657..7c46e7a 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -16,8 +16,10 @@
 
 package com.android.connectivitymanagertest;
 
+import com.android.connectivitymanagertest.R;
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -25,19 +27,22 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.view.KeyEvent;
+
+import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 import android.widget.LinearLayout;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
 
+import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 
-
 /**
  * An activity registered with connectivity manager broadcast
  * provides network connectivity information and
@@ -46,8 +51,11 @@
 public class ConnectivityManagerTestActivity extends Activity {
 
     public static final String LOG_TAG = "ConnectivityManagerTestActivity";
-    public static final int WAIT_FOR_SCAN_RESULT = 5 * 1000; //5 seconds
+    public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
     public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
+    public static final int SHORT_TIMEOUT = 5 * 1000;
+    public static final long LONG_TIMEOUT = 50 * 1000;
+    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
     public ConnectivityReceiver mConnectivityReceiver = null;
     public WifiReceiver mWifiReceiver = null;
     /*
@@ -175,6 +183,7 @@
         mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
         mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
         registerReceiver(mWifiReceiver, mIntentFilter);
 
         // Get an instance of ConnectivityManager
@@ -185,10 +194,26 @@
 
         if (mWifiManager.isWifiEnabled()) {
             Log.v(LOG_TAG, "Clear Wifi before we start the test.");
-            clearWifi();
+            removeConfiguredNetworksAndDisableWifi();
         }
      }
 
+    public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
+        InputStream in = getAssets().open(ACCESS_POINT_FILE);
+        AccessPointParserHelper parseHelper = new AccessPointParserHelper();
+        return parseHelper.processAccessPoint(in);
+    }
+
+    private void printNetConfig(String[] configuration) {
+        for (int i = 0; i < configuration.length; i++) {
+            if (i == 0) {
+                Log.v(LOG_TAG, "SSID: " + configuration[0]);
+            } else {
+                Log.v(LOG_TAG, "      " + configuration[i]);
+            }
+        }
+    }
+
     // for each network type, initialize network states to UNKNOWN, and no verification flag is set
     public void initializeNetworkStates() {
         for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
@@ -245,6 +270,68 @@
         }
     }
 
+    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
+    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
+    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
+                    return false;
+                } else {
+                    // the broadcast has been sent out. the state has been changed.
+                    Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
+                            mCM.getNetworkInfo(networkType));
+                    return true;
+                }
+            }
+            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+                    " to be " + expectedState.toString());
+            synchronized (connectivityObject) {
+                try {
+                    connectivityObject.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if ((mNetworkInfo.getType() != networkType) ||
+                    (mNetworkInfo.getState() != expectedState)) {
+                    Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
+                            "is: " + mNetworkInfo.getState());
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
+    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
+    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
+    public boolean waitForWifiState(int expectedState, long timeout) {
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (mWifiState != expectedState) {
+                    return false;
+                } else {
+                    return true;
+                }
+            }
+            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+            synchronized (wifiObject) {
+                try {
+                    wifiObject.wait(SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                if (mWifiState != expectedState) {
+                    Log.v(LOG_TAG, "Wifi state is: " + mWifiNetworkInfo.getState());
+                    continue;
+                }
+                return true;
+            }
+        }
+    }
+
     // Return true if device is currently connected to mobile network
     public boolean isConnectedToMobile() {
         return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
@@ -265,6 +352,22 @@
      * We don't verify whether the connection is successful or not, leave this to the test
      */
     public boolean connectToWifi(String knownSSID) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = knownSSID;
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        return connectToWifiWithConfiguration(config);
+    }
+
+    /**
+     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
+     * is pure string, we need to convert it to quoted string.
+     * @param config
+     * @return
+     */
+    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
+        String ssid = config.SSID;
+        config.SSID = convertToQuotedString(ssid);
+
         //If Wifi is not enabled, enable it
         if (!mWifiManager.isWifiEnabled()) {
             Log.v(LOG_TAG, "Wifi is not enabled, enable it");
@@ -273,6 +376,7 @@
 
         List<ScanResult> netList = mWifiManager.getScanResults();
         if (netList == null) {
+            Log.v(LOG_TAG, "scan results are null");
             // if no scan results are available, start active scan
             mWifiManager.startScanActive();
             mScanResultIsAvailable = false;
@@ -299,17 +403,20 @@
         }
 
         netList = mWifiManager.getScanResults();
+
         for (int i = 0; i < netList.size(); i++) {
             ScanResult sr= netList.get(i);
-            if (sr.SSID.equals(knownSSID)) {
-                Log.v(LOG_TAG, "found " + knownSSID + " in the scan result list");
-                WifiConfiguration config = new WifiConfiguration();
-                config.SSID = convertToQuotedString(sr.SSID);
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
+            if (sr.SSID.equals(ssid)) {
+                Log.v(LOG_TAG, "found " + ssid + " in the scan result list");
                 int networkId = mWifiManager.addNetwork(config);
                 // Connect to network by disabling others.
                 mWifiManager.enableNetwork(networkId, true);
                 mWifiManager.saveConfiguration();
+                List<WifiConfiguration> wifiNetworks = mWifiManager.getConfiguredNetworks();
+                for (WifiConfiguration netConfig : wifiNetworks) {
+                    Log.v(LOG_TAG, netConfig.toString());
+                }
+
                 mWifiManager.reconnect();
                 break;
            }
@@ -317,14 +424,14 @@
 
         List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
         if (netConfList.size() <= 0) {
-            Log.v(LOG_TAG, knownSSID + " is not available");
+            Log.v(LOG_TAG, ssid + " is not available");
             return false;
         }
         return true;
     }
 
     /*
-     * Disconnect from the current AP
+     * Disconnect from the current AP and remove configured networks.
      */
     public boolean disconnectAP() {
         if (mWifiManager.isWifiEnabled()) {
@@ -360,9 +467,9 @@
     }
 
     /**
-     * Disconnect from the current Wifi and clear the configuration list
+     * Remove configured networks and disable wifi
      */
-    public boolean clearWifi() {
+    public boolean removeConfiguredNetworksAndDisableWifi() {
             if (!disconnectAP()) {
                 return false;
             }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 592be92..3d4dc3d 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -21,6 +21,7 @@
 import android.test.InstrumentationTestSuite;
 import android.util.Log;
 import com.android.connectivitymanagertest.functional.ConnectivityManagerMobileTest;
+import com.android.connectivitymanagertest.functional.WifiConnectionTest;
 
 import junit.framework.TestSuite;
 
@@ -38,6 +39,7 @@
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
         suite.addTestSuite(ConnectivityManagerMobileTest.class);
+        suite.addTestSuite(WifiConnectionTest.class);
         return suite;
     }
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index ad8d444..5959cf3 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -41,8 +41,6 @@
     extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
     private static final String LOG_TAG = "ConnectivityManagerMobileTest";
     private static final String PKG_NAME = "com.android.connectivitymanagertest";
-    private static final long STATE_TRANSITION_SHORT_TIMEOUT = 5 * 1000;
-    private static final long STATE_TRANSITION_LONG_TIMEOUT = 30 * 1000;
 
     private String TEST_ACCESS_POINT;
     private ConnectivityManagerTestActivity cmActivity;
@@ -64,9 +62,14 @@
         wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "CMWakeLock");
         wl.acquire();
         // Each test case will start with cellular connection
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
-        verifyCellularConnection();
+        if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+            // Note: When the test fails in setUp(), tearDown is not called. In that case,
+            // the activity is destroyed which blocks the next test at "getActivity()".
+            // tearDown() is called hear to avoid that situation.
+            tearDown();
+            fail("Device is not connected to Mobile, setUp failed");
+        }
     }
 
     @Override
@@ -74,86 +77,26 @@
         cmActivity.finish();
         Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity");
         wl.release();
-        cmActivity.clearWifi();
+        cmActivity.removeConfiguredNetworksAndDisableWifi();
         super.tearDown();
     }
 
     // help function to verify 3G connection
     public void verifyCellularConnection() {
-        NetworkInfo extraNetInfo = cmActivity.mNetworkInfo;
+        NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo();
         assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
-            extraNetInfo.getType());
+                extraNetInfo.getType());
         assertTrue("not connected to cellular network", extraNetInfo.isConnected());
         assertTrue("no data connection", cmActivity.mState.equals(State.CONNECTED));
     }
 
-    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
-    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
-    private void waitForNetworkState(int networkType, State expectedState, long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                if (cmActivity.mCM.getNetworkInfo(networkType).getState() != expectedState) {
-                    assertFalse("Wait for network state timeout", true);
-                } else {
-                    // the broadcast has been sent out. the state has been changed.
-                    return;
-                }
-            }
-            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
-                    " to be " + expectedState.toString());
-            synchronized (cmActivity.connectivityObject) {
-                try {
-                    cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if ((cmActivity.mNetworkInfo.getType() != networkType) ||
-                    (cmActivity.mNetworkInfo.getState() != expectedState)) {
-                    Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
-                            "is: " + cmActivity.mNetworkInfo.getState());
-                    continue;
-                }
-                break;
-            }
-        }
-    }
-
-    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
-    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
-    private void waitForWifiState(int expectedState, long timeout) {
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            if ((System.currentTimeMillis() - startTime) > timeout) {
-                if (cmActivity.mWifiState != expectedState) {
-                    assertFalse("Wait for Wifi state timeout", true);
-                } else {
-                    return;
-                }
-            }
-            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
-            synchronized (cmActivity.wifiObject) {
-                try {
-                    cmActivity.wifiObject.wait(5*1000);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                if (cmActivity.mWifiState != expectedState) {
-                    Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
-                    continue;
-                }
-                break;
-            }
-        }
-    }
-
     // Test case 1: Test enabling Wifi without associating with any AP
     @LargeTest
     public void test3GToWifiNotification() {
         // To avoid UNKNOWN state when device boots up
         cmActivity.enableWifi();
         try {
-            Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -170,7 +113,7 @@
         // Eanble Wifi
         cmActivity.enableWifi();
         try {
-            Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -208,12 +151,13 @@
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                 cmActivity.connectToWifi(TEST_ACCESS_POINT));
 
-        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
         Log.v(LOG_TAG, "wifi state is enabled");
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // validate states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -237,12 +181,13 @@
         // Connect to TEST_ACCESS_POINT
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                 cmActivity.connectToWifi(TEST_ACCESS_POINT));
-        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -255,11 +200,12 @@
         }
 
         // Wait for the Wifi state to be DISABLED
-        waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         //Prepare for connectivity state verification
         NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
@@ -275,10 +221,10 @@
         cmActivity.enableWifi();
 
         // Wait for Wifi to be connected and mobile to be disconnected
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // validate wifi states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -298,12 +244,12 @@
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                    cmActivity.connectToWifi(TEST_ACCESS_POINT));
 
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-            STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+            ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -318,12 +264,12 @@
                 NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
 
         // clear Wifi
-        cmActivity.clearWifi();
+        cmActivity.removeConfiguredNetworksAndDisableWifi();
 
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // validate states
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -357,7 +303,7 @@
         // Enable airplane mode
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -389,8 +335,8 @@
         // disable airplane mode
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
 
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // Validate the state transition
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
@@ -414,8 +360,8 @@
         // Eanble airplane mode
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
 
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
         cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -429,8 +375,8 @@
         // Connect to Wifi
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                    cmActivity.connectToWifi(TEST_ACCESS_POINT));
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // validate state and broadcast
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -457,11 +403,11 @@
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                 cmActivity.connectToWifi(TEST_ACCESS_POINT));
 
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -469,11 +415,11 @@
         // Enable airplane mode without clearing Wifi
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
 
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -487,10 +433,10 @@
         // Disable airplane mode
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
 
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
-                            STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
+                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         // validate the state transition
         if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
@@ -508,14 +454,15 @@
         //Connect to TEST_ACCESS_POINT
         assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                    cmActivity.connectToWifi(TEST_ACCESS_POINT));
-        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
-                            STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+                            ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertNotNull("Not associated with any AP",
                       cmActivity.mWifiManager.getConnectionInfo().getBSSID());
 
         try {
-            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
+            Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
         } catch (Exception e) {
             Log.v(LOG_TAG, "exception: " + e.toString());
         }
@@ -527,13 +474,14 @@
         }
 
         // Verify the connectivity state for Wifi is DISCONNECTED
-        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
-                STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
 
         if (!cmActivity.disableWifi()) {
             Log.v(LOG_TAG, "disable Wifi failed");
             return;
         }
-        waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
+        assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
+                ConnectivityManagerTestActivity.LONG_TIMEOUT));
     }
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
new file mode 100644
index 0000000..69eb5db
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.connectivitymanagertest.functional;
+
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.NetworkState;
+
+import android.R;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test Wi-Fi connection with different configuration
+ * To run this tests:
+ *     adb shell am instrument -e class
+ *          com.android.connectivitymanagertest.functional.WifiConnectionTest
+ *          -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
+ */
+public class WifiConnectionTest
+    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+    private static final String TAG = "WifiConnectionTest";
+    private static final boolean DEBUG = true;
+    private static final String PKG_NAME = "com.android.connectivitymanagertests";
+    private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
+    private ConnectivityManagerTestActivity mAct;
+
+    public WifiConnectionTest() {
+        super(PKG_NAME, ConnectivityManagerTestActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mAct = getActivity();
+        networks = mAct.loadNetworkConfigurations();
+        if (DEBUG) {
+            printNetworkConfigurations();
+        }
+
+        // enable Wifi and verify wpa_supplicant is started
+        assertTrue("enable Wifi failed", mAct.enableWifi());
+        try {
+            Thread.sleep( 2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+        } catch (Exception e) {
+            fail("interrupted while waiting for WPA_SUPPLICANT to start");
+        }
+        WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+        assertNotNull(mConnection);
+        assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+    }
+
+    private void printNetworkConfigurations() {
+        Log.v(TAG, "==== print network configurations parsed from XML file ====");
+        Log.v(TAG, "number of access points: " + networks.size());
+        for (WifiConfiguration config : networks) {
+            Log.v(TAG, config.toString());
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mAct.removeConfiguredNetworksAndDisableWifi();
+        super.tearDown();
+    }
+
+    /**
+     * Connect to the provided Wi-Fi network
+     * @param config is the network configuration
+     * @return true if the connection is successful.
+     */
+    private void connectToWifi(WifiConfiguration config) {
+        // step 1: connect to the test access point
+        assertTrue("failed to connect to " + config.SSID,
+                mAct.connectToWifiWithConfiguration(config));
+
+        // step 2: verify Wifi state and network state;
+        assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+                ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+        assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+                State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+
+        // step 3: verify the current connected network is the given SSID
+        if (DEBUG) {
+            Log.v(TAG, "config.SSID = " + config.SSID);
+            Log.v(TAG, "mAct.mWifiManager.getConnectionInfo.getSSID()" +
+                    mAct.mWifiManager.getConnectionInfo().getSSID());
+        }
+        assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+
+        // Maintain the connection for 50 seconds before switching
+        try {
+            Thread.sleep(50*1000);
+        } catch (Exception e) {
+            fail("interrupted while waiting for WPA_SUPPLICANT to start");
+        }
+    }
+
+    @LargeTest
+    public void testWifiConnections() {
+        for (int i = 0; i < networks.size(); i++) {
+            connectToWifi(networks.get(i));
+            mAct.removeConfiguredNetworksAndDisableWifi();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index f019599..43cf06a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -110,6 +110,21 @@
         mTestUtils.disable(adapter);
     }
 
+    public void testAcceptPair() {
+        int iterations = BluetoothTestRunner.sPairIterations;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress);
+        mTestUtils.enable(adapter);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                    BluetoothTestRunner.sPairPin);
+            mTestUtils.unpair(adapter, device);
+        }
+        mTestUtils.disable(adapter);
+    }
+
     public void testConnectA2dp() {
         int iterations = BluetoothTestRunner.sConnectA2dpIterations;
         if (iterations == 0) {
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 328891c..29dee34 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -137,7 +137,6 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.i("BT", intent.toString());
             if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
                 setFiredFlag(DISCOVERY_STARTED_FLAG);
             } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
@@ -203,7 +202,7 @@
             if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
                 int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
                 assertNotSame(-1, varient);
-                switch(varient) {
+                switch (varient) {
                     case BluetoothDevice.PAIRING_VARIANT_PIN:
                         mDevice.setPin(mPin);
                         break;
@@ -252,7 +251,7 @@
             mDevice = device;
             mProfile = profile;
 
-            switch(mProfile) {
+            switch (mProfile) {
                 case BluetoothProfile.A2DP:
                     mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED;
                     break;
@@ -384,11 +383,14 @@
                 mask = 0; // Don't check for received intents since we might have missed them.
                 break;
             case BluetoothAdapter.STATE_OFF:
-            case BluetoothAdapter.STATE_TURNING_OFF:
                 assertFalse(adapter.isEnabled());
                 start = System.currentTimeMillis();
                 assertTrue(adapter.enable());
                 break;
+            case BluetoothAdapter.STATE_TURNING_OFF:
+                start = System.currentTimeMillis();
+                assertTrue(adapter.enable());
+                break;
             default:
                 removeReceiver(receiver);
                 fail(String.format("enable() invalid state: state=%d", state));
@@ -410,7 +412,6 @@
                     return;
                 }
             } else {
-                assertFalse(adapter.isEnabled());
                 assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
             }
             sleep(POLL_TIME);
@@ -437,7 +438,6 @@
             case BluetoothAdapter.STATE_TURNING_ON:
                 assertFalse(adapter.isEnabled());
                 start = System.currentTimeMillis();
-                assertTrue(adapter.disable());
                 break;
             case BluetoothAdapter.STATE_ON:
                 assertTrue(adapter.isEnabled());
@@ -470,7 +470,6 @@
                     return;
                 }
             } else {
-                assertFalse(adapter.isEnabled());
                 assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
             }
             sleep(POLL_TIME);
@@ -629,11 +628,22 @@
     }
 
     public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
+        pairOrAcceptPair(adapter, device, passkey, pin, true);
+    }
+
+    public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
+            byte[] pin) {
+        pairOrAcceptPair(adapter, device, passkey, pin, false);
+    }
+
+    private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
+            byte[] pin, boolean pair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
+        String methodName = pair ? "pair()" : "acceptPair()";
 
         if (!adapter.isEnabled()) {
-            fail("pair() bluetooth not enabled");
+            fail(methodName + " bluetooth not enabled");
         }
 
         PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
@@ -643,7 +653,9 @@
             case BluetoothDevice.BOND_NONE:
                 assertFalse(adapter.getBondedDevices().contains(device));
                 start = System.currentTimeMillis();
-                assertTrue(device.createBond());
+                if (pair) {
+                    assertTrue(device.createBond());
+                }
                 break;
             case BluetoothDevice.BOND_BONDING:
                 mask = 0; // Don't check for received intents since we might have missed them.
@@ -653,7 +665,8 @@
                 return;
             default:
                 removeReceiver(receiver);
-                fail(String.format("pair() invalid state: device=%s, state=%d", device, state));
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
         }
 
         long s = System.currentTimeMillis();
@@ -664,10 +677,10 @@
                 if ((receiver.getFiredFlags() & mask) == mask) {
                     long finish = receiver.getCompletedTime();
                     if (start != -1 && finish != -1) {
-                        writeOutput(String.format("pair() completed in %d ms: device=%s",
+                        writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
                                 (finish - start), device));
                     } else {
-                        writeOutput(String.format("pair() completed: device=%s", device));
+                        writeOutput(String.format("%s completed: device=%s", methodName, device));
                     }
                     removeReceiver(receiver);
                     return;
@@ -678,9 +691,9 @@
 
         int firedFlags = receiver.getFiredFlags();
         removeReceiver(receiver);
-        fail(String.format("pair() timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%x)", device, state, BluetoothDevice.BOND_BONDED,
-                firedFlags, mask));
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%x)", methodName, device, state,
+                BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
@@ -788,7 +801,7 @@
                     long finish = receiver.getCompletedTime();
                     if (start != -1 && finish != -1) {
                         writeOutput(String.format("connectProfile() completed in %d ms: "
-                                +"device=%s, profile=%d", (finish - start), device, profile));
+                                + "device=%s, profile=%d", (finish - start), device, profile));
                     } else {
                         writeOutput(String.format("connectProfile() completed: device=%s, "
                                 + "profile=%d", device, profile));
@@ -857,7 +870,7 @@
                     long finish = receiver.getCompletedTime();
                     if (start != -1 && finish != -1) {
                         writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                                +"device=%s, profile=%d", (finish - start), device, profile));
+                                + "device=%s, profile=%d", (finish - start), device, profile));
                     } else {
                         writeOutput(String.format("disconnectProfile() completed: device=%s, "
                                 + "profile=%d", device, profile));
@@ -934,14 +947,12 @@
         long s = System.currentTimeMillis();
         switch (profile) {
             case BluetoothProfile.A2DP:
-                while (mA2dp != null
-                        && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                while (mA2dp != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                     sleep(POLL_TIME);
                 }
                 return mA2dp;
             case BluetoothProfile.HEADSET:
-                while (mHeadset != null
-                        && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                while (mHeadset != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                     sleep(POLL_TIME);
                 }
                 return mHeadset;
diff --git a/core/tests/coretests/src/android/os/AsyncChannelTest.java b/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
similarity index 83%
rename from core/tests/coretests/src/android/os/AsyncChannelTest.java
rename to core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
index 43c8290..7088650 100644
--- a/core/tests/coretests/src/android/os/AsyncChannelTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package android.os;
+package com.android.internal.util;
 
+import android.os.Debug;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
@@ -26,13 +27,17 @@
  */
 public class AsyncChannelTest extends TestCase {
     private static final boolean DBG = true;
-    private static final boolean WAIT_FOR_DEBUGGER = true;
+    private static final boolean WAIT_FOR_DEBUGGER = false;
     private static final String TAG = "AsyncChannelTest";
 
     @SmallTest
     public void test1() throws Exception {
+        if (DBG) log("test1");
         if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
-        Log.d(TAG, "test1");
         assertTrue(1 == 1);
     }
+
+    protected void log(String s) {
+        Log.d(TAG, s);
+    }
 }
diff --git a/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java b/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
similarity index 99%
rename from core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java
rename to core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
index 6820987..36666c4 100644
--- a/core/tests/coretests/src/android/os/HierarchicalStateMachineTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
@@ -14,7 +14,13 @@
  * limitations under the License.
  */
 
-package android.os;
+package com.android.internal.util;
+
+import android.os.Debug;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
 
 import com.android.internal.util.HierarchicalState;
 import com.android.internal.util.HierarchicalStateMachine;
@@ -28,8 +34,6 @@
 
 /**
  * Test for HierarchicalStateMachine.
- *
- * @author wink@google.com (Wink Saville)
  */
 public class HierarchicalStateMachineTest extends TestCase {
     private static final int TEST_CMD_1 = 1;
@@ -40,7 +44,7 @@
     private static final int TEST_CMD_6 = 6;
 
     private static final boolean DBG = true;
-    private static final boolean WAIT_FOR_DEBUGGER = true;
+    private static final boolean WAIT_FOR_DEBUGGER = false;
     private static final String TAG = "HierarchicalStateMachineTest";
 
     /**
@@ -92,7 +96,7 @@
 
     @SmallTest
     public void testStateMachineQuitTest() throws Exception {
-        //if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
+        if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
 
         StateMachineQuitTest smQuitTest = new StateMachineQuitTest("smQuitTest");
         smQuitTest.start();
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 9c47dab..f3f3653 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -232,8 +232,6 @@
         float toDegrees = a.getFloat(
                 com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
 
-        toDegrees = Math.max(fromDegrees, toDegrees);
-
         int res = a.getResourceId(
                 com.android.internal.R.styleable.RotateDrawable_drawable, 0);
         Drawable drawable = null;
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 3d77278..bba7ed7 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -34,7 +34,6 @@
 
     virtual void            disconnect() = 0;
 
-    virtual status_t        setVideoISurface(const sp<ISurface>& surface) = 0;
     virtual status_t        setVideoSurface(const sp<Surface>& surface) = 0;
     virtual status_t        prepareAsync() = 0;
     virtual status_t        start() = 0;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index fa775e7..cb36bbb 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -120,30 +120,6 @@
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
-
-    virtual sp<IOMXRenderer> createRenderer(
-            const sp<ISurface> &surface,
-            const char *componentName,
-            OMX_COLOR_FORMATTYPE colorFormat,
-            size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight) = 0;
-
-    // Note: These methods are _not_ virtual, it exists as a wrapper around
-    // the virtual "createRenderer" method above facilitating extraction
-    // of the ISurface from a regular Surface or a java Surface object.
-    sp<IOMXRenderer> createRenderer(
-            const sp<Surface> &surface,
-            const char *componentName,
-            OMX_COLOR_FORMATTYPE colorFormat,
-            size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
-
-    sp<IOMXRenderer> createRendererFromJavaSurface(
-            JNIEnv *env, jobject javaSurface,
-            const char *componentName,
-            OMX_COLOR_FORMATTYPE colorFormat,
-            size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
 };
 
 struct omx_message {
@@ -190,13 +166,6 @@
     virtual void onMessage(const omx_message &msg) = 0;
 };
 
-class IOMXRenderer : public IInterface {
-public:
-    DECLARE_META_INTERFACE(OMXRenderer);
-
-    virtual void render(IOMX::buffer_id buffer) = 0;
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 
 class BnOMX : public BnInterface<IOMX> {
@@ -213,13 +182,6 @@
             uint32_t flags = 0);
 };
 
-class BnOMXRenderer : public BnInterface<IOMXRenderer> {
-public:
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-};
-
 }  // namespace android
 
 #endif  // ANDROID_IOMX_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 2d55a55..672931e 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -106,7 +106,6 @@
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
-    virtual status_t    setVideoISurface(const sp<ISurface>& surface) = 0;
     virtual status_t    setVideoSurface(const sp<Surface>& surface) = 0;
     virtual status_t    prepare() = 0;
     virtual status_t    prepareAsync() = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
deleted file mode 100644
index 4b44ccc..0000000
--- a/include/media/PVMediaRecorder.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- **
- ** Copyright 2008, 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.
- */
-
-#ifndef ANDROID_PVMEDIARECORDER_H
-#define ANDROID_PVMEDIARECORDER_H
-
-#include <media/IMediaRecorderClient.h>
-#include <media/MediaRecorderBase.h>
-
-namespace android {
-
-class Surface;
-class ICamera;
-class AuthorDriverWrapper;
-
-class PVMediaRecorder : public MediaRecorderBase {
-public:
-    PVMediaRecorder();
-    virtual ~PVMediaRecorder();
-
-    virtual status_t init();
-    virtual status_t setAudioSource(audio_source as);
-    virtual status_t setVideoSource(video_source vs);
-    virtual status_t setOutputFormat(output_format of);
-    virtual status_t setAudioEncoder(audio_encoder ae);
-    virtual status_t setVideoEncoder(video_encoder ve);
-    virtual status_t setVideoSize(int width, int height);
-    virtual status_t setVideoFrameRate(int frames_per_second);
-    virtual status_t setCamera(const sp<ICamera>& camera);
-    virtual status_t setPreviewSurface(const sp<Surface>& surface);
-    virtual status_t setOutputFile(const char *path);
-    virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
-    virtual status_t setParameters(const String8& params);
-    virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
-    virtual status_t prepare();
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t close();
-    virtual status_t reset();
-    virtual status_t getMaxAmplitude(int *max);
-    virtual status_t dump(int fd, const Vector<String16>& args) const;
-
-private:
-    status_t doStop();
-
-    AuthorDriverWrapper*            mAuthorDriverWrapper;
-
-    PVMediaRecorder(const PVMediaRecorder &);
-    PVMediaRecorder &operator=(const PVMediaRecorder &);
-};
-
-}; // namespace android
-
-#endif // ANDROID_PVMEDIARECORDER_H
diff --git a/include/media/PVMetadataRetriever.h b/include/media/PVMetadataRetriever.h
deleted file mode 100644
index c202dfe..0000000
--- a/include/media/PVMetadataRetriever.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-**
-** Copyright (C) 2008 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.
-*/
-
-#ifndef ANDROID_PVMETADATARETRIEVER_H
-#define ANDROID_PVMETADATARETRIEVER_H
-
-#include <utils/Errors.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-#include <private/media/VideoFrame.h>
-
-namespace android {
-
-class MetadataDriver;
-
-class PVMetadataRetriever : public MediaMetadataRetrieverInterface
-{
-public:
-                        PVMetadataRetriever();
-    virtual             ~PVMetadataRetriever();
-
-    virtual status_t    setDataSource(const char *url);
-    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
-    virtual status_t    setMode(int mode);
-    virtual status_t    getMode(int* mode) const;
-    virtual VideoFrame* captureFrame();
-    virtual MediaAlbumArt* extractAlbumArt();
-    virtual const char* extractMetadata(int keyCode);
-
-private:
-    mutable Mutex       mLock;
-    MetadataDriver*     mMetadataDriver;
-    char*               mDataSourcePath;
-};
-
-}; // namespace android
-
-#endif // ANDROID_PVMETADATARETRIEVER_H
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
deleted file mode 100644
index 657e7a6..0000000
--- a/include/media/PVPlayer.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-#ifndef ANDROID_PVPLAYER_H
-#define ANDROID_PVPLAYER_H
-
-#include <utils/Errors.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/Metadata.h>
-
-#define MAX_OPENCORE_INSTANCES 25
-
-#ifdef MAX_OPENCORE_INSTANCES
-#include <cutils/atomic.h>
-#endif
-
-class PlayerDriver;
-
-namespace android {
-
-class PVPlayer : public MediaPlayerInterface
-{
-public:
-                        PVPlayer();
-    virtual             ~PVPlayer();
-
-    virtual status_t    initCheck();
-
-    virtual status_t    setDataSource(
-            const char *url, const KeyedVector<String8, String8> *headers);
-
-    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
-    virtual status_t    setVideoISurface(const sp<ISurface>& surface);
-    virtual status_t    setVideoSurface(const sp<Surface>& surface);
-    virtual status_t    prepare();
-    virtual status_t    prepareAsync();
-    virtual status_t    start();
-    virtual status_t    stop();
-    virtual status_t    pause();
-    virtual bool        isPlaying();
-    virtual status_t    seekTo(int msec);
-    virtual status_t    getCurrentPosition(int *msec);
-    virtual status_t    getDuration(int *msec);
-    virtual status_t    reset();
-    virtual status_t    setLooping(int loop);
-    virtual player_type playerType() { return PV_PLAYER; }
-    virtual status_t    invoke(const Parcel& request, Parcel *reply);
-    virtual status_t    getMetadata(
-        const SortedVector<media::Metadata::Type>& ids,
-        Parcel *records);
-
-    // make available to PlayerDriver
-    void        sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
-
-private:
-    static void         do_nothing(status_t s, void *cookie, bool cancelled) { }
-    static void         run_init(status_t s, void *cookie, bool cancelled);
-    static void         run_set_video_surface(status_t s, void *cookie, bool cancelled);
-    static void         run_set_audio_output(status_t s, void *cookie, bool cancelled);
-    static void         run_prepare(status_t s, void *cookie, bool cancelled);
-    static void         check_for_live_streaming(status_t s, void *cookie, bool cancelled);
-
-    PlayerDriver*               mPlayerDriver;
-    char *                      mDataSourcePath;
-    bool                        mIsDataSourceSet;
-    sp<ISurface>                mSurface;
-    int                         mSharedFd;
-    status_t                    mInit;
-    int                         mDuration;
-
-#ifdef MAX_OPENCORE_INSTANCES
-    static volatile int32_t     sNumInstances;
-#endif
-};
-
-}; // namespace android
-
-#endif // ANDROID_PVPLAYER_H
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 4fd281b..17908b4 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -19,8 +19,6 @@
 #define HARDWARE_API_H_
 
 #include <media/stagefright/OMXPluginBase.h>
-#include <media/stagefright/VideoRenderer.h>
-#include <surfaceflinger/ISurface.h>
 #include <ui/android_native_buffer.h>
 #include <utils/RefBase.h>
 
@@ -91,13 +89,6 @@
 
 }  // namespace android
 
-extern android::VideoRenderer *createRenderer(
-        const android::sp<android::ISurface> &surface,
-        const char *componentName,
-        OMX_COLOR_FORMATTYPE colorFormat,
-        size_t displayWidth, size_t displayHeight,
-        size_t decodedWidth, size_t decodedHeight);
-
 extern android::OMXPluginBase *createOMXPlugin();
 
 #endif  // HARDWARE_API_H_
diff --git a/include/media/stagefright/VideoRenderer.h b/include/media/stagefright/VideoRenderer.h
deleted file mode 100644
index f80b277..0000000
--- a/include/media/stagefright/VideoRenderer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#ifndef VIDEO_RENDERER_H_
-
-#define VIDEO_RENDERER_H_
-
-#include <sys/types.h>
-
-namespace android {
-
-class VideoRenderer {
-public:
-    virtual ~VideoRenderer() {}
-
-    virtual void render(
-            const void *data, size_t size, void *platformPrivate) = 0;
-
-protected:
-    VideoRenderer() {}
-
-    VideoRenderer(const VideoRenderer &);
-    VideoRenderer &operator=(const VideoRenderer &);
-};
-
-}  // namespace android
-
-#endif  // VIDEO_RENDERER_H_
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 07a0c11..584f53f 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -19,39 +19,12 @@
 
 #include <utils/Errors.h>
 #include <utils/SharedBuffer.h>
-
-#include <stdint.h>
-#include <sys/types.h>
+#include <utils/Unicode.h>
 
 // ---------------------------------------------------------------------------
 
 extern "C" {
 
-typedef uint16_t char16_t;
-
-// Standard string functions on char16 strings.
-int strcmp16(const char16_t *, const char16_t *);
-int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
-size_t strlen16(const char16_t *);
-size_t strnlen16(const char16_t *, size_t);
-char16_t *strcpy16(char16_t *, const char16_t *);
-char16_t *strncpy16(char16_t *, const char16_t *, size_t);
-
-// Version of comparison that supports embedded nulls.
-// This is different than strncmp() because we don't stop
-// at a nul character and consider the strings to be different
-// if the lengths are different (thus we need to supply the
-// lengths of both strings).  This can also be used when
-// your string is not nul-terminated as it will have the
-// equivalent result as strcmp16 (unlike strncmp16).
-int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
-
-// Version of strzcmp16 for comparing strings in different endianness.
-int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
-
-// Convert UTF-8 to UTF-16 including surrogate pairs
-void utf8_to_utf16(const uint8_t *src, size_t srcLen, char16_t* dst, const size_t dstLen);
-
 }
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/String8.h b/include/utils/String8.h
index cef8eca..b36f128 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -18,122 +18,16 @@
 #define ANDROID_STRING8_H
 
 #include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/Unicode.h>
 
-// Need this for the char16_t type; String8.h should not
-// be depedent on the String16 class.
-#include <utils/String16.h>
-
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-
-// ---------------------------------------------------------------------------
-
-extern "C" {
-
-typedef uint32_t char32_t;
-
-size_t strlen32(const char32_t *);
-size_t strnlen32(const char32_t *, size_t);
-
-/*
- * Returns the length of "src" when "src" is valid UTF-8 string.
- * Returns 0 if src is NULL, 0-length string or non UTF-8 string.
- * This function should be used to determine whether "src" is valid UTF-8
- * characters with valid unicode codepoints. "src" must be null-terminated.
- *
- * If you are going to use other GetUtf... functions defined in this header
- * with string which may not be valid UTF-8 with valid codepoint (form 0 to
- * 0x10FFFF), you should use this function before calling others, since the
- * other functions do not check whether the string is valid UTF-8 or not.
- *
- * If you do not care whether "src" is valid UTF-8 or not, you should use
- * strlen() as usual, which should be much faster.
- */
-size_t utf8_length(const char *src);
-
-/*
- * Returns the UTF-32 length of "src".
- */
-size_t utf32_length(const char *src, size_t src_len);
-
-/*
- * Returns the UTF-8 length of "src".
- */
-size_t utf8_length_from_utf16(const char16_t *src, size_t src_len);
-
-/*
- * Returns the UTF-8 length of "src".
- */
-size_t utf8_length_from_utf32(const char32_t *src, size_t src_len);
-
-/*
- * Returns the unicode value at "index".
- * Returns -1 when the index is invalid (equals to or more than "src_len").
- * If returned value is positive, it is able to be converted to char32_t, which
- * is unsigned. Then, if "next_index" is not NULL, the next index to be used is
- * stored in "next_index". "next_index" can be NULL.
- */
-int32_t utf32_at(const char *src, size_t src_len,
-                 size_t index, size_t *next_index);
-
-/*
- * Stores a UTF-32 string converted from "src" in "dst", if "dst_length" is not
- * large enough to store the string, the part of the "src" string is stored
- * into "dst".
- * Returns the size actually used for storing the string.
- * "dst" is not null-terminated when dst_len is fully used (like strncpy).
- */
-size_t utf8_to_utf32(const char* src, size_t src_len,
-                     char32_t* dst, size_t dst_len);
-
-/*
- * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not
- * large enough to store the string, the part of the "src" string is stored
- * into "dst" as much as possible. See the examples for more detail.
- * Returns the size actually used for storing the string.
- * dst" is not null-terminated when dst_len is fully used (like strncpy).
- *
- * Example 1
- * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
- * "src_len" == 2
- * "dst_len" >= 7
- * ->
- * Returned value == 6
- * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0
- * (note that "dst" is null-terminated)
- *
- * Example 2
- * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
- * "src_len" == 2
- * "dst_len" == 5
- * ->
- * Returned value == 3
- * "dst" becomes \xE3\x81\x82\0
- * (note that "dst" is null-terminated, but \u3044 is not stored in "dst"
- * since "dst" does not have enough size to store the character)
- *
- * Example 3
- * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
- * "src_len" == 2
- * "dst_len" == 6
- * ->
- * Returned value == 6
- * "dst" becomes \xE3\x81\x82\xE3\x81\x84
- * (note that "dst" is NOT null-terminated, like strncpy)
- */
-size_t utf32_to_utf8(const char32_t* src, size_t src_len,
-                     char* dst, size_t dst_len);
-
-size_t utf16_to_utf8(const char16_t* src, size_t src_len,
-                     char* dst, size_t dst_len);
-
-}
+#include <string.h> // for strcmp
 
 // ---------------------------------------------------------------------------
 
 namespace android {
 
+class String16;
 class TextOutput;
 
 //! This is a string holding UTF-8 characters. Does not allow the value more
@@ -182,7 +76,7 @@
             size_t              getUtf32Length() const;
             int32_t             getUtf32At(size_t index,
                                            size_t *next_index) const;
-            size_t              getUtf32(char32_t* dst, size_t dst_len) const;
+            void                getUtf32(char32_t* dst) const;
 
     inline  String8&            operator=(const String8& other);
     inline  String8&            operator=(const char* other);
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
new file mode 100644
index 0000000..6afb291
--- /dev/null
+++ b/include/utils/Unicode.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_UNICODE_H
+#define ANDROID_UNICODE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern "C" {
+
+typedef uint32_t char32_t;
+typedef uint16_t char16_t;
+
+// Standard string functions on char16_t strings.
+int strcmp16(const char16_t *, const char16_t *);
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
+size_t strlen16(const char16_t *);
+size_t strnlen16(const char16_t *, size_t);
+char16_t *strcpy16(char16_t *, const char16_t *);
+char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+
+// Version of comparison that supports embedded nulls.
+// This is different than strncmp() because we don't stop
+// at a nul character and consider the strings to be different
+// if the lengths are different (thus we need to supply the
+// lengths of both strings).  This can also be used when
+// your string is not nul-terminated as it will have the
+// equivalent result as strcmp16 (unlike strncmp16).
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
+
+// Version of strzcmp16 for comparing strings in different endianness.
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
+
+// Standard string functions on char32_t strings.
+size_t strlen32(const char32_t *);
+size_t strnlen32(const char32_t *, size_t);
+
+/**
+ * Measure the length of a UTF-32 string in UTF-8. If the string is invalid
+ * such as containing a surrogate character, -1 will be returned.
+ */
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len);
+
+/**
+ * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not
+ * large enough to store the string, the part of the "src" string is stored
+ * into "dst" as much as possible. See the examples for more detail.
+ * Returns the size actually used for storing the string.
+ * dst" is not null-terminated when dst_len is fully used (like strncpy).
+ *
+ * Example 1
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" >= 7
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0
+ * (note that "dst" is null-terminated)
+ *
+ * Example 2
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 5
+ * ->
+ * Returned value == 3
+ * "dst" becomes \xE3\x81\x82\0
+ * (note that "dst" is null-terminated, but \u3044 is not stored in "dst"
+ * since "dst" does not have enough size to store the character)
+ *
+ * Example 3
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 6
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84
+ * (note that "dst" is NOT null-terminated, like strncpy)
+ */
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst);
+
+/**
+ * Returns the unicode value at "index".
+ * Returns -1 when the index is invalid (equals to or more than "src_len").
+ * If returned value is positive, it is able to be converted to char32_t, which
+ * is unsigned. Then, if "next_index" is not NULL, the next index to be used is
+ * stored in "next_index". "next_index" can be NULL.
+ */
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index);
+
+
+/**
+ * Returns the UTF-8 length of UTF-16 string "src".
+ */
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len);
+
+/**
+ * Converts a UTF-16 string to UTF-8. The destination buffer must be large
+ * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
+ * NULL terminator.
+ */
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst);
+
+/**
+ * Returns the length of "src" when "src" is valid UTF-8 string.
+ * Returns 0 if src is NULL or 0-length string. Returns -1 when the source
+ * is an invalid string.
+ *
+ * This function should be used to determine whether "src" is valid UTF-8
+ * characters with valid unicode codepoints. "src" must be null-terminated.
+ *
+ * If you are going to use other utf8_to_... functions defined in this header
+ * with string which may not be valid UTF-8 with valid codepoint (form 0 to
+ * 0x10FFFF), you should use this function before calling others, since the
+ * other functions do not check whether the string is valid UTF-8 or not.
+ *
+ * If you do not care whether "src" is valid UTF-8 or not, you should use
+ * strlen() as usual, which should be much faster.
+ */
+ssize_t utf8_length(const char *src);
+
+/**
+ * Measure the length of a UTF-32 string.
+ */
+size_t utf8_to_utf32_length(const char *src, size_t src_len);
+
+/**
+ * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large
+ * enough to store the entire converted string as measured by
+ * utf8_to_utf32_length plus space for a NULL terminator.
+ */
+void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst);
+
+/**
+ * Returns the UTF-16 length of UTF-8 string "src".
+ */
+ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen);
+
+/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer
+ * must be large enough to hold the result as measured by utf8_to_utf16_length
+ * plus an added NULL terminator.
+ */
+void utf8_to_utf16(const uint8_t* src, size_t srcLen, char16_t* dst);
+
+}
+
+#endif
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 148e864..450971d 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -372,6 +372,9 @@
     }
     if (listener != NULL) {
         listener->postDataTimestamp(timestamp, msgType, dataPtr);
+    } else {
+        LOGW("No listener was set. Drop a recording frame.");
+        releaseRecordingFrame(dataPtr);
     }
 }
 
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 698540b..3e81115 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
@@ -64,7 +64,7 @@
 
 
 static void copyInput() {
-    rs_allocation ain = {0};
+    rs_allocation ain;
     rsSetObject(&ain,rsGetAllocation(InPixel));
     uint32_t dimx = rsAllocationGetDimX(ain);
     uint32_t dimy = rsAllocationGetDimY(ain);
@@ -73,7 +73,6 @@
             ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]);
         }
     }
-    rsClearObject(&ain);
 }
 
 void filter() {
diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
index f29276a..0baccb8 100644
--- a/libs/rs/java/Samples/src/com/android/samples/rslist.rs
+++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
@@ -46,7 +46,7 @@
     rsgBindFont(gItalic);
     color(0.2, 0.2, 0.2, 0);
 
-    rs_allocation listAlloc = {0};
+    rs_allocation listAlloc;
     rsSetObject(&listAlloc, rsGetAllocation(gList));
     int allocSize = rsAllocationGetDimX(listAlloc);
 
@@ -67,7 +67,6 @@
         }
         currentYPos += itemHeight;
     }
-    rsClearObject(&listAlloc);
 
     return 10;
 }
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
index d1fde57..f354a72 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
@@ -47,7 +47,7 @@
     rsgBindFont(gFont);
     color(0.2, 0.2, 0.2, 0);
 
-    rs_allocation listAlloc = {0};
+    rs_allocation listAlloc;
     rsSetObject(&listAlloc, rsGetAllocation(gList));
     int allocSize = rsAllocationGetDimX(listAlloc);
 
@@ -103,7 +103,6 @@
         }
         currentYPos += itemHeight;
     }
-    rsClearObject(&listAlloc);
 
     return 10;
 }
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 33b0f51..96e350d 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -174,7 +174,7 @@
 
     while (glyphsLeft > 0) {
 
-        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
+        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
 
         // Reached the end of the string or encountered
         if (utfChar < 0) {
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 033f316..072cc168 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -65,12 +65,11 @@
         void **dest = ((void ***)mEnviroment.mFieldAddress)[ct];
 
         if (rsc->props.mLogScripts) {
-            LOGV("%p ScriptC::setupScript slot=%i  dst=%p  src=%p  type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType());
-
-            //const uint32_t *p32 = (const uint32_t *)ptr;
-            //for (uint32_t ct2=0; ct2 < mSlots[ct]->getType()->getDimX(); ct2++) {
-                //LOGE("  %i = 0x%08x ", ct2, p32[ct2]);
-            //}
+            if (mSlots[ct].get() != NULL) {
+                LOGV("%p ScriptC::setupScript slot=%i  dst=%p  src=%p  type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType());
+            } else {
+                LOGV("%p ScriptC::setupScript slot=%i  dst=%p  src=%p  type=null", rsc, ct, dest, ptr);
+            }
         }
 
         if (dest) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index ab8d9d7..7e4a247 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -345,6 +345,10 @@
     return a / b;
 }
 
+int SC_modsi3(int a, int b) {
+    return a % b;
+}
+
 int SC_getAllocation(const void *ptr) {
     GET_TLS();
     const Allocation *alloc = sc->ptrToAllocation(ptr);
@@ -402,6 +406,7 @@
 
 static ScriptCState::SymbolTable_t gSyms[] = {
     { "__divsi3", (void *)&SC_divsi3, true },
+    { "__modsi3", (void *)&SC_modsi3, true },
 
     // allocation
     { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
@@ -528,4 +533,3 @@
     }
     return NULL;
 }
-
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index eb75ed8..05a9674 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -41,6 +41,7 @@
 	TextOutput.cpp \
 	Threads.cpp \
 	Timers.cpp \
+	Unicode.cpp \
 	VectorImpl.cpp \
 	ZipFileCRO.cpp \
 	ZipFileRO.cpp \
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index f287298..bbf5093 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -444,15 +444,51 @@
     }
 }
 
-#define DECODE_LENGTH(str, chrsz, len) \
-    len = *(str); \
-    if (*(str)&(1<<(chrsz*8-1))) { \
-        (str)++; \
-        len = (((len)&((1<<(chrsz*8-1))-1))<<(chrsz*8)) + *(str); \
-    } \
-    (str)++;
+/**
+ * Strings in UTF-16 format have length indicated by a length encoded in the
+ * stored data. It is either 1 or 2 characters of length data. This allows a
+ * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
+ * much data in a string, you're abusing them.
+ *
+ * If the high bit is set, then there are two characters or 4 bytes of length
+ * data encoded. In that case, drop the high bit of the first character and
+ * add it together with the next character.
+ */
+static inline size_t
+decodeLength(const char16_t** str)
+{
+    size_t len = **str;
+    if ((len & 0x8000) != 0) {
+        (*str)++;
+        len = ((len & 0x7FFF) << 16) | **str;
+    }
+    (*str)++;
+    return len;
+}
 
-const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
+/**
+ * Strings in UTF-8 format have length indicated by a length encoded in the
+ * stored data. It is either 1 or 2 characters of length data. This allows a
+ * maximum length of 0x7FFF (32767 bytes), but you should consider storing
+ * text in another way if you're using that much data in a single string.
+ *
+ * If the high bit is set, then there are two characters or 2 bytes of length
+ * data encoded. In that case, drop the high bit of the first character and
+ * add it together with the next character.
+ */
+static inline size_t
+decodeLength(const uint8_t** str)
+{
+    size_t len = **str;
+    if ((len & 0x80) != 0) {
+        (*str)++;
+        len = ((len & 0x7F) << 8) | **str;
+    }
+    (*str)++;
+    return len;
+}
+
+const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
 {
     if (mError == NO_ERROR && idx < mHeader->stringCount) {
         const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
@@ -461,37 +497,51 @@
             if (!isUTF8) {
                 const char16_t* strings = (char16_t*)mStrings;
                 const char16_t* str = strings+off;
-                DECODE_LENGTH(str, sizeof(char16_t), *outLen)
-                if ((uint32_t)(str+*outLen-strings) < mStringPoolSize) {
+
+                *u16len = decodeLength(&str);
+                if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
                     return str;
                 } else {
                     LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
-                            (int)idx, (int)(str+*outLen-strings), (int)mStringPoolSize);
+                            (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
                 }
             } else {
                 const uint8_t* strings = (uint8_t*)mStrings;
-                const uint8_t* str = strings+off;
-                DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
-                size_t encLen;
-                DECODE_LENGTH(str, sizeof(uint8_t), encLen)
-                if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+                const uint8_t* u8str = strings+off;
+
+                *u16len = decodeLength(&u8str);
+                size_t u8len = decodeLength(&u8str);
+
+                // encLen must be less than 0x7FFF due to encoding.
+                if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
                     AutoMutex lock(mDecodeLock);
+
                     if (mCache[idx] != NULL) {
                         return mCache[idx];
                     }
-                    char16_t *u16str = (char16_t *)calloc(*outLen+1, sizeof(char16_t));
+
+                    ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
+                    if (actualLen < 0 || (size_t)actualLen != *u16len) {
+                        LOGW("Bad string block: string #%lld decoded length is not correct "
+                                "%lld vs %llu\n",
+                                (long long)idx, (long long)actualLen, (long long)*u16len);
+                        return NULL;
+                    }
+
+                    char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
                     if (!u16str) {
                         LOGW("No memory when trying to allocate decode cache for string #%d\n",
                                 (int)idx);
                         return NULL;
                     }
-                    const unsigned char *u8src = reinterpret_cast<const unsigned char *>(str);
-                    utf8_to_utf16(u8src, encLen, u16str, *outLen);
+
+                    utf8_to_utf16(u8str, u8len, u16str);
                     mCache[idx] = u16str;
                     return u16str;
                 } else {
-                    LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
-                            (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+                    LOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
+                            (long long)idx, (long long)(u8str+u8len-strings),
+                            (long long)mStringPoolSize);
                 }
             }
         } else {
@@ -512,9 +562,8 @@
             if (isUTF8) {
                 const uint8_t* strings = (uint8_t*)mStrings;
                 const uint8_t* str = strings+off;
-                DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
-                size_t encLen;
-                DECODE_LENGTH(str, sizeof(uint8_t), encLen)
+                *outLen = decodeLength(&str);
+                size_t encLen = decodeLength(&str);
                 if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
                     return (const char*)str;
                 } else {
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index eab7b2b..4ce1664 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -18,228 +18,17 @@
 
 #include <utils/Debug.h>
 #include <utils/Log.h>
+#include <utils/Unicode.h>
 #include <utils/String8.h>
 #include <utils/TextOutput.h>
 #include <utils/threads.h>
 
 #include <private/utils/Static.h>
 
-#ifdef HAVE_WINSOCK
-# undef  nhtol
-# undef  htonl
-# undef  nhtos
-# undef  htons
-
-# ifdef HAVE_LITTLE_ENDIAN
-#  define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
-#  define htonl(x)    ntohl(x)
-#  define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
-#  define htons(x)    ntohs(x)
-# else
-#  define ntohl(x)    (x)
-#  define htonl(x)    (x)
-#  define ntohs(x)    (x)
-#  define htons(x)    (x)
-# endif
-#else
-# include <netinet/in.h>
-#endif
-
 #include <memory.h>
 #include <stdio.h>
 #include <ctype.h>
 
-// ---------------------------------------------------------------------------
-
-int strcmp16(const char16_t *s1, const char16_t *s2)
-{
-  char16_t ch;
-  int d = 0;
-
-  while ( 1 ) {
-    d = (int)(ch = *s1++) - (int)*s2++;
-    if ( d || !ch )
-      break;
-  }
-
-  return d;
-}
-
-int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
-{
-  char16_t ch;
-  int d = 0;
-
-  while ( n-- ) {
-    d = (int)(ch = *s1++) - (int)*s2++;
-    if ( d || !ch )
-      break;
-  }
-
-  return d;
-}
-
-char16_t *strcpy16(char16_t *dst, const char16_t *src)
-{
-  char16_t *q = dst;
-  const char16_t *p = src;
-  char16_t ch;
-
-  do {
-    *q++ = ch = *p++;
-  } while ( ch );
-
-  return dst;
-}
-
-size_t strlen16(const char16_t *s)
-{
-  const char16_t *ss = s;
-  while ( *ss )
-    ss++;
-  return ss-s;
-}
-
-
-char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
-{
-  char16_t *q = dst;
-  const char16_t *p = src;
-  char ch;
-
-  while (n) {
-    n--;
-    *q++ = ch = *p++;
-    if ( !ch )
-      break;
-  }
-
-  *q = 0;
-
-  return dst;
-}
-
-size_t strnlen16(const char16_t *s, size_t maxlen)
-{
-  const char16_t *ss = s;
-
-  /* Important: the maxlen test must precede the reference through ss;
-     since the byte beyond the maximum may segfault */
-  while ((maxlen > 0) && *ss) {
-    ss++;
-    maxlen--;
-  }
-  return ss-s;
-}
-
-int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
-{
-    const char16_t* e1 = s1+n1;
-    const char16_t* e2 = s2+n2;
-
-    while (s1 < e1 && s2 < e2) {
-        const int d = (int)*s1++ - (int)*s2++;
-        if (d) {
-            return d;
-        }
-    }
-
-    return n1 < n2
-        ? (0 - (int)*s2)
-        : (n1 > n2
-           ? ((int)*s1 - 0)
-           : 0);
-}
-
-int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
-{
-    const char16_t* e1 = s1H+n1;
-    const char16_t* e2 = s2N+n2;
-
-    while (s1H < e1 && s2N < e2) {
-        const char16_t c2 = ntohs(*s2N);
-        const int d = (int)*s1H++ - (int)c2;
-        s2N++;
-        if (d) {
-            return d;
-        }
-    }
-
-    return n1 < n2
-        ? (0 - (int)ntohs(*s2N))
-        : (n1 > n2
-           ? ((int)*s1H - 0)
-           : 0);
-}
-
-static inline size_t
-utf8_char_len(uint8_t ch)
-{
-    return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
-}
-
-#define UTF8_SHIFT_AND_MASK(unicode, byte)  (unicode)<<=6; (unicode) |= (0x3f & (byte));
-
-static inline uint32_t
-utf8_to_utf32(const uint8_t *src, size_t length)
-{
-    uint32_t unicode;
-
-    switch (length)
-    {
-        case 1:
-            return src[0];
-        case 2:
-            unicode = src[0] & 0x1f;
-            UTF8_SHIFT_AND_MASK(unicode, src[1])
-            return unicode;
-        case 3:
-            unicode = src[0] & 0x0f;
-            UTF8_SHIFT_AND_MASK(unicode, src[1])
-            UTF8_SHIFT_AND_MASK(unicode, src[2])
-            return unicode;
-        case 4:
-            unicode = src[0] & 0x07;
-            UTF8_SHIFT_AND_MASK(unicode, src[1])
-            UTF8_SHIFT_AND_MASK(unicode, src[2])
-            UTF8_SHIFT_AND_MASK(unicode, src[3])
-            return unicode;
-        default:
-            return 0xffff;
-    }
-    
-    //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
-}
-
-void
-utf8_to_utf16(const uint8_t *src, size_t srcLen,
-        char16_t* dst, const size_t dstLen)
-{
-    const uint8_t* const end = src + srcLen;
-    const char16_t* const dstEnd = dst + dstLen;
-    while (src < end && dst < dstEnd) {
-        size_t len = utf8_char_len(*src);
-        uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len);
-
-        // Convert the UTF32 codepoint to one or more UTF16 codepoints
-        if (codepoint <= 0xFFFF) {
-            // Single UTF16 character
-            *dst++ = (char16_t) codepoint;
-        } else {
-            // Multiple UTF16 characters with surrogates
-            codepoint = codepoint - 0x10000;
-            *dst++ = (char16_t) ((codepoint >> 10) + 0xD800);
-            *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
-        }
-
-        src += len;
-    }
-    if (dst < dstEnd) {
-        *dst = 0;
-    }
-}
-
-// ---------------------------------------------------------------------------
 
 namespace android {
 
@@ -270,37 +59,33 @@
 
 // ---------------------------------------------------------------------------
 
-static char16_t* allocFromUTF8(const char* in, size_t len)
+static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
 {
-    if (len == 0) return getEmptyString();
-    
-    size_t chars = 0;
-    const char* end = in+len;
-    const char* p = in;
-    
-    while (p < end) {
-        chars++;
-        int utf8len = utf8_char_len(*p);
-        uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len);
-        if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16
-        p += utf8len;
+    if (u8len == 0) return getEmptyString();
+
+    const uint8_t* u8cur = (const uint8_t*) u8str;
+
+    const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
+    if (u16len < 0) {
+        return getEmptyString();
     }
-    
-    size_t bufSize = (chars+1)*sizeof(char16_t);
-    SharedBuffer* buf = SharedBuffer::alloc(bufSize);
+
+    const uint8_t* const u8end = u8cur + u8len;
+
+    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
     if (buf) {
-        p = in;
-        char16_t* str = (char16_t*)buf->data();
-        
-        utf8_to_utf16((const uint8_t*)p, len, str, bufSize);
+        u8cur = (const uint8_t*) u8str;
+        char16_t* u16str = (char16_t*)buf->data();
+
+        utf8_to_utf16(u8cur, u8len, u16str);
 
         //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
         //printHexData(1, str, buf->size(), 16, 1);
         //printf("\n");
         
-        return str;
+        return u16str;
     }
-    
+
     return getEmptyString();
 }
 
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index 6358fc4..c8dc083 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -17,6 +17,8 @@
 #include <utils/String8.h>
 
 #include <utils/Log.h>
+#include <utils/Unicode.h>
+#include <utils/SharedBuffer.h>
 #include <utils/String16.h>
 #include <utils/TextOutput.h>
 #include <utils/threads.h>
@@ -34,94 +36,10 @@
 
 namespace android {
 
-static const char32_t kByteMask = 0x000000BF;
-static const char32_t kByteMark = 0x00000080;
-
-// Surrogates aren't valid for UTF-32 characters, so define some
-// constants that will let us screen them out.
-static const char32_t kUnicodeSurrogateHighStart  = 0x0000D800;
-static const char32_t kUnicodeSurrogateHighEnd    = 0x0000DBFF;
-static const char32_t kUnicodeSurrogateLowStart   = 0x0000DC00;
-static const char32_t kUnicodeSurrogateLowEnd     = 0x0000DFFF;
-static const char32_t kUnicodeSurrogateStart      = kUnicodeSurrogateHighStart;
-static const char32_t kUnicodeSurrogateEnd        = kUnicodeSurrogateLowEnd;
-static const char32_t kUnicodeMaxCodepoint        = 0x0010FFFF;
-
-// Mask used to set appropriate bits in first byte of UTF-8 sequence,
-// indexed by number of bytes in the sequence.
-// 0xxxxxxx
-// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000
-// 110yyyyx 10xxxxxx
-// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0
-// 1110yyyy 10yxxxxx 10xxxxxx
-// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0
-// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
-// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0
-static const char32_t kFirstByteMark[] = {
-    0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
-};
-
 // Separator used by resource paths. This is not platform dependent contrary
 // to OS_PATH_SEPARATOR.
 #define RES_PATH_SEPARATOR '/'
 
-// Return number of utf8 bytes required for the character.
-static size_t utf32_to_utf8_bytes(char32_t srcChar)
-{
-    size_t bytesToWrite;
-
-    // Figure out how many bytes the result will require.
-    if (srcChar < 0x00000080)
-    {
-        bytesToWrite = 1;
-    }
-    else if (srcChar < 0x00000800)
-    {
-        bytesToWrite = 2;
-    }
-    else if (srcChar < 0x00010000)
-    {
-        if ((srcChar < kUnicodeSurrogateStart)
-         || (srcChar > kUnicodeSurrogateEnd))
-        {
-            bytesToWrite = 3;
-        }
-        else
-        {
-            // Surrogates are invalid UTF-32 characters.
-            return 0;
-        }
-    }
-    // Max code point for Unicode is 0x0010FFFF.
-    else if (srcChar <= kUnicodeMaxCodepoint)
-    {
-        bytesToWrite = 4;
-    }
-    else
-    {
-        // Invalid UTF-32 character.
-        return 0;
-    }
-
-    return bytesToWrite;
-}
-
-// Write out the source character to <dstP>.
-
-static void utf32_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes)
-{
-    dstP += bytes;
-    switch (bytes)
-    {   /* note: everything falls through. */
-        case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
-        case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
-        case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
-        case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
-    }
-}
-
-// ---------------------------------------------------------------------------
-
 static SharedBuffer* gEmptyStringBuf = NULL;
 static char* gEmptyString = NULL;
 
@@ -175,62 +93,47 @@
     return getEmptyString();
 }
 
-template<typename T, typename L>
-static char* allocFromUTF16OrUTF32(const T* in, L len)
-{
-    if (len == 0) return getEmptyString();
-
-    size_t bytes = 0;
-    const T* end = in+len;
-    const T* p = in;
-
-    while (p < end) {
-        bytes += utf32_to_utf8_bytes(*p);
-        p++;
-    }
-
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
-    LOG_ASSERT(buf, "Unable to allocate shared buffer");
-    if (buf) {
-        p = in;
-        char* str = (char*)buf->data();
-        char* d = str;
-        while (p < end) {
-            const T c = *p++;
-            size_t len = utf32_to_utf8_bytes(c);
-            utf32_to_utf8((uint8_t*)d, c, len);
-            d += len;
-        }
-        *d = 0;
-
-        return str;
-    }
-
-    return getEmptyString();
-}
-
 static char* allocFromUTF16(const char16_t* in, size_t len)
 {
     if (len == 0) return getEmptyString();
 
-    const size_t bytes = utf8_length_from_utf16(in, len);
+    const ssize_t bytes = utf16_to_utf8_length(in, len);
+    if (bytes < 0) {
+        return getEmptyString();
+    }
 
     SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
     LOG_ASSERT(buf, "Unable to allocate shared buffer");
-    if (buf) {
-        char* str = (char*)buf->data();
-
-        utf16_to_utf8(in, len, str, bytes+1);
-
-        return str;
+    if (!buf) {
+        return getEmptyString();
     }
 
-    return getEmptyString();
+    char* str = (char*)buf->data();
+    utf16_to_utf8(in, len, str);
+    return str;
 }
 
 static char* allocFromUTF32(const char32_t* in, size_t len)
 {
-    return allocFromUTF16OrUTF32<char32_t, size_t>(in, len);
+    if (len == 0) {
+        return getEmptyString();
+    }
+
+    const ssize_t bytes = utf32_to_utf8_length(in, len);
+    if (bytes < 0) {
+        return getEmptyString();
+    }
+
+    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (!buf) {
+        return getEmptyString();
+    }
+
+    char* str = (char*) buf->data();
+    utf32_to_utf8(in, len, str);
+
+    return str;
 }
 
 // ---------------------------------------------------------------------------
@@ -510,17 +413,17 @@
 
 size_t String8::getUtf32Length() const
 {
-    return utf32_length(mString, length());
+    return utf8_to_utf32_length(mString, length());
 }
 
 int32_t String8::getUtf32At(size_t index, size_t *next_index) const
 {
-    return utf32_at(mString, length(), index, next_index);
+    return utf32_from_utf8_at(mString, length(), index, next_index);
 }
 
-size_t String8::getUtf32(char32_t* dst, size_t dst_len) const
+void String8::getUtf32(char32_t* dst) const
 {
-    return utf8_to_utf32(mString, length(), dst, dst_len);
+    utf8_to_utf32(mString, length(), dst);
 }
 
 TextOutput& operator<<(TextOutput& to, const String8& val)
@@ -705,241 +608,3 @@
 }
 
 }; // namespace android
-
-// ---------------------------------------------------------------------------
-
-size_t strlen32(const char32_t *s)
-{
-  const char32_t *ss = s;
-  while ( *ss )
-    ss++;
-  return ss-s;
-}
-
-size_t strnlen32(const char32_t *s, size_t maxlen)
-{
-  const char32_t *ss = s;
-  while ((maxlen > 0) && *ss) {
-    ss++;
-    maxlen--;
-  }
-  return ss-s;
-}
-
-size_t utf8_length(const char *src)
-{
-    const char *cur = src;
-    size_t ret = 0;
-    while (*cur != '\0') {
-        const char first_char = *cur++;
-        if ((first_char & 0x80) == 0) { // ASCII
-            ret += 1;
-            continue;
-        }
-        // (UTF-8's character must not be like 10xxxxxx,
-        //  but 110xxxxx, 1110xxxx, ... or 1111110x)
-        if ((first_char & 0x40) == 0) {
-            return 0;
-        }
-
-        int32_t mask, to_ignore_mask;
-        size_t num_to_read = 0;
-        char32_t utf32 = 0;
-        for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
-             num_to_read < 5 && (first_char & mask);
-             num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
-            if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx
-                return 0;
-            }
-            // 0x3F == 00111111
-            utf32 = (utf32 << 6) + (*cur++ & 0x3F);
-        }
-        // "first_char" must be (110xxxxx - 11110xxx)
-        if (num_to_read == 5) {
-            return 0;
-        }
-        to_ignore_mask |= mask;
-        utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
-        if (utf32 > android::kUnicodeMaxCodepoint) {
-            return 0;
-        }
-
-        ret += num_to_read;
-    }
-    return ret;
-}
-
-size_t utf32_length(const char *src, size_t src_len)
-{
-    if (src == NULL || src_len == 0) {
-        return 0;
-    }
-    size_t ret = 0;
-    const char* cur;
-    const char* end;
-    size_t num_to_skip;
-    for (cur = src, end = src + src_len, num_to_skip = 1;
-         cur < end;
-         cur += num_to_skip, ret++) {
-        const char first_char = *cur;
-        num_to_skip = 1;
-        if ((first_char & 0x80) == 0) {  // ASCII
-            continue;
-        }
-        int32_t mask;
-
-        for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) {
-        }
-    }
-    return ret;
-}
-
-size_t utf8_length_from_utf32(const char32_t *src, size_t src_len)
-{
-    if (src == NULL || src_len == 0) {
-        return 0;
-    }
-    size_t ret = 0;
-    const char32_t *end = src + src_len;
-    while (src < end) {
-        ret += android::utf32_to_utf8_bytes(*src++);
-    }
-    return ret;
-}
-
-size_t utf8_length_from_utf16(const char16_t *src, size_t src_len)
-{
-    if (src == NULL || src_len == 0) {
-        return 0;
-    }
-    size_t ret = 0;
-    const char16_t* const end = src + src_len;
-    while (src < end) {
-        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
-                && (*++src & 0xFC00) == 0xDC00) {
-            // surrogate pairs are always 4 bytes.
-            ret += 4;
-            src++;
-        } else {
-            ret += android::utf32_to_utf8_bytes((char32_t) *src++);
-        }
-    }
-    return ret;
-}
-
-static int32_t utf32_at_internal(const char* cur, size_t *num_read)
-{
-    const char first_char = *cur;
-    if ((first_char & 0x80) == 0) { // ASCII
-        *num_read = 1;
-        return *cur;
-    }
-    cur++;
-    char32_t mask, to_ignore_mask;
-    size_t num_to_read = 0;
-    char32_t utf32 = first_char;
-    for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80;
-         (first_char & mask);
-         num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
-        // 0x3F == 00111111
-        utf32 = (utf32 << 6) + (*cur++ & 0x3F);
-    }
-    to_ignore_mask |= mask;
-    utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1)));
-
-    *num_read = num_to_read;
-    return static_cast<int32_t>(utf32);
-}
-
-int32_t utf32_at(const char *src, size_t src_len,
-                 size_t index, size_t *next_index)
-{
-    if (index >= src_len) {
-        return -1;
-    }
-    size_t dummy_index;
-    if (next_index == NULL) {
-        next_index = &dummy_index;
-    }
-    size_t num_read;
-    int32_t ret = utf32_at_internal(src + index, &num_read);
-    if (ret >= 0) {
-        *next_index = index + num_read;
-    }
-
-    return ret;
-}
-
-size_t utf8_to_utf32(const char* src, size_t src_len,
-                     char32_t* dst, size_t dst_len)
-{
-    if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
-        return 0;
-    }
-
-    const char* cur = src;
-    const char* end = src + src_len;
-    char32_t* cur_utf32 = dst;
-    const char32_t* end_utf32 = dst + dst_len;
-    while (cur_utf32 < end_utf32 && cur < end) {
-        size_t num_read;
-        *cur_utf32++ =
-                static_cast<char32_t>(utf32_at_internal(cur, &num_read));
-        cur += num_read;
-    }
-    if (cur_utf32 < end_utf32) {
-        *cur_utf32 = 0;
-    }
-    return static_cast<size_t>(cur_utf32 - dst);
-}
-
-size_t utf32_to_utf8(const char32_t* src, size_t src_len,
-                     char* dst, size_t dst_len)
-{
-    if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
-        return 0;
-    }
-    const char32_t *cur_utf32 = src;
-    const char32_t *end_utf32 = src + src_len;
-    char *cur = dst;
-    const char *end = dst + dst_len;
-    while (cur_utf32 < end_utf32 && cur < end) {
-        size_t len = android::utf32_to_utf8_bytes(*cur_utf32);
-        android::utf32_to_utf8((uint8_t *)cur, *cur_utf32++, len);
-        cur += len;
-    }
-    if (cur < end) {
-        *cur = '\0';
-    }
-    return cur - dst;
-}
-
-size_t utf16_to_utf8(const char16_t* src, size_t src_len,
-                     char* dst, size_t dst_len)
-{
-    if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
-        return 0;
-    }
-    const char16_t* cur_utf16 = src;
-    const char16_t* const end_utf16 = src + src_len;
-    char *cur = dst;
-    const char* const end = dst + dst_len;
-    while (cur_utf16 < end_utf16 && cur < end) {
-        char32_t utf32;
-        // surrogate pairs
-        if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) {
-            utf32 = (*cur_utf16++ - 0xD800) << 10;
-            utf32 |= *cur_utf16++ - 0xDC00;
-            utf32 += 0x10000;
-        } else {
-            utf32 = (char32_t) *cur_utf16++;
-        }
-        size_t len = android::utf32_to_utf8_bytes(utf32);
-        android::utf32_to_utf8((uint8_t*)cur, utf32, len);
-        cur += len;
-    }
-    if (cur < end) {
-        *cur = '\0';
-    }
-    return cur - dst;
-}
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
new file mode 100644
index 0000000..78c61b4
--- /dev/null
+++ b/libs/utils/Unicode.cpp
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/Unicode.h>
+
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+# undef  nhtol
+# undef  htonl
+# undef  nhtos
+# undef  htons
+
+# ifdef HAVE_LITTLE_ENDIAN
+#  define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+#  define htonl(x)    ntohl(x)
+#  define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+#  define htons(x)    ntohs(x)
+# else
+#  define ntohl(x)    (x)
+#  define htonl(x)    (x)
+#  define ntohs(x)    (x)
+#  define htons(x)    (x)
+# endif
+#else
+# include <netinet/in.h>
+#endif
+
+extern "C" {
+
+static const char32_t kByteMask = 0x000000BF;
+static const char32_t kByteMark = 0x00000080;
+
+// Surrogates aren't valid for UTF-32 characters, so define some
+// constants that will let us screen them out.
+static const char32_t kUnicodeSurrogateHighStart  = 0x0000D800;
+static const char32_t kUnicodeSurrogateHighEnd    = 0x0000DBFF;
+static const char32_t kUnicodeSurrogateLowStart   = 0x0000DC00;
+static const char32_t kUnicodeSurrogateLowEnd     = 0x0000DFFF;
+static const char32_t kUnicodeSurrogateStart      = kUnicodeSurrogateHighStart;
+static const char32_t kUnicodeSurrogateEnd        = kUnicodeSurrogateLowEnd;
+static const char32_t kUnicodeMaxCodepoint        = 0x0010FFFF;
+
+// Mask used to set appropriate bits in first byte of UTF-8 sequence,
+// indexed by number of bytes in the sequence.
+// 0xxxxxxx
+// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000
+// 110yyyyx 10xxxxxx
+// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0
+// 1110yyyy 10yxxxxx 10xxxxxx
+// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0
+// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
+// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0
+static const char32_t kFirstByteMark[] = {
+    0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
+};
+
+// --------------------------------------------------------------------------
+// UTF-32
+// --------------------------------------------------------------------------
+
+/**
+ * Return number of UTF-8 bytes required for the character. If the character
+ * is invalid, return size of 0.
+ */
+static inline size_t utf32_codepoint_utf8_length(char32_t srcChar)
+{
+    // Figure out how many bytes the result will require.
+    if (srcChar < 0x00000080) {
+        return 1;
+    } else if (srcChar < 0x00000800) {
+        return 2;
+    } else if (srcChar < 0x00010000) {
+        if ((srcChar < kUnicodeSurrogateStart) || (srcChar > kUnicodeSurrogateEnd)) {
+            return 3;
+        } else {
+            // Surrogates are invalid UTF-32 characters.
+            return 0;
+        }
+    }
+    // Max code point for Unicode is 0x0010FFFF.
+    else if (srcChar <= kUnicodeMaxCodepoint) {
+        return 4;
+    } else {
+        // Invalid UTF-32 character.
+        return 0;
+    }
+}
+
+// Write out the source character to <dstP>.
+
+static inline void utf32_codepoint_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes)
+{
+    dstP += bytes;
+    switch (bytes)
+    {   /* note: everything falls through. */
+        case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
+    }
+}
+
+size_t strlen32(const char32_t *s)
+{
+  const char32_t *ss = s;
+  while ( *ss )
+    ss++;
+  return ss-s;
+}
+
+size_t strnlen32(const char32_t *s, size_t maxlen)
+{
+  const char32_t *ss = s;
+  while ((maxlen > 0) && *ss) {
+    ss++;
+    maxlen--;
+  }
+  return ss-s;
+}
+
+static inline int32_t utf32_at_internal(const char* cur, size_t *num_read)
+{
+    const char first_char = *cur;
+    if ((first_char & 0x80) == 0) { // ASCII
+        *num_read = 1;
+        return *cur;
+    }
+    cur++;
+    char32_t mask, to_ignore_mask;
+    size_t num_to_read = 0;
+    char32_t utf32 = first_char;
+    for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80;
+         (first_char & mask);
+         num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+        // 0x3F == 00111111
+        utf32 = (utf32 << 6) + (*cur++ & 0x3F);
+    }
+    to_ignore_mask |= mask;
+    utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1)));
+
+    *num_read = num_to_read;
+    return static_cast<int32_t>(utf32);
+}
+
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index)
+{
+    if (index >= src_len) {
+        return -1;
+    }
+    size_t dummy_index;
+    if (next_index == NULL) {
+        next_index = &dummy_index;
+    }
+    size_t num_read;
+    int32_t ret = utf32_at_internal(src + index, &num_read);
+    if (ret >= 0) {
+        *next_index = index + num_read;
+    }
+
+    return ret;
+}
+
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return -1;
+    }
+
+    size_t ret = 0;
+    const char32_t *end = src + src_len;
+    while (src < end) {
+        ret += utf32_codepoint_utf8_length(*src++);
+    }
+    return ret;
+}
+
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char32_t *cur_utf32 = src;
+    const char32_t *end_utf32 = src + src_len;
+    char *cur = dst;
+    while (cur_utf32 < end_utf32) {
+        size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+        utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
+        cur += len;
+    }
+    *cur = '\0';
+}
+
+// --------------------------------------------------------------------------
+// UTF-16
+// --------------------------------------------------------------------------
+
+int strcmp16(const char16_t *s1, const char16_t *s2)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( 1 ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( n-- ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+char16_t *strcpy16(char16_t *dst, const char16_t *src)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char16_t ch;
+
+  do {
+    *q++ = ch = *p++;
+  } while ( ch );
+
+  return dst;
+}
+
+size_t strlen16(const char16_t *s)
+{
+  const char16_t *ss = s;
+  while ( *ss )
+    ss++;
+  return ss-s;
+}
+
+
+char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char ch;
+
+  while (n) {
+    n--;
+    *q++ = ch = *p++;
+    if ( !ch )
+      break;
+  }
+
+  *q = 0;
+
+  return dst;
+}
+
+size_t strnlen16(const char16_t *s, size_t maxlen)
+{
+  const char16_t *ss = s;
+
+  /* Important: the maxlen test must precede the reference through ss;
+     since the byte beyond the maximum may segfault */
+  while ((maxlen > 0) && *ss) {
+    ss++;
+    maxlen--;
+  }
+  return ss-s;
+}
+
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
+{
+    const char16_t* e1 = s1+n1;
+    const char16_t* e2 = s2+n2;
+
+    while (s1 < e1 && s2 < e2) {
+        const int d = (int)*s1++ - (int)*s2++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)*s2)
+        : (n1 > n2
+           ? ((int)*s1 - 0)
+           : 0);
+}
+
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
+{
+    const char16_t* e1 = s1H+n1;
+    const char16_t* e2 = s2N+n2;
+
+    while (s1H < e1 && s2N < e2) {
+        const char16_t c2 = ntohs(*s2N);
+        const int d = (int)*s1H++ - (int)c2;
+        s2N++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)ntohs(*s2N))
+        : (n1 > n2
+           ? ((int)*s1H - 0)
+           : 0);
+}
+
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char16_t* cur_utf16 = src;
+    const char16_t* const end_utf16 = src + src_len;
+    char *cur = dst;
+    while (cur_utf16 < end_utf16) {
+        char32_t utf32;
+        // surrogate pairs
+        if ((*cur_utf16 & 0xFC00) == 0xD800) {
+            utf32 = (*cur_utf16++ - 0xD800) << 10;
+            utf32 |= *cur_utf16++ - 0xDC00;
+            utf32 += 0x10000;
+        } else {
+            utf32 = (char32_t) *cur_utf16++;
+        }
+        const size_t len = utf32_codepoint_utf8_length(utf32);
+        utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len);
+        cur += len;
+    }
+    *cur = '\0';
+}
+
+// --------------------------------------------------------------------------
+// UTF-8
+// --------------------------------------------------------------------------
+
+ssize_t utf8_length(const char *src)
+{
+    const char *cur = src;
+    size_t ret = 0;
+    while (*cur != '\0') {
+        const char first_char = *cur++;
+        if ((first_char & 0x80) == 0) { // ASCII
+            ret += 1;
+            continue;
+        }
+        // (UTF-8's character must not be like 10xxxxxx,
+        //  but 110xxxxx, 1110xxxx, ... or 1111110x)
+        if ((first_char & 0x40) == 0) {
+            return -1;
+        }
+
+        int32_t mask, to_ignore_mask;
+        size_t num_to_read = 0;
+        char32_t utf32 = 0;
+        for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+             num_to_read < 5 && (first_char & mask);
+             num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+            if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx
+                return -1;
+            }
+            // 0x3F == 00111111
+            utf32 = (utf32 << 6) + (*cur++ & 0x3F);
+        }
+        // "first_char" must be (110xxxxx - 11110xxx)
+        if (num_to_read == 5) {
+            return -1;
+        }
+        to_ignore_mask |= mask;
+        utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+        if (utf32 > kUnicodeMaxCodepoint) {
+            return -1;
+        }
+
+        ret += num_to_read;
+    }
+    return ret;
+}
+
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return -1;
+    }
+
+    size_t ret = 0;
+    const char16_t* const end = src + src_len;
+    while (src < end) {
+        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+                && (*++src & 0xFC00) == 0xDC00) {
+            // surrogate pairs are always 4 bytes.
+            ret += 4;
+            src++;
+        } else {
+            ret += utf32_codepoint_utf8_length((char32_t) *src++);
+        }
+    }
+    return ret;
+}
+
+/**
+ * Returns 1-4 based on the number of leading bits.
+ *
+ * 1111 -> 4
+ * 1110 -> 3
+ * 110x -> 2
+ * 10xx -> 1
+ * 0xxx -> 1
+ */
+static inline size_t utf8_codepoint_len(uint8_t ch)
+{
+    return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
+}
+
+static inline void utf8_shift_and_mask(uint32_t* codePoint, const uint8_t byte)
+{
+    *codePoint <<= 6;
+    *codePoint |= 0x3F & byte;
+}
+
+size_t utf8_to_utf32_length(const char *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return 0;
+    }
+    size_t ret = 0;
+    const char* cur;
+    const char* end;
+    size_t num_to_skip;
+    for (cur = src, end = src + src_len, num_to_skip = 1;
+         cur < end;
+         cur += num_to_skip, ret++) {
+        const char first_char = *cur;
+        num_to_skip = 1;
+        if ((first_char & 0x80) == 0) {  // ASCII
+            continue;
+        }
+        int32_t mask;
+
+        for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) {
+        }
+    }
+    return ret;
+}
+
+void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char* cur = src;
+    const char* const end = src + src_len;
+    char32_t* cur_utf32 = dst;
+    while (cur < end) {
+        size_t num_read;
+        *cur_utf32++ = static_cast<char32_t>(utf32_at_internal(cur, &num_read));
+        cur += num_read;
+    }
+    *cur_utf32 = 0;
+}
+
+static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length)
+{
+    uint32_t unicode;
+
+    switch (length)
+    {
+        case 1:
+            return src[0];
+        case 2:
+            unicode = src[0] & 0x1f;
+            utf8_shift_and_mask(&unicode, src[1]);
+            return unicode;
+        case 3:
+            unicode = src[0] & 0x0f;
+            utf8_shift_and_mask(&unicode, src[1]);
+            utf8_shift_and_mask(&unicode, src[2]);
+            return unicode;
+        case 4:
+            unicode = src[0] & 0x07;
+            utf8_shift_and_mask(&unicode, src[1]);
+            utf8_shift_and_mask(&unicode, src[2]);
+            utf8_shift_and_mask(&unicode, src[3]);
+            return unicode;
+        default:
+            return 0xffff;
+    }
+
+    //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
+}
+
+ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len)
+{
+    const uint8_t* const u8end = u8str + u8len;
+    const uint8_t* u8cur = u8str;
+
+    /* Validate that the UTF-8 is the correct len */
+    size_t u16measuredLen = 0;
+    while (u8cur < u8end) {
+        u16measuredLen++;
+        int u8charLen = utf8_codepoint_len(*u8cur);
+        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen);
+        if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16
+        u8cur += u8charLen;
+    }
+
+    /**
+     * Make sure that we ended where we thought we would and the output UTF-16
+     * will be exactly how long we were told it would be.
+     */
+    if (u8cur != u8end) {
+        return -1;
+    }
+
+    return u16measuredLen;
+}
+
+/**
+ * Convert a UTF-8 string to UTF-16. The destination UTF-16 buffer must have
+ * space for NULL at the end.
+ */
+void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str)
+{
+    const uint8_t* const u8end = u8str + u8len;
+    const uint8_t* u8cur = u8str;
+    char16_t* u16cur = u16str;
+
+    while (u8cur < u8end) {
+        size_t u8len = utf8_codepoint_len(*u8cur);
+        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len);
+
+        // Convert the UTF32 codepoint to one or more UTF16 codepoints
+        if (codepoint <= 0xFFFF) {
+            // Single UTF16 character
+            *u16cur++ = (char16_t) codepoint;
+        } else {
+            // Multiple UTF16 characters with surrogates
+            codepoint = codepoint - 0x10000;
+            *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800);
+            *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+        }
+
+        u8cur += u8len;
+    }
+    *u16cur = 0;
+}
+
+}
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 00077ee..72d4876 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
 test_src_files := \
 	ObbFile_test.cpp \
 	Looper_test.cpp \
-	String8_test.cpp
+	String8_test.cpp \
+	Unicode_test.cpp
 
 shared_libraries := \
 	libz \
diff --git a/libs/utils/tests/Unicode_test.cpp b/libs/utils/tests/Unicode_test.cpp
new file mode 100644
index 0000000..18c130c
--- /dev/null
+++ b/libs/utils/tests/Unicode_test.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Unicode_test"
+#include <utils/Log.h>
+#include <utils/Unicode.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class UnicodeTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
+    ssize_t measured;
+
+    const uint8_t str[] = { };
+
+    measured = utf8_to_utf16_length(str, 0);
+    EXPECT_EQ(0, measured)
+            << "Zero length input should return zero length output.";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16ASCIILength) {
+    ssize_t measured;
+
+    // U+0030 or ASCII '0'
+    const uint8_t str[] = { 0x30 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(1, measured)
+            << "ASCII glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Plane1Length) {
+    ssize_t measured;
+
+    // U+2323 SMILE
+    const uint8_t str[] = { 0xE2, 0x8C, 0xA3 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(1, measured)
+            << "Plane 1 glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16SurrogateLength) {
+    ssize_t measured;
+
+    // U+10000
+    const uint8_t str[] = { 0xF0, 0x90, 0x80, 0x80 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(2, measured)
+            << "Surrogate pairs should have a length of 2 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) {
+    ssize_t measured;
+
+    // Truncated U+2323 SMILE
+    // U+2323 SMILE
+    const uint8_t str[] = { 0xE2, 0x8C };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(-1, measured)
+            << "Truncated UTF-8 should return -1 to indicate invalid";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Normal) {
+    const uint8_t str[] = {
+        0x30, // U+0030, 1 UTF-16 character
+        0xC4, 0x80, // U+0100, 1 UTF-16 character
+        0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character
+        0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
+    };
+
+    char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL
+
+    utf8_to_utf16(str, sizeof(str), output);
+
+    EXPECT_EQ(0x0030, output[0])
+            << "should be U+0030";
+    EXPECT_EQ(0x0100, output[1])
+            << "should be U+0100";
+    EXPECT_EQ(0x2323, output[2])
+            << "should be U+2323";
+    EXPECT_EQ(0xD800, output[3])
+            << "should be first half of surrogate U+10000";
+    EXPECT_EQ(0xDC00, output[4])
+            << "should be second half of surrogate U+10000";
+    EXPECT_EQ(NULL, output[5])
+            << "should be NULL terminated";
+}
+
+}
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 80c97a0..0e689e4 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -77,11 +77,13 @@
     private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP;
    
     // Playlist file types
-    public static final int FILE_TYPE_M3U     = 41;
-    public static final int FILE_TYPE_PLS     = 42;
-    public static final int FILE_TYPE_WPL     = 43;
+    public static final int FILE_TYPE_M3U      = 41;
+    public static final int FILE_TYPE_PLS      = 42;
+    public static final int FILE_TYPE_WPL      = 43;
+    public static final int FILE_TYPE_HTTPLIVE = 44;
+
     private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
-    private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL;
+    private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_HTTPLIVE;
 
     // Drm file types
     public static final int FILE_TYPE_FL      = 51;
@@ -194,6 +196,9 @@
         addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
         addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
         addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST);
+        addFileType("M3U8", FILE_TYPE_HTTPLIVE, "application/vnd.apple.mpegurl");
+        addFileType("M3U8", FILE_TYPE_HTTPLIVE, "audio/mpegurl");
+        addFileType("M3U8", FILE_TYPE_HTTPLIVE, "audio/x-mpegurl");
 
         addFileType("FL", FILE_TYPE_FL, "application/x-android-drm-fl");
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 4fe2c43..69b872b 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -434,24 +434,23 @@
                 }
             }
 
-            mMimeType = null;
+            mMimeType = mimeType;
             mFileType = 0;
             mFileSize = fileSize;
 
             // try mimeType first, if it is specified
             if (mimeType != null) {
                 mFileType = MediaFile.getFileTypeForMimeType(mimeType);
-                if (mFileType != 0) {
-                    mMimeType = mimeType;
-                }
             }
 
             // if mimeType was not specified, compute file type based on file extension.
-            if (mMimeType == null) {
+            if (mFileType == 0) {
                 MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
                 if (mediaFileType != null) {
                     mFileType = mediaFileType.fileType;
-                    mMimeType = mediaFileType.mimeType;
+                    if (mMimeType == null) {
+                        mMimeType = mediaFileType.mimeType;
+                    }
                 }
             }
 
@@ -1194,18 +1193,37 @@
         }
 
         mMtpObjectHandle = objectHandle;
+        initialize(volumeName);
         try {
-            initialize(volumeName);
-            // MTP will create a file entry for us so we don't want to do it in prescan
-            prescan(path, false);
+            if (MediaFile.isPlayListFileType(fileType)) {
+                // build file cache so we can look up tracks in the playlist
+                prescan(null, true);
 
-            File file = new File(path);
+                String key = path;
+                if (mMediaStoragePath != null && key.startsWith(mMediaStoragePath)) {
+                    // MediaProvider uses external variant of path for _data, so we need to match
+                    // against that path instead.
+                    key = mExternalStoragePath + key.substring(mMediaStoragePath.length());
+                }
+                if (mCaseInsensitivePaths) {
+                    key = path.toLowerCase();
+                }
+                FileCacheEntry entry = mFileCache.get(key);
+                if (entry != null) {
+                    processPlayList(entry);
+                }
+            } else {
+                // MTP will create a file entry for us so we don't want to do it in prescan
+                prescan(path, false);
 
-            // lastModified is in milliseconds on Files.
-            long lastModifiedSeconds = file.lastModified() / 1000;
+                File file = new File(path);
 
-            // always scan the file, so we can return the content://media Uri for existing files
-            mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), true);
+                // lastModified is in milliseconds on Files.
+                long lastModifiedSeconds = file.lastModified() / 1000;
+
+                // always scan the file, so we can return the content://media Uri for existing files
+                mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), true);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
         } finally {
@@ -1285,8 +1303,7 @@
             }
         }
 
-        // if the match is not for an audio file, bail out
-        if (bestMatch == null || ! mAudioUri.equals(bestMatch.mTableUri)) {
+        if (bestMatch == null) {
             return false;
         }
 
@@ -1431,63 +1448,67 @@
         }
     }
 
+    private void processPlayList(FileCacheEntry entry) throws RemoteException {
+        String path = entry.mPath;
+        ContentValues values = new ContentValues();
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
+        Uri uri, membersUri;
+        long rowId = entry.mRowId;
+        if (rowId == 0) {
+            // Create a new playlist
+
+            int lastDot = path.lastIndexOf('.');
+            String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot));
+            values.put(MediaStore.Audio.Playlists.NAME, name);
+            values.put(MediaStore.Audio.Playlists.DATA, path);
+            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
+            uri = mMediaProvider.insert(mPlaylistsUri, values);
+            rowId = ContentUris.parseId(uri);
+            membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
+        } else {
+            uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
+
+            // update lastModified value of existing playlist
+            values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
+            mMediaProvider.update(uri, values, null, null);
+
+            // delete members of existing playlist
+            membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
+            mMediaProvider.delete(membersUri, null, null);
+        }
+
+        String playListDirectory = path.substring(0, lastSlash + 1);
+        MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
+        int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
+
+        if (fileType == MediaFile.FILE_TYPE_M3U) {
+            processM3uPlayList(path, playListDirectory, membersUri, values);
+        } else if (fileType == MediaFile.FILE_TYPE_PLS) {
+            processPlsPlayList(path, playListDirectory, membersUri, values);
+        } else if (fileType == MediaFile.FILE_TYPE_WPL) {
+            processWplPlayList(path, playListDirectory, membersUri);
+        }
+
+        Cursor cursor = mMediaProvider.query(membersUri, PLAYLIST_MEMBERS_PROJECTION, null,
+                null, null);
+        try {
+            if (cursor == null || cursor.getCount() == 0) {
+                Log.d(TAG, "playlist is empty - deleting");
+                mMediaProvider.delete(uri, null, null);
+            }
+        } finally {
+            if (cursor != null) cursor.close();
+        }
+    }
+
     private void processPlayLists() throws RemoteException {
         Iterator<FileCacheEntry> iterator = mPlayLists.iterator();
         while (iterator.hasNext()) {
             FileCacheEntry entry = iterator.next();
-            String path = entry.mPath;
-
             // only process playlist files if they are new or have been modified since the last scan
             if (entry.mLastModifiedChanged) {
-                ContentValues values = new ContentValues();
-                int lastSlash = path.lastIndexOf('/');
-                if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
-                Uri uri, membersUri;
-                long rowId = entry.mRowId;
-                if (rowId == 0) {
-                    // Create a new playlist
-
-                    int lastDot = path.lastIndexOf('.');
-                    String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot));
-                    values.put(MediaStore.Audio.Playlists.NAME, name);
-                    values.put(MediaStore.Audio.Playlists.DATA, path);
-                    values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
-                    uri = mMediaProvider.insert(mPlaylistsUri, values);
-                    rowId = ContentUris.parseId(uri);
-                    membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
-                } else {
-                    uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-
-                    // update lastModified value of existing playlist
-                    values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
-                    mMediaProvider.update(uri, values, null, null);
-
-                    // delete members of existing playlist
-                    membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
-                    mMediaProvider.delete(membersUri, null, null);
-                }
-
-                String playListDirectory = path.substring(0, lastSlash + 1);
-                MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
-                int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
-
-                if (fileType == MediaFile.FILE_TYPE_M3U)
-                    processM3uPlayList(path, playListDirectory, membersUri, values);
-                else if (fileType == MediaFile.FILE_TYPE_PLS)
-                    processPlsPlayList(path, playListDirectory, membersUri, values);
-                else if (fileType == MediaFile.FILE_TYPE_WPL)
-                    processWplPlayList(path, playListDirectory, membersUri);
-
-                Cursor cursor = mMediaProvider.query(membersUri, PLAYLIST_MEMBERS_PROJECTION, null,
-                        null, null);
-                try {
-                    if (cursor == null || cursor.getCount() == 0) {
-                        Log.d(TAG, "playlist is empty - deleting");
-                        mMediaProvider.delete(uri, null, null);
-                    }
-                } finally {
-                    if (cursor != null) cursor.close();
-                }
+                processPlayList(entry);
             }
         }
     }
diff --git a/media/java/android/media/MtpConstants.java b/media/java/android/media/MtpConstants.java
index a7d33ce..b20cbd1 100644
--- a/media/java/android/media/MtpConstants.java
+++ b/media/java/android/media/MtpConstants.java
@@ -21,6 +21,30 @@
  */
 public final class MtpConstants {
 
+// MTP Data Types
+    public static final int TYPE_UNDEFINED = 0x0000;
+    public static final int TYPE_INT8 = 0x0001;
+    public static final int TYPE_UINT8 = 0x0002;
+    public static final int TYPE_INT16 = 0x0003;
+    public static final int TYPE_UINT16 = 0x0004;
+    public static final int TYPE_INT32 = 0x0005;
+    public static final int TYPE_UINT32 = 0x0006;
+    public static final int TYPE_INT64 = 0x0007;
+    public static final int TYPE_UINT64 = 0x0008;
+    public static final int TYPE_INT128 = 0x0009;
+    public static final int TYPE_UINT128 = 0x000A;
+    public static final int TYPE_AINT8 = 0x4001;
+    public static final int TYPE_AUINT8 = 0x4002;
+    public static final int TYPE_AINT16 = 0x4003;
+    public static final int TYPE_AUINT16 = 0x4004;
+    public static final int TYPE_AINT32 = 0x4005;
+    public static final int TYPE_AUINT32 = 0x4006;
+    public static final int TYPE_AINT64 = 0x4007;
+    public static final int TYPE_AUINT64 = 0x4008;
+    public static final int TYPE_AINT128 = 0x4009;
+    public static final int TYPE_AUINT128 = 0x400A;
+    public static final int TYPE_STR = 0xFFFF;
+
 // MTP Response Codes
     public static final int RESPONSE_UNDEFINED = 0x2000;
     public static final int RESPONSE_OK = 0x2001;
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 57ab3a1..42d068f 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -428,6 +428,26 @@
         }
     }
 
+    private String queryAudio(int id, String column) {
+        Cursor c = null;
+        try {
+            c = mMediaProvider.query(Audio.Media.getContentUri(mVolumeName),
+                            new String [] { Files.FileColumns._ID, column },
+                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+            if (c != null && c.moveToNext()) {
+                return c.getString(1);
+            } else {
+                return "";
+            }
+        } catch (Exception e) {
+            return null;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
     private String queryGenre(int id) {
         Cursor c = null;
         try {
@@ -450,7 +470,7 @@
         }
     }
 
-    private boolean queryInt(int id, String column, long[] outValue) {
+    private Long queryLong(int id, String column) {
         Cursor c = null;
         try {
             // for now we are only reading properties from the "objects" table
@@ -458,17 +478,15 @@
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null);
             if (c != null && c.moveToNext()) {
-                outValue[0] = c.getLong(1);
-                return true;
+                return new Long(c.getLong(1));
             }
-            return false;
         } catch (Exception e) {
-            return false;
         } finally {
             if (c != null) {
                 c.close();
             }
         }
+        return null;
     }
 
     private String nameFromPath(String path) {
@@ -485,6 +503,230 @@
         return path.substring(start, end);
     }
 
+    private MtpPropertyList getObjectPropertyList(int handle, int format, int property,
+                        int groupCode, int depth) {
+        // FIXME - implement group support
+        // For now we only support a single property at a time
+        if (groupCode != 0) {
+            return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED);
+        }
+        if (depth > 1) {
+            return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED);
+        }
+
+        String column = null;
+        int type = MtpConstants.TYPE_UNDEFINED;
+
+         switch (property) {
+            case MtpConstants.PROPERTY_STORAGE_ID:
+                // no query needed until we support multiple storage units
+                // for now it is always mStorageID
+                type = MtpConstants.TYPE_UINT32;
+                break;
+             case MtpConstants.PROPERTY_OBJECT_FORMAT:
+                column = Files.FileColumns.FORMAT;
+                type = MtpConstants.TYPE_UINT16;
+                break;
+            case MtpConstants.PROPERTY_PROTECTION_STATUS:
+                // protection status is always 0
+                type = MtpConstants.TYPE_UINT16;
+                break;
+            case MtpConstants.PROPERTY_OBJECT_SIZE:
+                column = Files.FileColumns.SIZE;
+                type = MtpConstants.TYPE_UINT64;
+                break;
+            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
+                column = Files.FileColumns.DATA;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_NAME:
+                column = MediaColumns.TITLE;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_DATE_MODIFIED:
+                column = Files.FileColumns.DATE_MODIFIED;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_DATE_ADDED:
+                column = Files.FileColumns.DATE_ADDED;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+                column = Audio.AudioColumns.YEAR;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_PARENT_OBJECT:
+                column = Files.FileColumns.PARENT;
+                type = MtpConstants.TYPE_UINT32;
+                break;
+            case MtpConstants.PROPERTY_PERSISTENT_UID:
+                // PUID is concatenation of storageID and object handle
+                type = MtpConstants.TYPE_UINT128;
+                break;
+            case MtpConstants.PROPERTY_DURATION:
+                column = Audio.AudioColumns.DURATION;
+                type = MtpConstants.TYPE_UINT32;
+                break;
+            case MtpConstants.PROPERTY_TRACK:
+                column = Audio.AudioColumns.TRACK;
+                type = MtpConstants.TYPE_UINT16;
+                break;
+            case MtpConstants.PROPERTY_DISPLAY_NAME:
+                column = MediaColumns.DISPLAY_NAME;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_ARTIST:
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_ALBUM_NAME:
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_ALBUM_ARTIST:
+                column = Audio.AudioColumns.ALBUM_ARTIST;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_GENRE:
+                // genre requires a special query
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_COMPOSER:
+                column = Audio.AudioColumns.COMPOSER;
+                type = MtpConstants.TYPE_STR;
+                break;
+            case MtpConstants.PROPERTY_DESCRIPTION:
+                column = Images.ImageColumns.DESCRIPTION;
+                type = MtpConstants.TYPE_STR;
+                break;
+            default:
+                return new MtpPropertyList(0, MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED);
+        }
+
+        Cursor c = null;
+        try {
+            if (column != null) {
+                c = mMediaProvider.query(mObjectsUri,
+                        new String [] { Files.FileColumns._ID, column },
+                        // depth 0: single record, depth 1: immediate children
+                        (depth == 0 ? ID_WHERE : PARENT_WHERE),
+                        new String[] { Integer.toString(handle) }, null);
+                if (c == null) {
+                    return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+                }
+            } else if (depth == 1) {
+                c = mMediaProvider.query(mObjectsUri,
+                        new String [] { Files.FileColumns._ID },
+                        PARENT_WHERE, new String[] { Integer.toString(handle) }, null);
+                if (c == null) {
+                    return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+                }
+            }
+
+            int count = (c == null ? 1 : c.getCount());
+            MtpPropertyList result = new MtpPropertyList(count, MtpConstants.RESPONSE_OK);
+
+            for (int index = 0; index < count; index++) {
+                if (c != null) {
+                    c.moveToNext();
+                }
+                if (depth == 1) {
+                    handle = (int)c.getLong(0);
+                }
+
+                switch (property) {
+                    // handle special cases here
+                    case MtpConstants.PROPERTY_STORAGE_ID:
+                        result.setProperty(index, handle, property, MtpConstants.TYPE_UINT32,
+                                mStorageID);
+                        break;
+                    case MtpConstants.PROPERTY_PROTECTION_STATUS:
+                        // protection status is always 0
+                        result.setProperty(index, handle, property, MtpConstants.TYPE_UINT16, 0);
+                        break;
+                    case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
+                        // special case - need to extract file name from full path
+                        String value = c.getString(1);
+                        if (value != null) {
+                            result.setProperty(index, handle, property, nameFromPath(value));
+                        } else {
+                            result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+                        }
+                        break;
+                    case MtpConstants.PROPERTY_NAME:
+                        // first try title
+                        String name = c.getString(1);
+                        // then try name
+                        if (name == null) {
+                            name = queryString(handle, Audio.PlaylistsColumns.NAME);
+                        }
+                        // if title and name fail, extract name from full path
+                        if (name == null) {
+                            name = queryString(handle, Files.FileColumns.DATA);
+                            if (name != null) {
+                                name = nameFromPath(name);
+                            }
+                        }
+                        if (name != null) {
+                            result.setProperty(index, handle, property, name);
+                        } else {
+                            result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+                        }
+                        break;
+                    case MtpConstants.PROPERTY_DATE_MODIFIED:
+                    case MtpConstants.PROPERTY_DATE_ADDED:
+                        // convert from seconds to DateTime
+                        result.setProperty(index, handle, property, format_date_time(c.getInt(1)));
+                        break;
+                    case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+                        // release date is stored internally as just the year
+                        int year = c.getInt(1);
+                        String dateTime = Integer.toString(year) + "0101T000000";
+                        result.setProperty(index, handle, property, dateTime);
+                        break;
+                    case MtpConstants.PROPERTY_PERSISTENT_UID:
+                        // PUID is concatenation of storageID and object handle
+                        long puid = mStorageID;
+                        puid <<= 32;
+                        puid += handle;
+                        result.setProperty(index, handle, property, MtpConstants.TYPE_UINT128, puid);
+                        break;
+                    case MtpConstants.PROPERTY_TRACK:
+                        result.setProperty(index, handle, property, MtpConstants.TYPE_UINT16,
+                                    c.getInt(1) % 1000);
+                        break;
+                    case MtpConstants.PROPERTY_ARTIST:
+                        result.setProperty(index, handle, property, queryAudio(handle, Audio.AudioColumns.ARTIST));
+                        break;
+                    case MtpConstants.PROPERTY_ALBUM_NAME:
+                        result.setProperty(index, handle, property, queryAudio(handle, Audio.AudioColumns.ALBUM));
+                        break;
+                    case MtpConstants.PROPERTY_GENRE:
+                        String genre = queryGenre(handle);
+                        if (genre != null) {
+                            result.setProperty(index, handle, property, genre);
+                        } else {
+                            result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+                        }
+                        break;
+                    default:
+                        if (type == MtpConstants.TYPE_STR) {
+                            result.setProperty(index, handle, property, c.getString(1));
+                        } else {
+                            result.setProperty(index, handle, property, type, c.getLong(1));
+                        }
+                }
+            }
+
+            return result;
+        } catch (RemoteException e) {
+            return new MtpPropertyList(0, MtpConstants.RESPONSE_GENERAL_ERROR);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        // impossible to get here, so no return statement
+    }
+
     private int renameFile(int handle, String newName) {
         Cursor c = null;
 
@@ -543,141 +785,6 @@
         return MtpConstants.RESPONSE_OK;
     }
 
-    private int getObjectProperty(int handle, int property,
-                            long[] outIntValue, char[] outStringValue) {
-        Log.d(TAG, "getObjectProperty: " + property);
-        String column = null;
-        boolean isString = false;
-
-        switch (property) {
-            case MtpConstants.PROPERTY_STORAGE_ID:
-                outIntValue[0] = mStorageID;
-                return MtpConstants.RESPONSE_OK;
-            case MtpConstants.PROPERTY_OBJECT_FORMAT:
-                column = Files.FileColumns.FORMAT;
-                break;
-            case MtpConstants.PROPERTY_PROTECTION_STATUS:
-                // protection status is always 0
-                outIntValue[0] = 0;
-                return MtpConstants.RESPONSE_OK;
-            case MtpConstants.PROPERTY_OBJECT_SIZE:
-                column = Files.FileColumns.SIZE;
-                break;
-            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
-                // special case - need to extract file name from full path
-                String value = queryString(handle, Files.FileColumns.DATA);
-                if (value != null) {
-                    value = nameFromPath(value);
-                    value.getChars(0, value.length(), outStringValue, 0);
-                    outStringValue[value.length()] = 0;
-                    return MtpConstants.RESPONSE_OK;
-                } else {
-                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-                }
-            case MtpConstants.PROPERTY_NAME:
-                // first try title
-                String name = queryString(handle, MediaColumns.TITLE);
-                // then try name
-                if (name == null) {
-                    name = queryString(handle, Audio.PlaylistsColumns.NAME);
-                }
-                // if title and name fail, extract name from full path
-                if (name == null) {
-                    name = queryString(handle, Files.FileColumns.DATA);
-                    if (name != null) {
-                        name = nameFromPath(name);
-                    }
-                }
-                if (name != null) {
-                    name.getChars(0, name.length(), outStringValue, 0);
-                    outStringValue[name.length()] = 0;
-                    return MtpConstants.RESPONSE_OK;
-                } else {
-                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-                }
-            case MtpConstants.PROPERTY_DATE_MODIFIED:
-                column = Files.FileColumns.DATE_MODIFIED;
-                break;
-            case MtpConstants.PROPERTY_DATE_ADDED:
-                column = Files.FileColumns.DATE_ADDED;
-                break;
-            case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
-                column = Audio.AudioColumns.YEAR;
-                break;
-            case MtpConstants.PROPERTY_PARENT_OBJECT:
-                column = Files.FileColumns.PARENT;
-                break;
-            case MtpConstants.PROPERTY_PERSISTENT_UID:
-                // PUID is concatenation of storageID and object handle
-                long puid = mStorageID;
-                puid <<= 32;
-                puid += handle;
-                outIntValue[0] = puid;
-                return MtpConstants.RESPONSE_OK;
-            case MtpConstants.PROPERTY_DURATION:
-                column = Audio.AudioColumns.DURATION;
-                break;
-            case MtpConstants.PROPERTY_TRACK:
-                if (queryInt(handle, Audio.AudioColumns.TRACK, outIntValue)) {
-                    // track is stored in lower 3 decimal digits
-                    outIntValue[0] %= 1000;
-                    return MtpConstants.RESPONSE_OK;
-                } else {
-                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-                }
-            case MtpConstants.PROPERTY_DISPLAY_NAME:
-                column = MediaColumns.DISPLAY_NAME;
-                isString = true;
-                break;
-            case MtpConstants.PROPERTY_ARTIST:
-                column = Audio.AudioColumns.ARTIST;
-                isString = true;
-                break;
-            case MtpConstants.PROPERTY_ALBUM_NAME:
-                column = Audio.AudioColumns.ALBUM;
-                isString = true;
-                break;
-            case MtpConstants.PROPERTY_ALBUM_ARTIST:
-                column = Audio.AudioColumns.ALBUM_ARTIST;
-                isString = true;
-                break;
-            case MtpConstants.PROPERTY_GENRE:
-                String genre = queryGenre(handle);
-                if (genre != null) {
-                    genre.getChars(0, genre.length(), outStringValue, 0);
-                    outStringValue[genre.length()] = 0;
-                    return MtpConstants.RESPONSE_OK;
-                } else {
-                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-                }
-            case MtpConstants.PROPERTY_COMPOSER:
-                column = Audio.AudioColumns.COMPOSER;
-                isString = true;
-                break;
-            case MtpConstants.PROPERTY_DESCRIPTION:
-                column = Images.ImageColumns.DESCRIPTION;
-                isString = true;
-                break;
-            default:
-                return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
-        }
-
-        if (isString) {
-            String value = queryString(handle, column);
-            if (value != null) {
-                value.getChars(0, value.length(), outStringValue, 0);
-                outStringValue[value.length()] = 0;
-                return MtpConstants.RESPONSE_OK;
-            }
-        } else {
-            if (queryInt(handle, column, outIntValue)) {
-                return MtpConstants.RESPONSE_OK;
-            }
-        }
-        // query failed if we get here
-        return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
-    }
-
     private int setObjectProperty(int handle, int property,
                             long intValue, String stringValue) {
         Log.d(TAG, "setObjectProperty: " + property);
@@ -913,4 +1020,5 @@
 
     private native final void native_setup();
     private native final void native_finalize();
+    private native String format_date_time(long seconds);
 }
diff --git a/media/java/android/media/MtpPropertyList.java b/media/java/android/media/MtpPropertyList.java
new file mode 100644
index 0000000..f598981
--- /dev/null
+++ b/media/java/android/media/MtpPropertyList.java
@@ -0,0 +1,76 @@
+/*
+ * 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 android.media;
+
+/**
+ * Encapsulates the ObjectPropList dataset used by the GetObjectPropList command.
+ * The fields of this class are read by JNI code in android_media_MtpDatabase.cpp
+ *
+ * {@hide}
+ */
+
+public class MtpPropertyList {
+
+    // number of results returned
+    public final int        mCount;
+    // result code for GetObjectPropList
+    public int              mResult;
+    // list of object handles (first field in quadruplet)
+    public final int[]      mObjectHandles;
+    // list of object propery codes (second field in quadruplet)
+    public final int[]      mPropertyCodes;
+    // list of data type codes (third field in quadruplet)
+    public final int[]     mDataTypes;
+    // list of long int property values (fourth field in quadruplet, when value is integer type)
+    public long[]     mLongValues;
+    // list of long int property values (fourth field in quadruplet, when value is string type)
+    public String[]   mStringValues;
+
+    // constructor only called from MtpDatabase
+    public MtpPropertyList(int count, int result) {
+        mCount = count;
+        mResult = result;
+        mObjectHandles = new int[count];
+        mPropertyCodes = new int[count];
+        mDataTypes = new int[count];
+        // mLongValues and mStringValues are created lazily since both might not be necessary
+    }
+
+    public void setProperty(int index, int handle, int property, int type, long value) {
+        if (mLongValues == null) {
+            mLongValues = new long[mCount];
+        }
+        mObjectHandles[index] = handle;
+        mPropertyCodes[index] = property;
+        mDataTypes[index] = type;
+        mLongValues[index] = value;
+    }
+
+    public void setProperty(int index, int handle, int property, String value) {
+        if (mStringValues == null) {
+            mStringValues = new String[mCount];
+        }
+        mObjectHandles[index] = handle;
+        mPropertyCodes[index] = property;
+        mDataTypes[index] = MtpConstants.TYPE_STR;
+        mStringValues[index] = value;
+    }
+
+    public void setResult(int result) {
+        mResult = result;
+    }
+}
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index 87cb82e..5377af6 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -46,10 +46,10 @@
 static jmethodID method_getSupportedCaptureFormats;
 static jmethodID method_getSupportedObjectProperties;
 static jmethodID method_getSupportedDeviceProperties;
-static jmethodID method_getObjectProperty;
 static jmethodID method_setObjectProperty;
 static jmethodID method_getDeviceProperty;
 static jmethodID method_setDeviceProperty;
+static jmethodID method_getObjectPropertyList;
 static jmethodID method_getObjectInfo;
 static jmethodID method_getObjectFilePath;
 static jmethodID method_deleteFile;
@@ -60,6 +60,16 @@
 
 static jfieldID field_context;
 
+// MtpPropertyList fields
+static jfieldID field_mCount;
+static jfieldID field_mResult;
+static jfieldID field_mObjectHandles;
+static jfieldID field_mPropertyCodes;
+static jfieldID field_mDataTypes;
+static jfieldID field_mLongValues;
+static jfieldID field_mStringValues;
+
+
 MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
     return (MtpDatabase *)env->GetIntField(database, field_context);
 }
@@ -122,6 +132,12 @@
 
     virtual MtpResponseCode         resetDeviceProperty(MtpDeviceProperty property);
 
+    virtual MtpResponseCode         getObjectPropertyList(MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            MtpObjectProperty property,
+                                            int groupCode, int depth,
+                                            MtpDataPacket& packet);
+
     virtual MtpResponseCode         getObjectInfo(MtpObjectHandle handle,
                                             MtpDataPacket& packet);
 
@@ -336,84 +352,111 @@
 MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
                                             MtpObjectProperty property,
                                             MtpDataPacket& packet) {
-    int         type;
-
-    if (!getObjectPropertyInfo(property, type))
-        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
-
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jint result = env->CallIntMethod(mDatabase, method_getObjectProperty,
-                (jint)handle, (jint)property, mLongBuffer, mStringBuffer);
-    if (result != MTP_RESPONSE_OK) {
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-        return result;
+    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
+                (jint)handle, 0, (jint)property, 0, 0);
+    MtpResponseCode result = env->GetIntField(list, field_mResult);
+    int count = env->GetIntField(list, field_mCount);
+    if (result == MTP_RESPONSE_OK && count != 1)
+        result = MTP_RESPONSE_GENERAL_ERROR;
+
+    if (result == MTP_RESPONSE_OK) {
+        jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
+        jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
+        jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
+        jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
+        jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
+
+        jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
+        jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
+        jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
+        jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
+
+        int type = dataTypes[0];
+        jlong longValue = (longValues ? longValues[0] : 0);
+
+        // special case date properties, which are strings to MTP
+        // but stored internally as a uint64
+        if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
+            char    date[20];
+            formatDateTime(longValue, date, sizeof(date));
+            packet.putString(date);
+            goto out;
+        }
+        // release date is stored internally as just the year
+        if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
+            char    date[20];
+            snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
+            packet.putString(date);
+            goto out;
+        }
+
+        switch (type) {
+            case MTP_TYPE_INT8:
+                packet.putInt8(longValue);
+                break;
+            case MTP_TYPE_UINT8:
+                packet.putUInt8(longValue);
+                break;
+            case MTP_TYPE_INT16:
+                packet.putInt16(longValue);
+                break;
+            case MTP_TYPE_UINT16:
+                packet.putUInt16(longValue);
+                break;
+            case MTP_TYPE_INT32:
+                packet.putInt32(longValue);
+                break;
+            case MTP_TYPE_UINT32:
+                packet.putUInt32(longValue);
+                break;
+            case MTP_TYPE_INT64:
+                packet.putInt64(longValue);
+                break;
+            case MTP_TYPE_UINT64:
+                packet.putUInt64(longValue);
+                break;
+            case MTP_TYPE_INT128:
+                packet.putInt128(longValue);
+                break;
+            case MTP_TYPE_UINT128:
+                packet.putInt128(longValue);
+                break;
+            case MTP_TYPE_STR:
+            {
+                jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
+                if (stringValue) {
+                    const char* str = env->GetStringUTFChars(stringValue, NULL);
+                    packet.putString(str);
+                    env->ReleaseStringUTFChars(stringValue, str);
+                } else {
+                    packet.putEmptyString();
+                }
+                break;
+             }
+            default:
+                LOGE("unsupported type in getObjectPropertyValue\n");
+                result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+        }
+out:
+        env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
+        env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
+        env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
+        if (longValues)
+            env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
+
+        env->DeleteLocalRef(objectHandlesArray);
+        env->DeleteLocalRef(propertyCodesArray);
+        env->DeleteLocalRef(dataTypesArray);
+        if (longValuesArray)
+            env->DeleteLocalRef(longValuesArray);
+        if (stringValuesArray)
+            env->DeleteLocalRef(stringValuesArray);
     }
 
-    jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
-    jlong longValue = longValues[0];
-    env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
-
-    // special case date properties, which are strings to MTP
-    // but stored internally as a uint64
-    if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
-        char    date[20];
-        formatDateTime(longValue, date, sizeof(date));
-        packet.putString(date);
-        return MTP_RESPONSE_OK;
-    }
-    // release date is stored internally as just the year
-    if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
-        char    date[20];
-        snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
-        packet.putString(date);
-        return MTP_RESPONSE_OK;
-    }
-
-    switch (type) {
-        case MTP_TYPE_INT8:
-            packet.putInt8(longValue);
-            break;
-        case MTP_TYPE_UINT8:
-            packet.putUInt8(longValue);
-            break;
-        case MTP_TYPE_INT16:
-            packet.putInt16(longValue);
-            break;
-        case MTP_TYPE_UINT16:
-            packet.putUInt16(longValue);
-            break;
-        case MTP_TYPE_INT32:
-            packet.putInt32(longValue);
-            break;
-        case MTP_TYPE_UINT32:
-            packet.putUInt32(longValue);
-            break;
-        case MTP_TYPE_INT64:
-            packet.putInt64(longValue);
-            break;
-        case MTP_TYPE_UINT64:
-            packet.putUInt64(longValue);
-            break;
-        case MTP_TYPE_INT128:
-            packet.putInt128(longValue);
-            break;
-        case MTP_TYPE_UINT128:
-            packet.putInt128(longValue);
-            break;
-        case MTP_TYPE_STR:
-        {
-            jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
-            packet.putString(str);
-            env->ReleaseCharArrayElements(mStringBuffer, str, 0);
-            break;
-         }
-        default:
-            LOGE("unsupported type in getObjectPropertyValue\n");
-            return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
-    }
-
+    env->DeleteLocalRef(list);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return MTP_RESPONSE_OK;
+    return result;
 }
 
 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
@@ -601,6 +644,106 @@
     return -1;
 }
 
+MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            MtpObjectProperty property,
+                                            int groupCode, int depth,
+                                            MtpDataPacket& packet) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
+                (jint)handle, (jint)format, (jint)property, (jint)groupCode, (jint)depth);
+    int count = env->GetIntField(list, field_mCount);
+    MtpResponseCode result = env->GetIntField(list, field_mResult);
+
+    packet.putUInt32(count);
+
+    if (count > 0) {
+        jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
+        jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
+        jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
+        jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
+        jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
+
+        jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
+        jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
+        jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
+        jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
+
+        for (int i = 0; i < count; i++) {
+            packet.putUInt32(objectHandles[i]);
+            packet.putUInt16(propertyCodes[i]);
+            int type = dataTypes[i];
+            packet.putUInt16(type);
+
+            switch (type) {
+                case MTP_TYPE_INT8:
+                    packet.putInt8(longValues[i]);
+                    break;
+                case MTP_TYPE_UINT8:
+                    packet.putUInt8(longValues[i]);
+                    break;
+                case MTP_TYPE_INT16:
+                    packet.putInt16(longValues[i]);
+                    break;
+                case MTP_TYPE_UINT16:
+                    packet.putUInt16(longValues[i]);
+                    break;
+                case MTP_TYPE_INT32:
+                    packet.putInt32(longValues[i]);
+                    break;
+                case MTP_TYPE_UINT32:
+                    packet.putUInt32(longValues[i]);
+                    break;
+                case MTP_TYPE_INT64:
+                    packet.putInt64(longValues[i]);
+                    break;
+                case MTP_TYPE_UINT64:
+                    packet.putUInt64(longValues[i]);
+                    break;
+                case MTP_TYPE_INT128:
+                    packet.putInt128(longValues[i]);
+                    break;
+                case MTP_TYPE_UINT128:
+                    packet.putUInt128(longValues[i]);
+                    break;
+                case MTP_TYPE_STR: {
+                    jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
+                    const char *valueStr = env->GetStringUTFChars(value, NULL);
+                    if (valueStr) {
+                        packet.putString(valueStr);
+                        env->ReleaseStringUTFChars(value, valueStr);
+                    } else {
+                        packet.putEmptyString();
+                    }
+                    env->DeleteLocalRef(value);
+                    break;
+                }
+                default:
+                    LOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
+                    break;
+            }
+        }
+
+        env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
+        env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
+        env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
+        if (longValues)
+            env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
+
+        env->DeleteLocalRef(objectHandlesArray);
+        env->DeleteLocalRef(propertyCodesArray);
+        env->DeleteLocalRef(dataTypesArray);
+        if (longValuesArray)
+            env->DeleteLocalRef(longValuesArray);
+        if (stringValuesArray)
+            env->DeleteLocalRef(stringValuesArray);
+    }
+
+    env->DeleteLocalRef(list);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
+}
+
 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
                                             MtpDataPacket& packet) {
     char    date[20];
@@ -894,11 +1037,25 @@
 #endif
 }
 
+static jstring
+android_media_MtpDatabase_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
+{
+#ifdef HAVE_ANDROID_OS
+    char    date[20];
+    formatDateTime(seconds, date, sizeof(date));
+    return env->NewStringUTF(date);
+#else
+    return NULL;
+#endif
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
     {"native_setup",            "()V",  (void *)android_media_MtpDatabase_setup},
     {"native_finalize",         "()V",  (void *)android_media_MtpDatabase_finalize},
+    {"format_date_time",        "(J)Ljava/lang/String;",
+                                        (void *)android_media_MtpDatabase_format_date_time},
 };
 
 static const char* const kClassPathName = "android/media/MtpDatabase";
@@ -954,11 +1111,6 @@
         LOGE("Can't find getSupportedDeviceProperties");
         return -1;
     }
-    method_getObjectProperty = env->GetMethodID(clazz, "getObjectProperty", "(II[J[C)I");
-    if (method_getObjectProperty == NULL) {
-        LOGE("Can't find getObjectProperty");
-        return -1;
-    }
     method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
     if (method_setObjectProperty == NULL) {
         LOGE("Can't find setObjectProperty");
@@ -974,6 +1126,12 @@
         LOGE("Can't find setDeviceProperty");
         return -1;
     }
+    method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
+            "(IIIII)Landroid/media/MtpPropertyList;");
+    if (method_getObjectPropertyList == NULL) {
+        LOGE("Can't find getObjectPropertyList");
+        return -1;
+    }
     method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
     if (method_getObjectInfo == NULL) {
         LOGE("Can't find getObjectInfo");
@@ -1016,6 +1174,48 @@
         return -1;
     }
 
+    // now set up fields for MtpPropertyList class
+    clazz = env->FindClass("android/media/MtpPropertyList");
+    if (clazz == NULL) {
+        LOGE("Can't find android/media/MtpPropertyList");
+        return -1;
+    }
+    field_mCount = env->GetFieldID(clazz, "mCount", "I");
+    if (field_mCount == NULL) {
+        LOGE("Can't find MtpPropertyList.mCount");
+        return -1;
+    }
+    field_mResult = env->GetFieldID(clazz, "mResult", "I");
+    if (field_mResult == NULL) {
+        LOGE("Can't find MtpPropertyList.mResult");
+        return -1;
+    }
+    field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
+    if (field_mObjectHandles == NULL) {
+        LOGE("Can't find MtpPropertyList.mObjectHandles");
+        return -1;
+    }
+    field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
+    if (field_mPropertyCodes == NULL) {
+        LOGE("Can't find MtpPropertyList.mPropertyCodes");
+        return -1;
+    }
+    field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
+    if (field_mDataTypes == NULL) {
+        LOGE("Can't find MtpPropertyList.mDataTypes");
+        return -1;
+    }
+    field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
+    if (field_mLongValues == NULL) {
+        LOGE("Can't find MtpPropertyList.mLongValues");
+        return -1;
+    }
+    field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
+    if (field_mStringValues == NULL) {
+        LOGE("Can't find MtpPropertyList.mStringValues");
+        return -1;
+    }
+
     return AndroidRuntime::registerNativeMethods(env,
                 "android/media/MtpDatabase", gMethods, NELEM(gMethods));
 }
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 1a46715..c287c0a 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -29,7 +29,6 @@
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_VIDEO_SURFACE,
-    SET_VIDEO_ISURFACE,
     PREPARE_ASYNC,
     START,
     STOP,
@@ -65,15 +64,6 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
-    status_t setVideoISurface(const sp<ISurface>& surface)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-        data.writeStrongBinder(surface->asBinder());
-        remote()->transact(SET_VIDEO_ISURFACE, data, &reply);
-        return reply.readInt32();
-    }
-
     status_t setVideoSurface(const sp<Surface>& surface)
     {
         Parcel data, reply;
@@ -245,12 +235,6 @@
             disconnect();
             return NO_ERROR;
         } break;
-        case SET_VIDEO_ISURFACE: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
-            reply->writeInt32(setVideoISurface(surface));
-            return NO_ERROR;
-        } break;
         case SET_VIDEO_SURFACE: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<Surface> surface = Surface::readFromParcel(data);
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f975217..9ce6738 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -31,48 +31,9 @@
     FILL_BUFFER,
     EMPTY_BUFFER,
     GET_EXTENSION_INDEX,
-    CREATE_RENDERER,
     OBSERVER_ON_MSG,
-    RENDERER_RENDER,
 };
 
-sp<IOMXRenderer> IOMX::createRenderer(
-        const sp<Surface> &surface,
-        const char *componentName,
-        OMX_COLOR_FORMATTYPE colorFormat,
-        size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
-    return createRenderer(
-            surface->getISurface(),
-            componentName, colorFormat, encodedWidth, encodedHeight,
-            displayWidth, displayHeight);
-}
-
-sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
-        JNIEnv *env, jobject javaSurface,
-        const char *componentName,
-        OMX_COLOR_FORMATTYPE colorFormat,
-        size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
-    jclass surfaceClass = env->FindClass("android/view/Surface");
-    if (surfaceClass == NULL) {
-        LOGE("Can't find android/view/Surface");
-        return NULL;
-    }
-
-    jfieldID surfaceID = env->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    if (surfaceID == NULL) {
-        LOGE("Can't find Surface.mSurface");
-        return NULL;
-    }
-
-    sp<Surface> surface = (Surface *)env->GetIntField(javaSurface, surfaceID);
-
-    return createRenderer(
-            surface, componentName, colorFormat, encodedWidth,
-            encodedHeight, displayWidth, displayHeight);
-}
-
 class BpOMX : public BpInterface<IOMX> {
 public:
     BpOMX(const sp<IBinder> &impl)
@@ -395,28 +356,6 @@
 
         return err;
     }
-
-    virtual sp<IOMXRenderer> createRenderer(
-            const sp<ISurface> &surface,
-            const char *componentName,
-            OMX_COLOR_FORMATTYPE colorFormat,
-            size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-
-        data.writeStrongBinder(surface->asBinder());
-        data.writeCString(componentName);
-        data.writeInt32(colorFormat);
-        data.writeInt32(encodedWidth);
-        data.writeInt32(encodedHeight);
-        data.writeInt32(displayWidth);
-        data.writeInt32(displayHeight);
-
-        remote()->transact(CREATE_RENDERER, data, &reply);
-
-        return interface_cast<IOMXRenderer>(reply.readStrongBinder());
-    }
 };
 
 IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
@@ -767,33 +706,6 @@
             return OK;
         }
 
-        case CREATE_RENDERER:
-        {
-            CHECK_INTERFACE(IOMX, data, reply);
-
-            sp<ISurface> isurface =
-                interface_cast<ISurface>(data.readStrongBinder());
-
-            const char *componentName = data.readCString();
-
-            OMX_COLOR_FORMATTYPE colorFormat =
-                static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
-
-            size_t encodedWidth = (size_t)data.readInt32();
-            size_t encodedHeight = (size_t)data.readInt32();
-            size_t displayWidth = (size_t)data.readInt32();
-            size_t displayHeight = (size_t)data.readInt32();
-
-            sp<IOMXRenderer> renderer =
-                createRenderer(isurface, componentName, colorFormat,
-                               encodedWidth, encodedHeight,
-                               displayWidth, displayHeight);
-
-            reply->writeStrongBinder(renderer->asBinder());
-
-            return OK;
-        }
-
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
@@ -839,44 +751,4 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-class BpOMXRenderer : public BpInterface<IOMXRenderer> {
-public:
-    BpOMXRenderer(const sp<IBinder> &impl)
-        : BpInterface<IOMXRenderer>(impl) {
-    }
-
-    virtual void render(IOMX::buffer_id buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)buffer);
-
-        // NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
-        // so that the caller knows when to recycle the buffer.
-        remote()->transact(RENDERER_RENDER, data, &reply);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
-
-status_t BnOMXRenderer::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case RENDERER_RENDER:
-        {
-            CHECK_INTERFACE(IOMXRenderer, data, reply);
-
-            IOMX::buffer_id buffer = (void*)data.readIntPtr();
-
-            render(buffer);
-
-            return NO_ERROR;
-        }
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
 }  // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 34e41a1..54b292c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -198,13 +198,6 @@
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
 
-    status_t err = mPlayer->setVideoISurface(
-            surface == NULL ? NULL : surface->getISurface());
-
-    if (err != OK) {
-        return err;
-    }
-
     return mPlayer->setVideoSurface(surface);
 }
 
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 55846be..3341ff7 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -38,14 +38,6 @@
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_rtsp
 
-ifneq ($(BUILD_WITHOUT_PV),true)
-LOCAL_SHARED_LIBRARIES += \
-	libopencore_player    \
-	libopencore_author
-else
-LOCAL_CFLAGS += -DNO_OPENCORE
-endif
-
 ifneq ($(TARGET_SIMULATOR),true)
 LOCAL_SHARED_LIBRARIES += libdl
 endif
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index bb86e05..00e510b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -56,7 +56,6 @@
 #include "MetadataRetrieverClient.h"
 
 #include "MidiFile.h"
-#include <media/PVPlayer.h>
 #include "TestPlayerStub.h"
 #include "StagefrightPlayer.h"
 
@@ -196,11 +195,6 @@
         {".rtttl", SONIVOX_PLAYER},
         {".rtx", SONIVOX_PLAYER},
         {".ota", SONIVOX_PLAYER},
-#ifndef NO_OPENCORE
-        {".wma", PV_PLAYER},
-        {".wmv", PV_PLAYER},
-        {".asf", PV_PLAYER},
-#endif
 };
 
 // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
@@ -691,14 +685,6 @@
     if (ident == 0x5367674f) // 'OggS'
         return STAGEFRIGHT_PLAYER;
 
-#ifndef NO_OPENCORE
-    if (ident == 0x75b22630) {
-        // The magic number for .asf files, i.e. wmv and wma content.
-        // These are not currently supported through stagefright.
-        return PV_PLAYER;
-    }
-#endif
-
     // Some kind of MIDI?
     EAS_DATA_HANDLE easdata;
     if (EAS_Init(&easdata) == EAS_SUCCESS) {
@@ -737,16 +723,6 @@
         }
     }
 
-    if (!strncasecmp(url, "rtsp://", 7)) {
-        char value[PROPERTY_VALUE_MAX];
-        if (property_get("media.stagefright.enable-rtsp", value, NULL)
-            && (strcmp(value, "1") && strcasecmp(value, "true"))) {
-            // For now, we're going to use PV for rtsp-based playback
-            // by default until we can clear up a few more issues.
-            return PV_PLAYER;
-        }
-    }
-
     return getDefaultPlayerType();
 }
 
@@ -755,12 +731,6 @@
 {
     sp<MediaPlayerBase> p;
     switch (playerType) {
-#ifndef NO_OPENCORE
-        case PV_PLAYER:
-            LOGV(" create PVPlayer");
-            p = new PVPlayer();
-            break;
-#endif
         case SONIVOX_PLAYER:
             LOGV(" create MidiFile");
             p = new MidiFile();
@@ -773,6 +743,9 @@
             LOGV("Create Test Player stub");
             p = new TestPlayerStub();
             break;
+        default:
+            LOGE("Unknown player type: %d", playerType);
+            return NULL;
     }
     if (p != NULL) {
         if (p->initCheck() == NO_ERROR) {
@@ -891,14 +864,6 @@
     return mStatus;
 }
 
-status_t MediaPlayerService::Client::setVideoISurface(const sp<ISurface>& surface)
-{
-    LOGV("[%d] setVideoISurface(%p)", mConnId, surface.get());
-    sp<MediaPlayerBase> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->setVideoISurface(surface);
-}
-
 status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
 {
     LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index e197cde..184324c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -206,7 +206,6 @@
 
         // IMediaPlayer interface
         virtual void            disconnect();
-        virtual status_t        setVideoISurface(const sp<ISurface>& surface);
         virtual status_t        setVideoSurface(const sp<Surface>& surface);
         virtual status_t        prepareAsync();
         virtual status_t        start();
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index be6a8be..1a1780c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -31,10 +31,6 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
-#ifndef NO_OPENCORE
-#include <media/PVMediaRecorder.h>
-#endif
-
 #include <utils/String16.h>
 
 #include <media/AudioTrack.h>
@@ -304,22 +300,7 @@
 {
     LOGV("Client constructor");
     mPid = pid;
-
-    char value[PROPERTY_VALUE_MAX];
-    if (!property_get("media.stagefright.enable-record", value, NULL)
-        || !strcmp(value, "1") || !strcasecmp(value, "true")) {
-        mRecorder = new StagefrightRecorder;
-    } else
-#ifndef NO_OPENCORE
-    {
-        mRecorder = new PVMediaRecorder();
-    }
-#else
-    {
-        mRecorder = NULL;
-    }
-#endif
-
+    mRecorder = new StagefrightRecorder;
     mMediaPlayerService = service;
 }
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 39fce81..b069345 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,7 +35,6 @@
 #include <binder/IServiceManager.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
-#include <media/PVMetadataRetriever.h>
 #include <private/media/VideoFrame.h>
 #include "MidiMetadataRetriever.h"
 #include "MetadataRetrieverClient.h"
@@ -107,12 +106,6 @@
             p = new StagefrightMetadataRetriever;
             break;
         }
-#ifndef NO_OPENCORE
-        case PV_PLAYER:
-            LOGV("create pv metadata retriever");
-            p = new PVMetadataRetriever();
-            break;
-#endif
         case SONIVOX_PLAYER:
             LOGV("create midi metadata retriever");
             p = new MidiMetadataRetriever();
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 06e4b70..aa8f3f0e 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -35,7 +35,6 @@
             const char* path, const KeyedVector<String8, String8> *headers);
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
-    virtual status_t    setVideoISurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
     virtual status_t    setVideoSurface(const sp<Surface>& surface) { return UNKNOWN_ERROR; }
     virtual status_t    prepare();
     virtual status_t    prepareAsync();
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index e0957f6..58ef99b 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -44,13 +44,6 @@
     return mPlayer->setDataSource(dup(fd), offset, length);
 }
 
-status_t StagefrightPlayer::setVideoISurface(const sp<ISurface> &surface) {
-    LOGV("setVideoISurface");
-
-    mPlayer->setISurface(surface);
-    return OK;
-}
-
 status_t StagefrightPlayer::setVideoSurface(const sp<Surface> &surface) {
     LOGV("setVideoSurface");
 
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 3899447..c4a2588 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -35,7 +35,6 @@
             const char *url, const KeyedVector<String8, String8> *headers);
 
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
-    virtual status_t setVideoISurface(const sp<ISurface> &surface);
     virtual status_t setVideoSurface(const sp<Surface> &surface);
     virtual status_t prepare();
     virtual status_t prepareAsync();
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index 5eaf592..6abd8e3 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -75,9 +75,6 @@
 
 
     // All the methods below wrap the mPlayer instance.
-    virtual status_t setVideoISurface(const android::sp<android::ISurface>& s)  {
-        return mPlayer->setVideoISurface(s);
-    }
     virtual status_t setVideoSurface(const android::sp<android::Surface>& s)  {
         return mPlayer->setVideoSurface(s);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 1df0bed..8fe1d4d 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -68,7 +68,8 @@
         libsurfaceflinger_client \
         libstagefright_yuv \
         libcamera_client \
-        libdrmframework
+        libdrmframework  \
+        libcrypto
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_aacdec \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f084e28..ff9f255 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -49,6 +49,8 @@
 
 #include <media/stagefright/foundation/ALooper.h>
 
+#define USE_SURFACE_ALLOC 1
+
 namespace android {
 
 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
@@ -77,39 +79,16 @@
     AwesomeEvent &operator=(const AwesomeEvent &);
 };
 
-struct AwesomeRemoteRenderer : public AwesomeRenderer {
-    AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
-        : mTarget(target) {
-    }
-
-    virtual void render(MediaBuffer *buffer) {
-        void *id;
-        if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
-            mTarget->render((IOMX::buffer_id)id);
-        }
-    }
-
-private:
-    sp<IOMXRenderer> mTarget;
-
-    AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
-    AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
-};
-
 struct AwesomeLocalRenderer : public AwesomeRenderer {
     AwesomeLocalRenderer(
-            bool previewOnly,
-            const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
-            const sp<ISurface> &isurface,
             const sp<Surface> &surface,
             size_t displayWidth, size_t displayHeight,
             size_t decodedWidth, size_t decodedHeight)
-        : mTarget(NULL),
-          mLibHandle(NULL) {
-            init(previewOnly, componentName,
-                 colorFormat, isurface, surface, displayWidth,
-                 displayHeight, decodedWidth, decodedHeight);
+        : mTarget(NULL) {
+            init(colorFormat, surface,
+                 displayWidth, displayHeight,
+                 decodedWidth, decodedHeight);
     }
 
     virtual void render(MediaBuffer *buffer) {
@@ -125,22 +104,13 @@
     virtual ~AwesomeLocalRenderer() {
         delete mTarget;
         mTarget = NULL;
-
-        if (mLibHandle) {
-            dlclose(mLibHandle);
-            mLibHandle = NULL;
-        }
     }
 
 private:
-    VideoRenderer *mTarget;
-    void *mLibHandle;
+    SoftwareRenderer *mTarget;
 
     void init(
-            bool previewOnly,
-            const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
-            const sp<ISurface> &isurface,
             const sp<Surface> &surface,
             size_t displayWidth, size_t displayHeight,
             size_t decodedWidth, size_t decodedHeight);
@@ -150,48 +120,13 @@
 };
 
 void AwesomeLocalRenderer::init(
-        bool previewOnly,
-        const char *componentName,
         OMX_COLOR_FORMATTYPE colorFormat,
-        const sp<ISurface> &isurface,
         const sp<Surface> &surface,
         size_t displayWidth, size_t displayHeight,
         size_t decodedWidth, size_t decodedHeight) {
-    if (!previewOnly) {
-        // We will stick to the vanilla software-color-converting renderer
-        // for "previewOnly" mode, to avoid unneccessarily switching overlays
-        // more often than necessary.
-
-        mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
-
-        if (mLibHandle) {
-            typedef VideoRenderer *(*CreateRendererFunc)(
-                    const sp<ISurface> &surface,
-                    const char *componentName,
-                    OMX_COLOR_FORMATTYPE colorFormat,
-                    size_t displayWidth, size_t displayHeight,
-                    size_t decodedWidth, size_t decodedHeight);
-
-            CreateRendererFunc func =
-                (CreateRendererFunc)dlsym(
-                        mLibHandle,
-                        "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
-                        "OMX_COLOR_FORMATTYPEjjjj");
-
-            if (func) {
-                mTarget =
-                    (*func)(isurface, componentName, colorFormat,
-                        displayWidth, displayHeight,
-                        decodedWidth, decodedHeight);
-            }
-        }
-    }
-
-    if (mTarget == NULL) {
-        mTarget = new SoftwareRenderer(
-                colorFormat, surface, displayWidth, displayHeight,
-                decodedWidth, decodedHeight);
-    }
+    mTarget = new SoftwareRenderer(
+            colorFormat, surface, displayWidth, displayHeight,
+            decodedWidth, decodedHeight);
 }
 
 struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
@@ -294,6 +229,16 @@
 
     mUri = uri;
 
+    if (!strncmp("http://", uri, 7)) {
+        // Hack to support http live.
+
+        size_t len = strlen(uri);
+        if (!strcasecmp(&uri[len - 5], ".m3u8")) {
+            mUri = "httplive://";
+            mUri.append(&uri[7]);
+        }
+    }
+
     if (headers) {
         mUriHeaders = *headers;
     }
@@ -855,54 +800,41 @@
 }
 
 void AwesomePlayer::initRenderer_l() {
-    if (mSurface != NULL || mISurface != NULL) {
-        sp<MetaData> meta = mVideoSource->getFormat();
+    if (mSurface == NULL) {
+        return;
+    }
 
-        int32_t format;
-        const char *component;
-        int32_t decodedWidth, decodedHeight;
-        CHECK(meta->findInt32(kKeyColorFormat, &format));
-        CHECK(meta->findCString(kKeyDecoderComponent, &component));
-        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
-        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
+    sp<MetaData> meta = mVideoSource->getFormat();
 
-        mVideoRenderer.clear();
+    int32_t format;
+    const char *component;
+    int32_t decodedWidth, decodedHeight;
+    CHECK(meta->findInt32(kKeyColorFormat, &format));
+    CHECK(meta->findCString(kKeyDecoderComponent, &component));
+    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
+    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
 
-        // Must ensure that mVideoRenderer's destructor is actually executed
-        // before creating a new one.
-        IPCThreadState::self()->flushCommands();
+    mVideoRenderer.clear();
 
-        if (mSurface != NULL) {
-            if (strncmp(component, "OMX.", 4) == 0) {
-                // Hardware decoders avoid the CPU color conversion by decoding
-                // directly to ANativeBuffers, so we must use a renderer that
-                // just pushes those buffers to the ANativeWindow.
-                mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
-            } else {
-                // Other decoders are instantiated locally and as a consequence
-                // allocate their buffers in local address space.  This renderer
-                // then performs a color conversion and copy to get the data
-                // into the ANativeBuffer.
-                mVideoRenderer = new AwesomeLocalRenderer(
-                    false,  // previewOnly
-                    component,
-                    (OMX_COLOR_FORMATTYPE)format,
-                    mISurface,
-                    mSurface,
-                    mVideoWidth, mVideoHeight,
-                    decodedWidth, decodedHeight);
-            }
-        } else {
-            // Our OMX codecs allocate buffers on the media_server side
-            // therefore they require a remote IOMXRenderer that knows how
-            // to display them.
-            mVideoRenderer = new AwesomeRemoteRenderer(
-                mClient.interface()->createRenderer(
-                        mISurface, component,
-                        (OMX_COLOR_FORMATTYPE)format,
-                        decodedWidth, decodedHeight,
-                        mVideoWidth, mVideoHeight));
-        }
+    // Must ensure that mVideoRenderer's destructor is actually executed
+    // before creating a new one.
+    IPCThreadState::self()->flushCommands();
+
+    if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
+        // Hardware decoders avoid the CPU color conversion by decoding
+        // directly to ANativeBuffers, so we must use a renderer that
+        // just pushes those buffers to the ANativeWindow.
+        mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
+    } else {
+        // Other decoders are instantiated locally and as a consequence
+        // allocate their buffers in local address space.  This renderer
+        // then performs a color conversion and copy to get the data
+        // into the ANativeBuffer.
+        mVideoRenderer = new AwesomeLocalRenderer(
+            (OMX_COLOR_FORMATTYPE)format,
+            mSurface,
+            mVideoWidth, mVideoHeight,
+            decodedWidth, decodedHeight);
     }
 }
 
@@ -946,12 +878,6 @@
     return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
 }
 
-void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
-    Mutex::Autolock autoLock(mLock);
-
-    mISurface = isurface;
-}
-
 void AwesomePlayer::setSurface(const sp<Surface> &surface) {
     Mutex::Autolock autoLock(mLock);
 
@@ -1143,7 +1069,7 @@
             mClient.interface(), mVideoTrack->getFormat(),
             false, // createEncoder
             mVideoTrack,
-            NULL, flags, mSurface);
+            NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
 
     if (mVideoSource != NULL) {
         int64_t durationUs;
@@ -1885,13 +1811,10 @@
 
     mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
 
-    if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
+    if (state->mLastVideoFrame && mSurface != NULL) {
         mVideoRenderer =
             new AwesomeLocalRenderer(
-                    true,  // previewOnly
-                    "",
                     (OMX_COLOR_FORMATTYPE)state->mColorFormat,
-                    mISurface,
                     mSurface,
                     state->mVideoWidth,
                     state->mVideoHeight,
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index b8450fb..d9ff723 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -495,26 +495,6 @@
         mIsMetaDataStoredInVideoBuffers = true;
     }
 
-    /*
-     * mCamera->startRecording() signals camera hal to make
-     * available the video buffers (for instance, allocation
-     * of the video buffers may be triggered when camera hal's
-     * startRecording() method is called). Making available these
-     * video buffers earlier (before calling start()) is critical,
-     * if one wants to configure omx video encoders to use these
-     * buffers for passing video frame data during video recording
-     * without the need to memcpy the video frame data stored
-     * in these buffers. Eliminating memcpy for video frame data
-     * is crucial in performance for HD quality video recording
-     * applications.
-     *
-     * Based on OMX IL spec, configuring the omx video encoders
-     * must occur in loaded state. When start() is called, omx
-     * video encoders are already in idle state, which is too
-     * late. Thus, we must call mCamera->startRecording() earlier.
-     */
-    startCameraRecording();
-
     IPCThreadState::self()->restoreCallingIdentity(token);
 
     int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
@@ -565,8 +545,11 @@
         mStartTimeUs = startTimeUs;
     }
 
+    // Call setListener first before calling startCameraRecording()
+    // to avoid recording frames being dropped.
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
     mCamera->setListener(new CameraSourceListener(this));
+    startCameraRecording();
     IPCThreadState::self()->restoreCallingIdentity(token);
 
     mStarted = true;
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index 7aac447..133f225 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -5,6 +5,7 @@
 #include "include/NuHTTPDataSource.h"
 
 #include <cutils/properties.h>
+#include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaErrors.h>
 
@@ -68,6 +69,9 @@
       mOffset(0),
       mContentLength(0),
       mContentLengthValid(false),
+      mNumBandwidthHistoryItems(0),
+      mTotalTransferTimeUs(0),
+      mTotalTransferBytes(0),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL) {
 }
@@ -189,6 +193,20 @@
             return ERROR_IO;
         }
 
+        {
+            string value;
+            if (mHTTP.find_header_value("Transfer-Encoding", &value)) {
+                // We don't currently support any transfer encodings.
+
+                mState = DISCONNECTED;
+                mHTTP.disconnect();
+
+                LOGE("We don't support '%s' transfer encoding.", value.c_str());
+
+                return ERROR_UNSUPPORTED;
+            }
+        }
+
         applyTimeoutResponse();
 
         if (offset == 0) {
@@ -254,6 +272,8 @@
 
     size_t numBytesRead = 0;
     while (numBytesRead < size) {
+        int64_t startTimeUs = ALooper::GetNowUs();
+
         ssize_t n =
             mHTTP.receive((uint8_t *)data + numBytesRead, size - numBytesRead);
 
@@ -261,6 +281,9 @@
             return n;
         }
 
+        int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+        addBandwidthMeasurement_l(n, delayUs);
+
         numBytesRead += (size_t)n;
 
         if (n == 0) {
@@ -345,6 +368,36 @@
     }
 }
 
+bool NuHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mNumBandwidthHistoryItems < 10) {
+        return false;
+    }
+
+    *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+    return true;
+}
+
+void NuHTTPDataSource::addBandwidthMeasurement_l(
+        size_t numBytes, int64_t delayUs) {
+    BandwidthEntry entry;
+    entry.mDelayUs = delayUs;
+    entry.mNumBytes = numBytes;
+    mTotalTransferTimeUs += delayUs;
+    mTotalTransferBytes += numBytes;
+
+    mBandwidthHistory.push_back(entry);
+    if (++mNumBandwidthHistoryItems > 100) {
+        BandwidthEntry *entry = &*mBandwidthHistory.begin();
+        mTotalTransferTimeUs -= entry->mDelayUs;
+        mTotalTransferBytes -= entry->mNumBytes;
+        mBandwidthHistory.erase(mBandwidthHistory.begin());
+        --mNumBandwidthHistoryItems;
+    }
+}
+
 DecryptHandle* NuHTTPDataSource::DrmInitialization(DrmManagerClient* client) {
     if (client == NULL) {
         return NULL;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8edcd12..5ed4d84 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -54,6 +54,7 @@
 #include <OMX_Component.h>
 
 #include "include/ThreadedSource.h"
+#include "include/avc_utils.h"
 
 namespace android {
 
@@ -264,39 +265,6 @@
     return NULL;
 }
 
-enum {
-    kAVCProfileBaseline      = 0x42,
-    kAVCProfileMain          = 0x4d,
-    kAVCProfileExtended      = 0x58,
-    kAVCProfileHigh          = 0x64,
-    kAVCProfileHigh10        = 0x6e,
-    kAVCProfileHigh422       = 0x7a,
-    kAVCProfileHigh444       = 0xf4,
-    kAVCProfileCAVLC444Intra = 0x2c
-};
-
-static const char *AVCProfileToString(uint8_t profile) {
-    switch (profile) {
-        case kAVCProfileBaseline:
-            return "Baseline";
-        case kAVCProfileMain:
-            return "Main";
-        case kAVCProfileExtended:
-            return "Extended";
-        case kAVCProfileHigh:
-            return "High";
-        case kAVCProfileHigh10:
-            return "High 10";
-        case kAVCProfileHigh422:
-            return "High 422";
-        case kAVCProfileHigh444:
-            return "High 444";
-        case kAVCProfileCAVLC444Intra:
-            return "CAVLC 444 Intra";
-        default:   return "Unknown";
-    }
-}
-
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 478e40c..2fe5e18 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -218,6 +218,28 @@
     return NULL;
 }
 
+const char *AVCProfileToString(uint8_t profile) {
+    switch (profile) {
+        case kAVCProfileBaseline:
+            return "Baseline";
+        case kAVCProfileMain:
+            return "Main";
+        case kAVCProfileExtended:
+            return "Extended";
+        case kAVCProfileHigh:
+            return "High";
+        case kAVCProfileHigh10:
+            return "High 10";
+        case kAVCProfileHigh422:
+            return "High 422";
+        case kAVCProfileHigh444:
+            return "High 444";
+        case kAVCProfileCAVLC444Intra:
+            return "CAVLC 444 Intra";
+        default:   return "Unknown";
+    }
+}
+
 sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
@@ -244,6 +266,10 @@
 
     *out++ = 0x01;  // configurationVersion
     memcpy(out, seqParamSet->data() + 1, 3);  // profile/level...
+
+    uint8_t profile = out[0];
+    uint8_t level = out[2];
+
     out += 3;
     *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
     *out++ = 0xe0 | 1;
@@ -271,7 +297,8 @@
     meta->setInt32(kKeyWidth, width);
     meta->setInt32(kKeyHeight, height);
 
-    LOGI("found AVC codec config (%d x %d)", width, height);
+    LOGI("found AVC codec config (%d x %d, %s-profile level %d.%d)",
+         width, height, AVCProfileToString(profile), level / 10, level % 10);
 
     return meta;
 }
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index df9f107..9524884 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -36,6 +36,7 @@
       mStarted(false),
       mBufferGroup(NULL),
       mInputBuffer(NULL),
+      mInputFrame(NULL),
       mEncoderHandle(NULL),
       mApiHandle(NULL),
       mMemOperator(NULL) {
@@ -45,6 +46,7 @@
     CHECK(mApiHandle == NULL && mEncoderHandle == NULL);
     CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate));
     CHECK(mMeta->findInt32(kKeyChannelCount, &mChannels));
+    CHECK(mChannels <= 2 && mChannels >= 1);
     CHECK(mMeta->findInt32(kKeyBitRate, &mBitRate));
 
     mApiHandle = new VO_AUDIO_CODECAPI;
@@ -145,6 +147,10 @@
     mNumInputSamples = 0;
     mAnchorTimeUs = 0;
     mFrameCount = 0;
+
+    mInputFrame = new int16_t[mChannels * kNumSamplesPerFrame];
+    CHECK(mInputFrame != NULL);
+
     mSource->start(params);
 
     mStarted = true;
@@ -176,6 +182,10 @@
     mApiHandle = NULL;
 
     mStarted = false;
+    if (mInputFrame) {
+        delete[] mInputFrame;
+        mInputFrame = NULL;
+    }
 
     return OK;
 }
@@ -222,7 +232,8 @@
         buffer->meta_data()->setInt32(kKeyIsCodecConfig, false);
     }
 
-    while (mNumInputSamples < kNumSamplesPerFrame) {
+    const int32_t nSamples = mChannels * kNumSamplesPerFrame;
+    while (mNumInputSamples < nSamples) {
         if (mInputBuffer == NULL) {
             if (mSource->read(&mInputBuffer, options) != OK) {
                 if (mNumInputSamples == 0) {
@@ -231,7 +242,7 @@
                 }
                 memset(&mInputFrame[mNumInputSamples],
                        0,
-                       sizeof(int16_t) * (kNumSamplesPerFrame - mNumInputSamples));
+                       sizeof(int16_t) * (nSamples - mNumInputSamples));
                 mNumInputSamples = 0;
                 break;
             }
@@ -250,8 +261,7 @@
         } else {
             readFromSource = false;
         }
-        size_t copy =
-            (kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t);
+        size_t copy = (nSamples - mNumInputSamples) * sizeof(int16_t);
 
         if (copy > mInputBuffer->range_length()) {
             copy = mInputBuffer->range_length();
@@ -271,8 +281,8 @@
             mInputBuffer = NULL;
         }
         mNumInputSamples += copy / sizeof(int16_t);
-        if (mNumInputSamples >= kNumSamplesPerFrame) {
-            mNumInputSamples %= kNumSamplesPerFrame;
+        if (mNumInputSamples >= nSamples) {
+            mNumInputSamples %= nSamples;
             break;
         }
     }
@@ -280,7 +290,7 @@
     VO_CODECBUFFER inputData;
     memset(&inputData, 0, sizeof(inputData));
     inputData.Buffer = (unsigned char*) mInputFrame;
-    inputData.Length = kNumSamplesPerFrame * sizeof(int16_t);
+    inputData.Length = nSamples * sizeof(int16_t);
     CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
 
     VO_CODECBUFFER outputData;
@@ -289,15 +299,21 @@
     memset(&outputInfo, 0, sizeof(outputInfo));
 
     VO_U32 ret = VO_ERR_NONE;
-    outputData.Buffer = outPtr;
-    outputData.Length = buffer->size();
-    ret = mApiHandle->GetOutputData(mEncoderHandle, &outputData, &outputInfo);
-    CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
-    CHECK(outputData.Length != 0);
-    buffer->set_range(0, outputData.Length);
+    size_t nOutputBytes = 0;
+    do {
+        outputData.Buffer = outPtr;
+        outputData.Length = buffer->size() - nOutputBytes;
+        ret = mApiHandle->GetOutputData(mEncoderHandle, &outputData, &outputInfo);
+        if (ret == VO_ERR_NONE) {
+            outPtr += outputData.Length;
+            nOutputBytes += outputData.Length;
+        }
+    } while (ret != VO_ERR_INPUT_BUFFER_SMALL);
+    buffer->set_range(0, nOutputBytes);
 
     int64_t mediaTimeUs =
         ((mFrameCount - 1) * 1000000LL * kNumSamplesPerFrame) / mSampleRate;
+
     buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
     if (readFromSource && wallClockTimeUs != -1) {
         buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index cc7dd4f..3aabf5f 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -9,7 +9,8 @@
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
 	$(TOP)/frameworks/base/include/media/stagefright/openmax \
-        $(TOP)/frameworks/base/media/libstagefright
+        $(TOP)/frameworks/base/media/libstagefright \
+        $(TOP)/external/openssl/include
 
 LOCAL_MODULE:= libstagefright_httplive
 
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 4124571..f9d27eb 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -22,9 +22,14 @@
 #include "include/M3UParser.h"
 #include "include/NuHTTPDataSource.h"
 
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
+
+#include <ctype.h>
+#include <openssl/aes.h>
 
 namespace android {
 
@@ -38,7 +43,9 @@
       mSourceSize(0),
       mOffsetBias(0),
       mSignalDiscontinuity(false),
-      mPrevBandwidthIndex(-1) {
+      mPrevBandwidthIndex(-1),
+      mAESKey((AES_KEY *)malloc(sizeof(AES_KEY))),
+      mStreamEncrypted(false) {
     if (switchToNext()) {
         mInitCheck = OK;
 
@@ -47,6 +54,8 @@
 }
 
 LiveSource::~LiveSource() {
+    free(mAESKey);
+    mAESKey = NULL;
 }
 
 status_t LiveSource::initCheck() const {
@@ -68,7 +77,77 @@
     return (double)rand() / RAND_MAX;
 }
 
-bool LiveSource::loadPlaylist(bool fetchMaster) {
+size_t LiveSource::getBandwidthIndex() {
+    if (mBandwidthItems.size() == 0) {
+        return 0;
+    }
+
+#if 1
+    int32_t bandwidthBps;
+    if (mSource != NULL && mSource->estimateBandwidth(&bandwidthBps)) {
+        LOGI("bandwidth estimated at %.2f kbps", bandwidthBps / 1024.0f);
+    } else {
+        LOGI("no bandwidth estimate.");
+        return 0;  // Pick the lowest bandwidth stream by default.
+    }
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.httplive.max-bw", value, NULL)) {
+        char *end;
+        long maxBw = strtoul(value, &end, 10);
+        if (end > value && *end == '\0') {
+            if (maxBw > 0 && bandwidthBps > maxBw) {
+                LOGV("bandwidth capped to %ld bps", maxBw);
+                bandwidthBps = maxBw;
+            }
+        }
+    }
+
+    // Consider only 80% of the available bandwidth usable.
+    bandwidthBps = (bandwidthBps * 8) / 10;
+
+    // Pick the highest bandwidth stream below or equal to estimated bandwidth.
+
+    size_t index = mBandwidthItems.size() - 1;
+    while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth
+                            > (size_t)bandwidthBps) {
+        --index;
+    }
+#elif 0
+    // Change bandwidth at random()
+    size_t index = uniformRand() * mBandwidthItems.size();
+#elif 0
+    // There's a 50% chance to stay on the current bandwidth and
+    // a 50% chance to switch to the next higher bandwidth (wrapping around
+    // to lowest)
+    const size_t kMinIndex = 0;
+
+    size_t index;
+    if (mPrevBandwidthIndex < 0) {
+        index = kMinIndex;
+    } else if (uniformRand() < 0.5) {
+        index = (size_t)mPrevBandwidthIndex;
+    } else {
+        index = mPrevBandwidthIndex + 1;
+        if (index == mBandwidthItems.size()) {
+            index = kMinIndex;
+        }
+    }
+#elif 0
+    // Pick the highest bandwidth stream below or equal to 1.2 Mbit/sec
+
+    size_t index = mBandwidthItems.size() - 1;
+    while (index > 0 && mBandwidthItems.itemAt(index).mBandwidth > 1200000) {
+        --index;
+    }
+#else
+    size_t index = mBandwidthItems.size() - 1;  // Highest bandwidth stream
+#endif
+
+    return index;
+}
+
+bool LiveSource::loadPlaylist(bool fetchMaster, size_t bandwidthIndex) {
     mSignalDiscontinuity = false;
 
     mPlaylist.clear();
@@ -112,49 +191,35 @@
 
             mBandwidthItems.sort(SortByBandwidth);
 
+#if 1  // XXX
+            if (mBandwidthItems.size() > 1) {
+                // Remove the lowest bandwidth stream, this is sometimes
+                // an AAC program stream, which we don't support at this point.
+                mBandwidthItems.removeItemsAt(0);
+            }
+#endif
+
             for (size_t i = 0; i < mBandwidthItems.size(); ++i) {
                 const BandwidthItem &item = mBandwidthItems.itemAt(i);
                 LOGV("item #%d: %s", i, item.mURI.c_str());
             }
+
+            bandwidthIndex = getBandwidthIndex();
         }
     }
 
     if (mBandwidthItems.size() > 0) {
-#if 0
-        // Change bandwidth at random()
-        size_t index = uniformRand() * mBandwidthItems.size();
-#elif 0
-        // There's a 50% chance to stay on the current bandwidth and
-        // a 50% chance to switch to the next higher bandwidth (wrapping around
-        // to lowest)
-        size_t index;
-        if (uniformRand() < 0.5) {
-            index = mPrevBandwidthIndex < 0 ? 0 : (size_t)mPrevBandwidthIndex;
-        } else {
-            if (mPrevBandwidthIndex < 0) {
-                index = 0;
-            } else {
-                index = mPrevBandwidthIndex + 1;
-                if (index == mBandwidthItems.size()) {
-                    index = 0;
-                }
-            }
-        }
-#else
-        // Stay on the lowest bandwidth available.
-        size_t index = mBandwidthItems.size() - 1;  // Highest bandwidth stream
-#endif
+        mURL = mBandwidthItems.editItemAt(bandwidthIndex).mURI;
 
-        mURL = mBandwidthItems.editItemAt(index).mURI;
-
-        if (mPrevBandwidthIndex >= 0 && (size_t)mPrevBandwidthIndex != index) {
+        if (mPrevBandwidthIndex >= 0
+                && (size_t)mPrevBandwidthIndex != bandwidthIndex) {
             // If we switched streams because of bandwidth changes,
             // we'll signal this discontinuity by inserting a
             // special transport stream packet into the stream.
             mSignalDiscontinuity = true;
         }
 
-        mPrevBandwidthIndex = index;
+        mPrevBandwidthIndex = bandwidthIndex;
     } else {
         mURL = mMasterURL;
     }
@@ -199,18 +264,33 @@
     mOffsetBias += mSourceSize;
     mSourceSize = 0;
 
+    size_t bandwidthIndex = getBandwidthIndex();
+
     if (mLastFetchTimeUs < 0 || getNowUs() >= mLastFetchTimeUs + 15000000ll
-        || mPlaylistIndex == mPlaylist->size()) {
+        || mPlaylistIndex == mPlaylist->size()
+        || (ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
         int32_t nextSequenceNumber =
             mPlaylistIndex + mFirstItemSequenceNumber;
 
-        if (!loadPlaylist(mLastFetchTimeUs < 0)) {
+        if (!loadPlaylist(mLastFetchTimeUs < 0, bandwidthIndex)) {
             LOGE("failed to reload playlist");
             return false;
         }
 
         if (mLastFetchTimeUs < 0) {
-            mPlaylistIndex = 0;
+            if (isSeekable()) {
+                mPlaylistIndex = 0;
+            } else {
+                // This is live streamed content, the first seqnum in the
+                // various bandwidth' streams may be slightly off, so don't
+                // start at the very first entry.
+                // With a segment duration of 6-10secs, this really only
+                // delays playback up to 30secs compared to real time.
+                mPlaylistIndex = 3;
+                if (mPlaylistIndex >= mPlaylist->size()) {
+                    mPlaylistIndex = mPlaylist->size() - 1;
+                }
+            }
         } else {
             if (nextSequenceNumber < mFirstItemSequenceNumber
                     || nextSequenceNumber
@@ -227,6 +307,10 @@
         mLastFetchTimeUs = getNowUs();
     }
 
+    if (!setupCipher()) {
+        return false;
+    }
+
     AString uri;
     sp<AMessage> itemMeta;
     CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri, &itemMeta));
@@ -243,6 +327,121 @@
     }
 
     mPlaylistIndex++;
+
+    return true;
+}
+
+bool LiveSource::setupCipher() {
+    sp<AMessage> itemMeta;
+    bool found = false;
+    AString method;
+
+    for (ssize_t i = mPlaylistIndex; i >= 0; --i) {
+        AString uri;
+        CHECK(mPlaylist->itemAt(i, &uri, &itemMeta));
+
+        if (itemMeta->findString("cipher-method", &method)) {
+            found = true;
+            break;
+        }
+    }
+
+    if (!found) {
+        method = "NONE";
+    }
+
+    mStreamEncrypted = false;
+
+    if (method == "AES-128") {
+        AString keyURI;
+        if (!itemMeta->findString("cipher-uri", &keyURI)) {
+            LOGE("Missing key uri");
+            return false;
+        }
+
+        if (keyURI.size() >= 2
+                && keyURI.c_str()[0] == '"'
+                && keyURI.c_str()[keyURI.size() - 1] == '"') {
+            // Remove surrounding quotes.
+            AString tmp(keyURI, 1, keyURI.size() - 2);
+            keyURI = tmp;
+        }
+
+        ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
+
+        sp<ABuffer> key;
+        if (index >= 0) {
+            key = mAESKeyForURI.valueAt(index);
+        } else {
+            key = new ABuffer(16);
+
+            sp<NuHTTPDataSource> keySource = new NuHTTPDataSource;
+            status_t err = keySource->connect(keyURI.c_str());
+
+            if (err == OK) {
+                size_t offset = 0;
+                while (offset < 16) {
+                    ssize_t n = keySource->readAt(
+                            offset, key->data() + offset, 16 - offset);
+                    if (n <= 0) {
+                        err = ERROR_IO;
+                        break;
+                    }
+
+                    offset += n;
+                }
+            }
+
+            if (err != OK) {
+                LOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
+                return false;
+            }
+
+            mAESKeyForURI.add(keyURI, key);
+        }
+
+        if (AES_set_decrypt_key(key->data(), 128, (AES_KEY *)mAESKey) != 0) {
+            LOGE("failed to set AES decryption key.");
+            return false;
+        }
+
+        AString iv;
+        if (itemMeta->findString("cipher-iv", &iv)) {
+            if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
+                    || iv.size() != 16 * 2 + 2) {
+                LOGE("malformed cipher IV '%s'.", iv.c_str());
+                return false;
+            }
+
+            memset(mAESIVec, 0, sizeof(mAESIVec));
+            for (size_t i = 0; i < 16; ++i) {
+                char c1 = tolower(iv.c_str()[2 + 2 * i]);
+                char c2 = tolower(iv.c_str()[3 + 2 * i]);
+                if (!isxdigit(c1) || !isxdigit(c2)) {
+                    LOGE("malformed cipher IV '%s'.", iv.c_str());
+                    return false;
+                }
+                uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
+                uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
+
+                mAESIVec[i] = nibble1 << 4 | nibble2;
+            }
+        } else {
+            size_t seqNum = mPlaylistIndex + mFirstItemSequenceNumber;
+
+            memset(mAESIVec, 0, sizeof(mAESIVec));
+            mAESIVec[15] = seqNum & 0xff;
+            mAESIVec[14] = (seqNum >> 8) & 0xff;
+            mAESIVec[13] = (seqNum >> 16) & 0xff;
+            mAESIVec[12] = (seqNum >> 24) & 0xff;
+        }
+
+        mStreamEncrypted = true;
+    } else if (!(method == "NONE")) {
+        LOGE("Unsupported cipher method '%s'", method.c_str());
+        return false;
+    }
+
     return true;
 }
 
@@ -279,6 +478,7 @@
         return avail;
     }
 
+    bool done = false;
     size_t numRead = 0;
     while (numRead < size) {
         ssize_t n = mSource->readAt(
@@ -289,7 +489,44 @@
             break;
         }
 
+        if (mStreamEncrypted) {
+            size_t nmod = n % 16;
+            CHECK(nmod == 0);
+
+            sp<ABuffer> tmp = new ABuffer(n);
+
+            AES_cbc_encrypt((const unsigned char *)data + numRead,
+                            tmp->data(),
+                            n,
+                            (const AES_KEY *)mAESKey,
+                            mAESIVec,
+                            AES_DECRYPT);
+
+            if (mSourceSize == (off_t)(offset + numRead - delta + n)) {
+                // check for padding at the end of the file.
+
+                size_t pad = tmp->data()[n - 1];
+                CHECK_GT(pad, 0u);
+                CHECK_LE(pad, 16u);
+                CHECK_GE((size_t)n, pad);
+                for (size_t i = 0; i < pad; ++i) {
+                    CHECK_EQ((unsigned)tmp->data()[n - 1 - i], pad);
+                }
+
+                n -= pad;
+                mSourceSize -= pad;
+
+                done = true;
+            }
+
+            memcpy((uint8_t *)data + numRead, tmp->data(), n);
+        }
+
         numRead += n;
+
+        if (done) {
+            break;
+        }
     }
 
     return numRead;
@@ -359,19 +596,17 @@
         return false;
     }
 
-    size_t newPlaylistIndex = mFirstItemSequenceNumber + index;
-
-    if (newPlaylistIndex == mPlaylistIndex) {
+    if (index == mPlaylistIndex) {
         return false;
     }
 
-    mPlaylistIndex = newPlaylistIndex;
+    mPlaylistIndex = index;
+
+    LOGV("seeking to index %lld", index);
 
     switchToNext();
     mOffsetBias = 0;
 
-    LOGV("seeking to index %lld", index);
-
     return true;
 }
 
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 90f3d6d..b166cc3 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -158,6 +158,11 @@
                     return ERROR_MALFORMED;
                 }
                 err = parseMetaData(line, &mMeta, "media-sequence");
+            } else if (line.startsWith("#EXT-X-KEY")) {
+                if (mIsVariantPlaylist) {
+                    return ERROR_MALFORMED;
+                }
+                err = parseCipherInfo(line, &itemMeta);
             } else if (line.startsWith("#EXT-X-ENDLIST")) {
                 mIsComplete = true;
             } else if (line.startsWith("#EXTINF")) {
@@ -292,6 +297,57 @@
 }
 
 // static
+status_t M3UParser::parseCipherInfo(
+        const AString &line, sp<AMessage> *meta) {
+    ssize_t colonPos = line.find(":");
+
+    if (colonPos < 0) {
+        return ERROR_MALFORMED;
+    }
+
+    size_t offset = colonPos + 1;
+
+    while (offset < line.size()) {
+        ssize_t end = line.find(",", offset);
+        if (end < 0) {
+            end = line.size();
+        }
+
+        AString attr(line, offset, end - offset);
+        attr.trim();
+
+        offset = end + 1;
+
+        ssize_t equalPos = attr.find("=");
+        if (equalPos < 0) {
+            continue;
+        }
+
+        AString key(attr, 0, equalPos);
+        key.trim();
+
+        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
+        val.trim();
+
+        LOGV("key=%s value=%s", key.c_str(), val.c_str());
+
+        key.tolower();
+
+        if (key == "method" || key == "uri" || key == "iv") {
+            if (meta->get() == NULL) {
+                *meta = new AMessage;
+            }
+
+            key.insert(AString("cipher-"), 0);
+
+            (*meta)->setString(key.c_str(), val.c_str(), val.size());
+        }
+    }
+
+    return OK;
+}
+
+// static
 status_t M3UParser::ParseInt32(const char *s, int32_t *x) {
     char *end;
     long lval = strtol(s, &end, 10);
diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h
index ecc533f..3d5fc60 100644
--- a/media/libstagefright/include/AACEncoder.h
+++ b/media/libstagefright/include/AACEncoder.h
@@ -60,7 +60,7 @@
             kNumSamplesPerFrame = 1024,
         };
 
-        int16_t           mInputFrame[kNumSamplesPerFrame];
+        int16_t           *mInputFrame;
 
         uint8_t           mAudioSpecificConfigData[2]; // auido specific data
         void             *mEncoderHandle;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 302a1ba..4e63b7a 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -79,7 +79,6 @@
 
     bool isPlaying() const;
 
-    void setISurface(const sp<ISurface> &isurface);
     void setSurface(const sp<Surface> &surface);
     void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
     status_t setLooping(bool shouldLoop);
@@ -130,7 +129,6 @@
     bool mQueueStarted;
     wp<MediaPlayerBase> mListener;
 
-    sp<ISurface> mISurface;
     sp<Surface> mSurface;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
diff --git a/media/libstagefright/include/LiveSource.h b/media/libstagefright/include/LiveSource.h
index 55dd45e..7ba1f44 100644
--- a/media/libstagefright/include/LiveSource.h
+++ b/media/libstagefright/include/LiveSource.h
@@ -21,6 +21,7 @@
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/DataSource.h>
+#include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -72,14 +73,23 @@
     bool mSignalDiscontinuity;
     ssize_t mPrevBandwidthIndex;
 
+    void *mAESKey;
+    unsigned char mAESIVec[16];
+    bool mStreamEncrypted;
+
+    KeyedVector<AString, sp<ABuffer> > mAESKeyForURI;
+
     status_t fetchM3U(const char *url, sp<ABuffer> *buffer);
 
     static int SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b);
 
     bool switchToNext();
-    bool loadPlaylist(bool fetchMaster);
+    bool loadPlaylist(bool fetchMaster, size_t bandwidthIndex);
     void determineSeekability();
 
+    size_t getBandwidthIndex();
+    bool setupCipher();
+
     DISALLOW_EVIL_CONSTRUCTORS(LiveSource);
 };
 
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index bd9eebe..531d184 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -66,6 +66,9 @@
     static status_t parseStreamInf(
             const AString &line, sp<AMessage> *meta);
 
+    static status_t parseCipherInfo(
+            const AString &line, sp<AMessage> *meta);
+
     static status_t ParseInt32(const char *s, int32_t *x);
 
     DISALLOW_EVIL_CONSTRUCTORS(M3UParser);
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 93b7a76..c707fdc 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -3,6 +3,7 @@
 #define NU_HTTP_DATA_SOURCE_H_
 
 #include <media/stagefright/DataSource.h>
+#include <utils/List.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
@@ -26,6 +27,10 @@
     virtual status_t getSize(off_t *size);
     virtual uint32_t flags();
 
+    // Returns true if bandwidth could successfully be estimated,
+    // false otherwise.
+    bool estimateBandwidth(int32_t *bandwidth_bps);
+
     virtual DecryptHandle* DrmInitialization(DrmManagerClient *client);
     virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
 
@@ -39,6 +44,11 @@
         CONNECTED
     };
 
+    struct BandwidthEntry {
+        int64_t mDelayUs;
+        size_t mNumBytes;
+    };
+
     Mutex mLock;
 
     State mState;
@@ -54,6 +64,11 @@
     off_t mContentLength;
     bool mContentLengthValid;
 
+    List<BandwidthEntry> mBandwidthHistory;
+    size_t mNumBandwidthHistoryItems;
+    int64_t mTotalTransferTimeUs;
+    size_t mTotalTransferBytes;
+
     DecryptHandle *mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
@@ -66,6 +81,7 @@
             off_t offset);
 
     void applyTimeoutResponse();
+    void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
 
     static void MakeFullHeaders(
             const KeyedVector<String8, String8> *overrides,
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 5a6c96f9..5fed98a 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -97,13 +97,6 @@
             const char *parameter_name,
             OMX_INDEXTYPE *index);
 
-    virtual sp<IOMXRenderer> createRenderer(
-            const sp<ISurface> &surface,
-            const char *componentName,
-            OMX_COLOR_FORMATTYPE colorFormat,
-            size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
-
     virtual void binderDied(const wp<IBinder> &the_late_who);
 
     OMX_ERRORTYPE OnEvent(
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 8d58056..198bfd6 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -19,15 +19,13 @@
 #define SOFTWARE_RENDERER_H_
 
 #include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/VideoRenderer.h>
 #include <utils/RefBase.h>
 
 namespace android {
 
 class Surface;
-class MemoryHeapBase;
 
-class SoftwareRenderer : public VideoRenderer {
+class SoftwareRenderer {
 public:
     SoftwareRenderer(
             OMX_COLOR_FORMATTYPE colorFormat,
@@ -35,9 +33,9 @@
             size_t displayWidth, size_t displayHeight,
             size_t decodedWidth, size_t decodedHeight);
 
-    virtual ~SoftwareRenderer();
+    ~SoftwareRenderer();
 
-    virtual void render(
+    void render(
             const void *data, size_t size, void *platformPrivate);
 
 private:
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index 62cfc36..3aeb07f 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -24,6 +24,17 @@
 
 struct ABitReader;
 
+enum {
+    kAVCProfileBaseline      = 0x42,
+    kAVCProfileMain          = 0x4d,
+    kAVCProfileExtended      = 0x58,
+    kAVCProfileHigh          = 0x64,
+    kAVCProfileHigh10        = 0x6e,
+    kAVCProfileHigh422       = 0x7a,
+    kAVCProfileHigh444       = 0xf4,
+    kAVCProfileCAVLC444Intra = 0x2c
+};
+
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
 
@@ -39,6 +50,8 @@
 
 bool IsIDR(const sp<ABuffer> &accessUnit);
 
+const char *AVCProfileToString(uint8_t profile);
+
 }  // namespace android
 
 #endif  // AVC_UTILS_H_
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index d16476d..a40c0a3 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -22,13 +22,15 @@
 
 #include "mkvparser.hpp"
 
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -81,46 +83,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-#include <ctype.h>
-static void hexdump(const void *_data, size_t size) {
-    const uint8_t *data = (const uint8_t *)_data;
-    size_t offset = 0;
-    while (offset < size) {
-        printf("0x%04x  ", offset);
-
-        size_t n = size - offset;
-        if (n > 16) {
-            n = 16;
-        }
-
-        for (size_t i = 0; i < 16; ++i) {
-            if (i == 8) {
-                printf(" ");
-            }
-
-            if (offset + i < size) {
-                printf("%02x ", data[offset + i]);
-            } else {
-                printf("   ");
-            }
-        }
-
-        printf(" ");
-
-        for (size_t i = 0; i < n; ++i) {
-            if (isprint(data[offset + i])) {
-                printf("%c", data[offset + i]);
-            } else {
-                printf(".");
-            }
-        }
-
-        printf("\n");
-
-        offset += 16;
-    }
-}
-
 struct BlockIterator {
     BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
 
@@ -167,6 +129,7 @@
     size_t mTrackIndex;
     Type mType;
     BlockIterator mBlockIter;
+    size_t mNALSizeLen;  // for type AVC
 
     status_t advance();
 
@@ -180,13 +143,26 @@
       mTrackIndex(index),
       mType(OTHER),
       mBlockIter(mExtractor->mSegment,
-                 mExtractor->mTracks.itemAt(index).mTrackNum) {
+                 mExtractor->mTracks.itemAt(index).mTrackNum),
+      mNALSizeLen(0) {
+    sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
+
     const char *mime;
-    CHECK(mExtractor->mTracks.itemAt(index).mMeta->
-            findCString(kKeyMIMEType, &mime));
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         mType = AVC;
+
+        uint32_t dummy;
+        const uint8_t *avcc;
+        size_t avccSize;
+        CHECK(meta->findData(
+                    kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
+
+        CHECK_GE(avccSize, 5u);
+
+        mNALSizeLen = 1 + (avcc[4] & 3);
+        LOGV("mNALSizeLen = %d", mNALSizeLen);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
     }
@@ -276,6 +252,10 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+static unsigned U24_AT(const uint8_t *ptr) {
+    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+}
+
 status_t MatroskaSource::read(
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
@@ -286,6 +266,7 @@
         mBlockIter.seek(seekTimeUs);
     }
 
+again:
     if (mBlockIter.eos()) {
         return ERROR_END_OF_STREAM;
     }
@@ -294,38 +275,70 @@
     size_t size = block->GetSize();
     int64_t timeUs = mBlockIter.blockTimeUs();
 
-    MediaBuffer *buffer = new MediaBuffer(size + 2);
+    // In the case of AVC content, each NAL unit is prefixed by
+    // mNALSizeLen bytes of length. We want to prefix the data with
+    // a four-byte 0x00000001 startcode instead of the length prefix.
+    // mNALSizeLen ranges from 1 through 4 bytes, so add an extra
+    // 3 bytes of padding to the buffer start.
+    static const size_t kPadding = 3;
+
+    MediaBuffer *buffer = new MediaBuffer(size + kPadding);
     buffer->meta_data()->setInt64(kKeyTime, timeUs);
     buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
     long res = block->Read(
-            mExtractor->mReader, (unsigned char *)buffer->data() + 2);
+            mExtractor->mReader, (unsigned char *)buffer->data() + kPadding);
 
     if (res != 0) {
         return ERROR_END_OF_STREAM;
     }
 
-    buffer->set_range(2, size);
+    buffer->set_range(kPadding, size);
 
     if (mType == AVC) {
-        CHECK(size >= 2);
+        CHECK_GE(size, mNALSizeLen);
 
         uint8_t *data = (uint8_t *)buffer->data();
 
-        unsigned NALsize = data[2] << 8 | data[3];
-        CHECK_EQ(size, NALsize + 2);
+        size_t NALsize;
+        switch (mNALSizeLen) {
+            case 1: NALsize = data[kPadding]; break;
+            case 2: NALsize = U16_AT(&data[kPadding]); break;
+            case 3: NALsize = U24_AT(&data[kPadding]); break;
+            case 4: NALsize = U32_AT(&data[kPadding]); break;
+            default:
+                TRESPASS();
+        }
 
-        memcpy(data, "\x00\x00\x00\x01", 4);
-        buffer->set_range(0, size + 2);
+        CHECK_GE(size, NALsize + mNALSizeLen);
+        if (size > NALsize + mNALSizeLen) {
+            LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen);
+        }
+
+        // actual data starts at &data[kPadding + mNALSizeLen]
+
+        memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
+        buffer->set_range(mNALSizeLen - 1, NALsize + 4);
     } else if (mType == AAC) {
         // There's strange junk at the beginning...
 
-        const uint8_t *data = (const uint8_t *)buffer->data() + 2;
+        const uint8_t *data = (const uint8_t *)buffer->data() + kPadding;
+
+        // hexdump(data, size);
+
         size_t offset = 0;
         while (offset < size && data[offset] != 0x21) {
             ++offset;
         }
-        buffer->set_range(2 + offset, size - offset);
+
+        if (size == offset) {
+            buffer->release();
+
+            mBlockIter.advance();
+            goto again;
+        }
+
+        buffer->set_range(kPadding + offset, size - offset);
     }
 
     *out = buffer;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index c88c6c1..f06a1bb 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -274,6 +274,8 @@
       mQueue(streamType == 0x1b
               ? ElementaryStreamQueue::H264 : ElementaryStreamQueue::AAC) {
     mBuffer->setRange(0, 0);
+
+    LOGV("new stream PID 0x%02x, type 0x%02x", elementaryPID, streamType);
 }
 
 ATSParser::Stream::~Stream() {
@@ -307,7 +309,8 @@
 }
 
 void ATSParser::Stream::signalDiscontinuity(bool isASeek) {
-    LOGV("Stream discontinuity");
+    isASeek = false;  // Always signal a "real" discontinuity
+
     mPayloadStarted = false;
     mBuffer->setRange(0, 0);
 
@@ -317,7 +320,9 @@
         // This is only a "minor" discontinuity, we stay within the same
         // bitstream.
 
-        mSource->clear();
+        if (mSource != NULL) {
+            mSource->clear();
+        }
         return;
     }
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index b0b9e66..f11b3c3 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -41,7 +41,10 @@
 }
 
 void ElementaryStreamQueue::clear() {
-    mBuffer->setRange(0, 0);
+    if (mBuffer != NULL) {
+        mBuffer->setRange(0, 0);
+    }
+
     mTimestamps.clear();
     mFormat.clear();
 }
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index f9f638f..4e9920b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -24,14 +24,11 @@
 #include <sys/resource.h>
 
 #include "../include/OMX.h"
-#include "OMXRenderer.h"
 
 #include "../include/OMXNodeInstance.h"
-#include "../include/SoftwareRenderer.h"
 
 #include <binder/IMemory.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/VideoRenderer.h>
 #include <utils/threads.h>
 
 #include "OMXMaster.h"
@@ -442,110 +439,4 @@
     mNodeIDToInstance.removeItem(node);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-struct SharedVideoRenderer : public VideoRenderer {
-    SharedVideoRenderer(void *libHandle, VideoRenderer *obj)
-        : mLibHandle(libHandle),
-          mObj(obj) {
-    }
-
-    virtual ~SharedVideoRenderer() {
-        delete mObj;
-        mObj = NULL;
-
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
-    }
-
-    virtual void render(
-            const void *data, size_t size, void *platformPrivate) {
-        return mObj->render(data, size, platformPrivate);
-    }
-
-private:
-    void *mLibHandle;
-    VideoRenderer *mObj;
-
-    SharedVideoRenderer(const SharedVideoRenderer &);
-    SharedVideoRenderer &operator=(const SharedVideoRenderer &);
-};
-
-sp<IOMXRenderer> OMX::createRenderer(
-        const sp<ISurface> &surface,
-        const char *componentName,
-        OMX_COLOR_FORMATTYPE colorFormat,
-        size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
-    Mutex::Autolock autoLock(mLock);
-
-    VideoRenderer *impl = NULL;
-
-    void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
-
-    if (libHandle) {
-        typedef VideoRenderer *(*CreateRendererFunc)(
-                const sp<ISurface> &surface,
-                const char *componentName,
-                OMX_COLOR_FORMATTYPE colorFormat,
-                size_t displayWidth, size_t displayHeight,
-                size_t decodedWidth, size_t decodedHeight);
-
-        CreateRendererFunc func =
-            (CreateRendererFunc)dlsym(
-                    libHandle,
-                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
-                    "OMX_COLOR_FORMATTYPEjjjj");
-
-        if (func) {
-            impl = (*func)(surface, componentName, colorFormat,
-                    displayWidth, displayHeight, encodedWidth, encodedHeight);
-
-            if (impl) {
-                impl = new SharedVideoRenderer(libHandle, impl);
-                libHandle = NULL;
-            }
-        }
-
-        if (libHandle) {
-            dlclose(libHandle);
-            libHandle = NULL;
-        }
-    }
-
-    if (!impl) {
-#if 0
-        LOGW("Using software renderer.");
-        impl = new SoftwareRenderer(
-                colorFormat,
-                surface,
-                displayWidth, displayHeight,
-                encodedWidth, encodedHeight);
-#else
-        CHECK(!"Should not be here.");
-        return NULL;
-#endif
-    }
-
-    return new OMXRenderer(impl);
-}
-
-OMXRenderer::OMXRenderer(VideoRenderer *impl)
-    : mImpl(impl) {
-}
-
-OMXRenderer::~OMXRenderer() {
-    delete mImpl;
-    mImpl = NULL;
-}
-
-void OMXRenderer::render(IOMX::buffer_id buffer) {
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
-
-    mImpl->render(
-            header->pBuffer + header->nOffset,
-            header->nFilledLen,
-            header->pPlatformPrivate);
-}
-
 }  // namespace android
diff --git a/media/libstagefright/omx/OMXRenderer.h b/media/libstagefright/omx/OMXRenderer.h
deleted file mode 100644
index 4d194ce..0000000
--- a/media/libstagefright/omx/OMXRenderer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#ifndef OMX_RENDERER_H_
-
-#define OMX_RENDERER_H_
-
-#include <media/IOMX.h>
-
-namespace android {
-
-class VideoRenderer;
-
-class OMXRenderer : public BnOMXRenderer {
-public:
-    // Assumes ownership of "impl".
-    OMXRenderer(VideoRenderer *impl);
-    virtual ~OMXRenderer();
-
-    virtual void render(IOMX::buffer_id buffer);
-
-private:
-    VideoRenderer *mImpl;
-
-    OMXRenderer(const OMXRenderer &);
-    OMXRenderer &operator=(const OMXRenderer &);
-};
-
-}  // namespace android
-
-#endif  // OMX_RENDERER_H_
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index c8cb016..fafd221 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -75,6 +75,12 @@
 
     virtual MtpResponseCode         resetDeviceProperty(MtpDeviceProperty property) = 0;
 
+    virtual MtpResponseCode         getObjectPropertyList(MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            MtpObjectProperty property,
+                                            int groupCode, int depth,
+                                            MtpDataPacket& packet) = 0;
+
     virtual MtpResponseCode         getObjectInfo(MtpObjectHandle handle,
                                             MtpDataPacket& packet) = 0;
 
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 3416807..1668ecf 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -56,6 +56,10 @@
     { "MTP_OPERATION_GET_OBJECT_PROP_DESC",         0x9802 },
     { "MTP_OPERATION_GET_OBJECT_PROP_VALUE",        0x9803 },
     { "MTP_OPERATION_SET_OBJECT_PROP_VALUE",        0x9804 },
+    { "MTP_OPERATION_GET_OBJECT_PROP_LIST",         0x9805 },
+    { "MTP_OPERATION_SET_OBJECT_PROP_LIST",         0x9806 },
+    { "MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC", 0x9807 },
+    { "MTP_OPERATION_SEND_OBJECT_PROP_LIST",        0x9808 },
     { "MTP_OPERATION_GET_OBJECT_REFERENCES",        0x9810 },
     { "MTP_OPERATION_SET_OBJECT_REFERENCES",        0x9811 },
     { "MTP_OPERATION_SKIP",                         0x9820 },
@@ -371,15 +375,21 @@
     return getCodeName(code, sOperationCodes);
 }
 
-const char* MtpDebug::getFormatCodeName(MtpOperationCode code) {
+const char* MtpDebug::getFormatCodeName(MtpObjectFormat code) {
+    if (code == 0)
+        return "NONE";
     return getCodeName(code, sFormatCodes);
 }
 
 const char* MtpDebug::getObjectPropCodeName(MtpPropertyCode code) {
+    if (code == 0)
+        return "NONE";
     return getCodeName(code, sObjectPropCodes);
 }
 
 const char* MtpDebug::getDevicePropCodeName(MtpPropertyCode code) {
+    if (code == 0)
+        return "NONE";
     return getCodeName(code, sDevicePropCodes);
 }
 
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index f7c12d6..86889c3 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -53,7 +53,7 @@
         mDefaultArrayValues(NULL),
         mCurrentArrayLength(0),
         mCurrentArrayValues(NULL),
-        mGroupCode(0),
+        mGroupCode(-1), // disable multiple properties in GetObjectPropList for now
         mFormFlag(kFormNone),
         mEnumLength(0),
         mEnumValues(NULL)
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 5ba6be9..6cf70ec 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -72,6 +72,10 @@
     MTP_OPERATION_GET_OBJECT_PROP_DESC,
     MTP_OPERATION_GET_OBJECT_PROP_VALUE,
     MTP_OPERATION_SET_OBJECT_PROP_VALUE,
+    MTP_OPERATION_GET_OBJECT_PROP_LIST,
+//    MTP_OPERATION_SET_OBJECT_PROP_LIST,
+//    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
+//    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
     MTP_OPERATION_GET_OBJECT_REFERENCES,
     MTP_OPERATION_SET_OBJECT_REFERENCES,
 //    MTP_OPERATION_SKIP,
@@ -276,6 +280,9 @@
         case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
             response = doResetDevicePropValue();
             break;
+        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
+            response = doGetObjectPropList();
+            break;
         case MTP_OPERATION_GET_OBJECT_INFO:
             response = doGetObjectInfo();
             break;
@@ -523,6 +530,20 @@
     return mDatabase->resetDeviceProperty(property);
 }
 
+MtpResponseCode MtpServer::doGetObjectPropList() {
+
+    MtpObjectHandle handle = mRequest.getParameter(1);
+    MtpObjectFormat format = mRequest.getParameter(2);
+    MtpDeviceProperty property = mRequest.getParameter(3);
+    int groupCode = mRequest.getParameter(4);
+    int depth = mRequest.getParameter(4);
+   LOGD("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
+            handle, MtpDebug::getFormatCodeName(format),
+            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
+
+    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
+}
+
 MtpResponseCode MtpServer::doGetObjectInfo() {
     MtpObjectHandle handle = mRequest.getParameter(1);
     return mDatabase->getObjectInfo(handle, mData);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 68a6564..e65ddb0 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -93,6 +93,7 @@
     MtpResponseCode     doGetDevicePropValue();
     MtpResponseCode     doSetDevicePropValue();
     MtpResponseCode     doResetDevicePropValue();
+    MtpResponseCode     doGetObjectPropList();
     MtpResponseCode     doGetObjectInfo();
     MtpResponseCode     doGetObject();
     MtpResponseCode     doSendObjectInfo();
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index b7afa66..8bc2e22 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,7 +37,7 @@
 #define MTP_CONTAINER_PARAMETER_OFFSET          12
 #define MTP_CONTAINER_HEADER_SIZE               12
 
-// MTP Types
+// MTP Data Types
 #define MTP_TYPE_UNDEFINED      0x0000          // Undefined
 #define MTP_TYPE_INT8           0x0001          // Signed 8-bit integer
 #define MTP_TYPE_UINT8          0x0002          // Unsigned 8-bit integer
@@ -383,6 +383,10 @@
 #define MTP_OPERATION_GET_OBJECT_PROP_DESC                  0x9802
 #define MTP_OPERATION_GET_OBJECT_PROP_VALUE                 0x9803
 #define MTP_OPERATION_SET_OBJECT_PROP_VALUE                 0x9804
+#define MTP_OPERATION_GET_OBJECT_PROP_LIST                  0x9805
+#define MTP_OPERATION_SET_OBJECT_PROP_LIST                  0x9806
+#define MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC          0x9807
+#define MTP_OPERATION_SEND_OBJECT_PROP_LIST                 0x9808
 #define MTP_OPERATION_GET_OBJECT_REFERENCES                 0x9810
 #define MTP_OPERATION_SET_OBJECT_REFERENCES                 0x9811
 #define MTP_OPERATION_SKIP                                  0x9820
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index 0132ae8..95b7386 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -64,7 +64,7 @@
 
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         try {
-            assertTrue(MediaFrameworkTest.checkStreamingServer());
+            //assertTrue(MediaFrameworkTest.checkStreamingServer());
             for (int i = 0; i < NUMBER_OF_STRESS_LOOPS; i++) {
                 MediaPlayer mp = new MediaPlayer();
                 mp.setDataSource(MediaNames.STREAM_H264_480_360_1411k);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStateUnitTestTemplate.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStateUnitTestTemplate.java
index 6abfbb2..f8e8f98 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStateUnitTestTemplate.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStateUnitTestTemplate.java
@@ -39,7 +39,7 @@
  */
 class MediaPlayerStateUnitTestTemplate extends AndroidTestCase {
     private static final String TEST_PATH = MediaNames.TEST_PATH_1;
-    private static final String TAG = "MediaPlayerSeekToStateUnitTest";
+    private static final String TAG = "MediaPlayerStateUnitTestTemplate";
     private static final int SEEK_TO_END  = 135110;  // Milliseconds.
     private static int WAIT_FOR_COMMAND_TO_COMPLETE = 1000;  // Milliseconds.
     
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index 53308be..1e3731e 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -68,7 +68,6 @@
     }
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
-    virtual status_t    setVideoISurface(const sp<ISurface>& surface) {return OK;}
     virtual status_t    setVideoSurface(const sp<Surface>& surface) {return OK;}
     virtual status_t    prepare() {return OK;}
     virtual status_t    prepareAsync() {return OK;}
diff --git a/packages/SystemUI/res/anim/navigation_out.xml b/packages/SystemUI/res/anim/navigation_out.xml
deleted file mode 100644
index 4717e47..0000000
--- a/packages/SystemUI/res/anim/navigation_out.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_0.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_0.png
deleted file mode 100644
index 35b765f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_10.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_10.png
deleted file mode 100644
index 39eeb06..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_10.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_100.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_100.png
deleted file mode 100644
index b5787aa..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_20.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_20.png
deleted file mode 100644
index 3fc2852..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_20.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_30.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_30.png
deleted file mode 100644
index 6ba6da3..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_30.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_40.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_40.png
deleted file mode 100644
index f5ac131..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_40.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_50.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_50.png
deleted file mode 100644
index fffb701..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_50.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_60.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_60.png
deleted file mode 100644
index 7b4fa44..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_60.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_70.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_70.png
deleted file mode 100644
index 3c9eeb1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_70.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_80.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_80.png
deleted file mode 100644
index 3945188..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_80.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_90.png b/packages/SystemUI/res/drawable-hdpi/sysbar_battery_90.png
deleted file mode 100644
index 8a9241c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_battery_90.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_100.png b/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_100.png
deleted file mode 100644
index 67591fe..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_red.png b/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_red.png
deleted file mode 100644
index 697044b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_batterymini_red.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/sysbar_signalmini_100.png b/packages/SystemUI/res/drawable-hdpi/sysbar_signalmini_100.png
deleted file mode 100644
index 8bec533..0000000
--- a/packages/SystemUI/res/drawable-hdpi/sysbar_signalmini_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png
new file mode 100644
index 0000000..4434b5c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_0.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_0.png
deleted file mode 100644
index ff75a51..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_10.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_10.png
deleted file mode 100644
index 66ab4c6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_10.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_100.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_100.png
deleted file mode 100644
index 3b50500..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_20.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_20.png
deleted file mode 100644
index 9119065..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_20.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_30.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_30.png
deleted file mode 100644
index 296f19f26b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_30.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_40.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_40.png
deleted file mode 100644
index 9daab23..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_40.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_50.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_50.png
deleted file mode 100644
index 62d24c4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_50.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_60.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_60.png
deleted file mode 100644
index eea927a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_60.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_70.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_70.png
deleted file mode 100644
index 6816088..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_70.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_80.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_80.png
deleted file mode 100644
index b7dd9bb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_80.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_90.png b/packages/SystemUI/res/drawable-mdpi/sysbar_battery_90.png
deleted file mode 100644
index 6e36f53..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_battery_90.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_100.png b/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_100.png
deleted file mode 100644
index 8eb0f29..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_red.png b/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_red.png
deleted file mode 100644
index adcc6b9..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_batterymini_red.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_0.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_0.png
deleted file mode 100644
index 7469372..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_10.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_10.png
deleted file mode 100644
index 6625d9a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_10.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_100.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_100.png
deleted file mode 100644
index b2e763b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_100.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_20.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_20.png
deleted file mode 100644
index fb66362..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_20.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_30.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_30.png
deleted file mode 100644
index a87d94e..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_30.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_40.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_40.png
deleted file mode 100644
index 8e229d5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_40.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_50.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_50.png
deleted file mode 100644
index fe989d4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_50.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_60.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_60.png
deleted file mode 100644
index aac57dc..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_60.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_70.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_70.png
deleted file mode 100644
index 2281968..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_70.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_80.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_80.png
deleted file mode 100644
index 7177ae1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_80.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_90.png b/packages/SystemUI/res/drawable-mdpi/sysbar_signal_90.png
deleted file mode 100644
index 7f60480..0000000
--- a/packages/SystemUI/res/drawable-mdpi/sysbar_signal_90.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/sysbar_battery.xml b/packages/SystemUI/res/drawable/sysbar_battery.xml
deleted file mode 100644
index 9551bf0..0000000
--- a/packages/SystemUI/res/drawable/sysbar_battery.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="01" android:drawable="@drawable/sysbar_battery_0" />
-    <item android:maxLevel="10" android:drawable="@drawable/sysbar_battery_10" />
-    <item android:maxLevel="20" android:drawable="@drawable/sysbar_battery_20" />
-    <item android:maxLevel="30" android:drawable="@drawable/sysbar_battery_30" />
-    <item android:maxLevel="40" android:drawable="@drawable/sysbar_battery_40" />
-    <item android:maxLevel="50" android:drawable="@drawable/sysbar_battery_50" />
-    <item android:maxLevel="60" android:drawable="@drawable/sysbar_battery_60" />
-    <item android:maxLevel="70" android:drawable="@drawable/sysbar_battery_70" />
-    <item android:maxLevel="80" android:drawable="@drawable/sysbar_battery_80" />
-    <item android:maxLevel="90" android:drawable="@drawable/sysbar_battery_90" />
-    <item android:maxLevel="101" android:drawable="@drawable/sysbar_battery_100" />
-</level-list>
diff --git a/packages/SystemUI/res/drawable/sysbar_batterymini.xml b/packages/SystemUI/res/drawable/sysbar_batterymini.xml
deleted file mode 100644
index c7300e6..0000000
--- a/packages/SystemUI/res/drawable/sysbar_batterymini.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<clip xmlns:android="http://schemas.android.com/apk/res/android"
-        android:clipOrientation="horizontal"
-        android:maxLevel="100"
-        android:gravity="left">
-    <level-list>
-        <item android:maxLevel="1500"  android:drawable="@drawable/sysbar_batterymini_red" />
-        <item android:maxLevel="10000" android:drawable="@drawable/sysbar_batterymini_100" />
-    </level-list>
-</clip>
diff --git a/packages/SystemUI/res/drawable/sysbar_signal.xml b/packages/SystemUI/res/drawable/sysbar_signal.xml
deleted file mode 100644
index 9561c37..0000000
--- a/packages/SystemUI/res/drawable/sysbar_signal.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="01" android:drawable="@drawable/sysbar_signal_0" />
-    <item android:maxLevel="10" android:drawable="@drawable/sysbar_signal_10" />
-    <item android:maxLevel="20" android:drawable="@drawable/sysbar_signal_20" />
-    <item android:maxLevel="30" android:drawable="@drawable/sysbar_signal_30" />
-    <item android:maxLevel="40" android:drawable="@drawable/sysbar_signal_40" />
-    <item android:maxLevel="50" android:drawable="@drawable/sysbar_signal_50" />
-    <item android:maxLevel="60" android:drawable="@drawable/sysbar_signal_60" />
-    <item android:maxLevel="70" android:drawable="@drawable/sysbar_signal_70" />
-    <item android:maxLevel="80" android:drawable="@drawable/sysbar_signal_80" />
-    <item android:maxLevel="90" android:drawable="@drawable/sysbar_signal_90" />
-    <item android:maxLevel="101" android:drawable="@drawable/sysbar_signal_100" />
-</level-list>
diff --git a/packages/SystemUI/res/drawable/sysbar_signalmini.xml b/packages/SystemUI/res/drawable/sysbar_signalmini.xml
deleted file mode 100644
index 598bf10..0000000
--- a/packages/SystemUI/res/drawable/sysbar_signalmini.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<clip xmlns:android="http://schemas.android.com/apk/res/android"
-        android:clipOrientation="horizontal"
-        android:gravity="right"
-        android:maxLevel="10000"
-        android:drawable="@drawable/sysbar_signalmini_100" />
diff --git a/packages/SystemUI/res/drawable/sysbar_wifi.xml b/packages/SystemUI/res/drawable/sysbar_wifi.xml
deleted file mode 100644
index 9561c37..0000000
--- a/packages/SystemUI/res/drawable/sysbar_wifi.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="01" android:drawable="@drawable/sysbar_signal_0" />
-    <item android:maxLevel="10" android:drawable="@drawable/sysbar_signal_10" />
-    <item android:maxLevel="20" android:drawable="@drawable/sysbar_signal_20" />
-    <item android:maxLevel="30" android:drawable="@drawable/sysbar_signal_30" />
-    <item android:maxLevel="40" android:drawable="@drawable/sysbar_signal_40" />
-    <item android:maxLevel="50" android:drawable="@drawable/sysbar_signal_50" />
-    <item android:maxLevel="60" android:drawable="@drawable/sysbar_signal_60" />
-    <item android:maxLevel="70" android:drawable="@drawable/sysbar_signal_70" />
-    <item android:maxLevel="80" android:drawable="@drawable/sysbar_signal_80" />
-    <item android:maxLevel="90" android:drawable="@drawable/sysbar_signal_90" />
-    <item android:maxLevel="101" android:drawable="@drawable/sysbar_signal_100" />
-</level-list>
diff --git a/packages/SystemUI/res/drawable/sysbar_wifimini.xml b/packages/SystemUI/res/drawable/sysbar_wifimini.xml
deleted file mode 100644
index ca6c9ed..0000000
--- a/packages/SystemUI/res/drawable/sysbar_wifimini.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/stat_sys_battery.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<clip xmlns:android="http://schemas.android.com/apk/res/android"
-        android:clipOrientation="horizontal"
-        android:gravity="right"
-        android:maxLevel="100"
-        android:drawable="@drawable/sysbar_signalmini_100" />
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 590132f..a6e5c89 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -25,84 +25,9 @@
         android:id="@+id/bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:animateLayoutChanges="true"
         >
 
-        <ImageView
-            android:id="@+id/notificationTrigger"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_alignParentRight="true"
-            android:layout_marginLeft="6dip"
-            android:src="@drawable/ic_sysbar_noti_none"
-            android:background="@drawable/ic_sysbar_icon_bg"
-            android:gravity="center"
-            />
-
-        <LinearLayout
-            android:id="@+id/notificationButtons"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@+id/notificationTrigger"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:visibility="gone"
-            >
-
-            <TextView android:id="@+id/clear_all_button"
-                style="?android:attr/textAppearance"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="right|center_vertical"
-                android:layout_marginTop="2dip"
-                android:layout_marginBottom="1dip"
-                android:layout_marginRight="10dip"
-                android:padding="6dip"
-                android:textSize="14sp"
-                android:text="@string/status_bar_clear_all_button"
-                />
-
-            <TextView android:id="@+id/do_not_disturb"
-                style="?android:attr/textAppearance"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="right|center_vertical"
-                android:layout_marginTop="2dip"
-                android:layout_marginBottom="1dip"
-                android:layout_marginRight="10dip"
-                android:padding="6dip"
-                android:textSize="14sp"
-                android:text="@string/status_bar_do_not_disturb_button"
-                />
-
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.tablet.NotificationIconArea
-            android:id="@+id/notificationIcons"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@+id/notificationTrigger"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            >
-            <com.android.systemui.statusbar.tablet.InputMethodButton
-                android:id="@+id/imeButton"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_marginLeft="8dip"
-                android:src="@drawable/ic_sysbar_ime_default"
-                android:background="@drawable/ic_sysbar_icon_bg"
-                android:visibility="invisible"
-                />
-            <view
-                class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout"
-                android:id="@+id/icons"
-                android:layout_width="wrap_content"
-                android:layout_height="@*android:dimen/status_bar_icon_size"
-                android:layout_marginLeft="8dip"
-                />
-        </com.android.systemui.statusbar.tablet.NotificationIconArea>
-
-
         <FrameLayout
             android:id="@+id/ticker"
             android:layout_width="wrap_content"
@@ -114,11 +39,60 @@
             android:animateLayoutChanges="true"
             />
 
-        <include layout="@layout/status_bar_center"
-            android:layout_width="256dip"
+        <LinearLayout
+            android:id="@+id/notificationArea"
+            android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_centerInParent="true"
-            />
+            android:layout_alignParentRight="true"
+            android:orientation="horizontal"
+            >
+            <com.android.systemui.statusbar.tablet.NotificationIconArea
+                android:id="@+id/notificationIcons"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                >
+                <view
+                    class="com.android.systemui.statusbar.tablet.NotificationIconArea$IconLayout"
+                    android:id="@+id/icons"
+                    android:layout_width="wrap_content"
+                    android:layout_height="@*android:dimen/status_bar_icon_size"
+                    android:layout_marginLeft="8dip"
+                    />
+            </com.android.systemui.statusbar.tablet.NotificationIconArea>
+
+            <LinearLayout
+                android:id="@+id/notificationTrigger"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                >
+                <com.android.systemui.statusbar.policy.Clock
+                    style="@*android:style/TextAppearance.StatusBar.Icon"
+                    android:id="@+id/clock"
+                    android:layout_width="64dip"
+                    android:layout_height="48dip"
+                    android:singleLine="true"
+                    android:gravity="center"
+                    android:textSize="16sp"
+                    android:textStyle="bold"
+                    android:padding="2dip"
+                    />
+                <ImageView
+                    android:id="@+id/battery"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_gravity="center_vertical"
+                    />
+                <ImageView
+                    android:id="@+id/network"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/ic_sysbar_wifi_mini"
+                    />
+            </LinearLayout>
+        </LinearLayout>
 
         <LinearLayout
             android:id="@+id/navigationArea"
@@ -126,9 +100,10 @@
             android:layout_height="match_parent"
             android:layout_alignParentLeft="true"
             android:orientation="horizontal"
+            android:animateLayoutChanges="true"
             >
 
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
+            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:paddingLeft="15dip"
@@ -137,7 +112,7 @@
                 android:background="@drawable/ic_sysbar_icon_bg"
                 systemui:keyCode="4"
                 />
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
+            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:paddingLeft="15dip"
@@ -154,7 +129,7 @@
                 android:paddingLeft="15dip"
                 android:paddingRight="15dip"
                 />
-            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
+            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:paddingLeft="15dip"
@@ -185,6 +160,15 @@
                     android:gravity="center"
                     />
             </com.android.systemui.statusbar.tablet.ShirtPocket>
+            <com.android.systemui.statusbar.tablet.InputMethodButton
+                android:id="@+id/imeButton"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginLeft="8dip"
+                android:src="@drawable/ic_sysbar_ime_default"
+                android:background="@drawable/ic_sysbar_icon_bg"
+                android:visibility="invisible"
+                />
         </LinearLayout>
     </RelativeLayout>
 
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_center.xml b/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
deleted file mode 100644
index d4f0e50..0000000
--- a/packages/SystemUI/res/layout-xlarge/status_bar_center.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- Center of status bar: System info display, system info panel trigger -->
-<RelativeLayout android:id="@+id/systemInfo"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_centerInParent="true"
-    android:clickable="true"
-    >
-    <com.android.systemui.statusbar.Clock
-        style="@*android:style/TextAppearance.StatusBar.Icon"
-        android:id="@+id/clock"
-        android:layout_width="64dip"
-        android:layout_height="48dip"
-        android:layout_centerInParent="true"
-        android:singleLine="true"
-        android:gravity="center"
-        android:textSize="16sp"
-        android:textStyle="bold"
-        android:padding="2dip"
-        />
-    <ImageView
-        android:id="@+id/battery"
-        android:layout_width="64dip"
-        android:layout_height="16dip"
-        android:layout_toLeftOf="@id/clock"
-        android:layout_centerInParent="true"
-        android:background="@drawable/sysbar_minimeter_bg" 
-        />
-    <ImageView
-        android:id="@+id/signal"
-        android:layout_width="64dip"
-        android:layout_height="16dip"
-        android:layout_toRightOf="@id/clock"
-        android:layout_centerInParent="true"
-        android:background="@drawable/sysbar_minimeter_bg" 
-        />
-    <ImageView
-        android:id="@+id/battery_icon"
-        android:layout_height="30dip"
-        android:layout_width="30dip"
-        android:layout_toLeftOf="@id/battery"
-        android:layout_centerInParent="true"
-        android:src="@drawable/ic_sysbar_battery_mini"
-        />
-    <ImageView
-        android:id="@+id/signal_icon"
-        android:layout_height="30dip"
-        android:layout_width="30dip"
-        android:layout_toRightOf="@id/signal"
-        android:layout_centerInParent="true"
-        android:src="@drawable/ic_sysbar_wifi_mini"
-        />
-</RelativeLayout>
-
-
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml
index a7c91f5..02f9a90 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml
@@ -19,7 +19,7 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.systemui.statusbar.tablet.NotificationPanel
+<com.android.systemui.statusbar.tablet.NotificationPeekPanel
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
@@ -40,4 +40,4 @@
         android:descendantFocusability="afterDescendants"
         >
     </FrameLayout>
-</com.android.systemui.statusbar.tablet.NotificationPanel>
+</com.android.systemui.statusbar.tablet.NotificationPeekPanel>
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
index 8cbf3e3..884a473 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml
@@ -28,11 +28,97 @@
     android:animateLayoutChanges="true"
     >
 
+    <com.android.systemui.statusbar.policy.Clock
+        android:id="@+id/clock"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_alignParentTop="true"
+        android:gravity="right"
+        />
+
+    <com.android.systemui.statusbar.policy.DateView
+        android:id="@+id/date"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_below="@id/clock"
+        android:gravity="right"
+        />
+
+    <ImageView
+        android:id="@+id/settings_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/date"
+        android:layout_alignParentRight="true"
+        android:paddingRight="10dp"
+        android:src="@drawable/ic_sysbar_quicksettings"
+        android:baseline="17dp"
+        />
+
+    <ImageView
+        android:id="@+id/notification_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@id/settings_button"
+        android:layout_alignParentRight="true"
+        android:paddingRight="10dp"
+        android:visibility="invisible"
+        android:src="@drawable/status_bar_veto"
+        android:baseline="17dp"
+        />
+
+    <ImageView
+        android:id="@+id/battery"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignBaseline="@id/settings_button"
+        android:src="@drawable/ic_sysbar_battery_mini"
+        android:baseline="17dp"
+        />
+
+    <TextView
+        android:id="@+id/battery_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/battery"
+        android:layout_alignBaseline="@id/settings_button"
+        android:singleLine="true"
+        android:text="@string/system_panel_settings_button"
+        />
+
+    <ImageView
+        android:id="@+id/network"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_toRightOf="@id/battery_text"
+        android:layout_alignBaseline="@id/settings_button"
+        android:src="@drawable/ic_sysbar_wifi_mini"
+        android:baseline="21dp"
+        />
+
+    <TextView
+        android:id="@+id/network_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/network"
+        android:layout_alignBaseline="@id/settings_button"
+        android:singleLine="true"
+        android:text="@string/system_panel_settings_button"
+        />
+
+    <FrameLayout
+        android:id="@+id/settings_frame"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_below="@id/settings_button"
+        />
+
     <ScrollView
         android:id="@+id/notificationScroller"
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
-        android:animateLayoutChanges="true"
+        android:layout_below="@id/settings_button"
         >
         <LinearLayout 
             android:id="@+id/content"
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml
new file mode 100644
index 0000000..c6ddfed
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+-->
+
+<com.android.systemui.statusbar.tablet.SettingsPanel
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="200dip"
+    >
+</com.android.systemui.statusbar.tablet.SettingsPanel>
+
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
index e6ec9f4..a1792fd 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_system.xml
@@ -95,7 +95,6 @@
                 android:layout_height="wrap_content"
                 android:layout_alignParentBottom="true"
                 android:scaleType="centerCrop"
-                android:src="@drawable/sysbar_battery"
                 />
             <TextView android:id="@+id/battery_info"
                 style="@style/TextAppearance.StatusBar.SystemPanel"
@@ -106,7 +105,7 @@
                 />
         </RelativeLayout>
 
-        <com.android.systemui.statusbar.Clock
+        <com.android.systemui.statusbar.policy.Clock
             style="@style/TextAppearance.StatusBar.SystemPanel"
             android:id="@+id/clock"
             android:layout_width="wrap_content"
@@ -130,7 +129,6 @@
                 android:layout_height="wrap_content"
                 android:layout_alignParentBottom="true"
                 android:scaleType="centerCrop"
-                android:src="@drawable/sysbar_signal"
                 />
 
             <TextView android:id="@+id/signal_info"
@@ -200,7 +198,7 @@
             >
             <!-- TODO: alarm -->
             <!-- TODO: sync -->
-            <com.android.systemui.statusbar.DateView
+            <com.android.systemui.statusbar.policy.DateView
                 android:id="@+id/date"
                 style="@style/TextAppearance.StatusBar.SystemPanel"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 2f1b36e8..c8f5772 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -19,7 +19,7 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.systemui.statusbar.StatusBarView
+<com.android.systemui.statusbar.phone.PhoneStatusBarView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:background="@drawable/status_bar_background"
@@ -33,7 +33,7 @@
         android:layout_height="match_parent"
         android:orientation="horizontal">
             
-        <com.android.systemui.statusbar.IconMerger android:id="@+id/notificationIcons"
+        <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="match_parent"
@@ -50,7 +50,7 @@
             android:gravity="center_vertical"
             android:orientation="horizontal"/>    
 
-        <com.android.systemui.statusbar.Clock
+        <com.android.systemui.statusbar.policy.Clock
             android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
@@ -82,7 +82,7 @@
                 android:layout_height="25dip"
                 />
         </ImageSwitcher>
-        <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
+        <com.android.systemui.statusbar.phone.TickerView android:id="@+id/tickerText"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="wrap_content"
@@ -100,10 +100,10 @@
                 android:layout_height="wrap_content"
                 android:singleLine="true"
                 />
-        </com.android.systemui.statusbar.TickerView>
+        </com.android.systemui.statusbar.phone.TickerView>
     </LinearLayout>
 
-    <com.android.systemui.statusbar.DateView android:id="@+id/date"
+    <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
         android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
@@ -113,4 +113,4 @@
         android:paddingRight="6px"
         android:background="@drawable/status_bar_background"
         />
-</com.android.systemui.statusbar.StatusBarView>
+</com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index b5b1b50..3ad199e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.systemui.statusbar.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.phone.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -33,7 +33,7 @@
         android:paddingRight="3dp"
         android:background="@drawable/shade_header_background"
         >
-        <com.android.systemui.statusbar.CarrierLabel
+        <com.android.systemui.statusbar.phone.CarrierLabel
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
@@ -72,7 +72,7 @@
             android:layout_height="match_parent"
             android:fadingEdge="none"
             >
-            <com.android.systemui.statusbar.NotificationLinearLayout
+            <LinearLayout
                 android:id="@+id/notificationLinearLayout"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -115,7 +115,7 @@
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
                     />
-            </com.android.systemui.statusbar.NotificationLinearLayout>
+            </LinearLayout>
         </ScrollView>
 
         <ImageView
@@ -126,4 +126,4 @@
         />
 
     </FrameLayout>
-</com.android.systemui.statusbar.ExpandedView>
+</com.android.systemui.statusbar.phone.ExpandedView>
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index a2b40e6..a0ddab5 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -15,7 +15,7 @@
     limitations under the License.
 -->
 
-<com.android.systemui.statusbar.TrackingView
+<com.android.systemui.statusbar.phone.TrackingView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:visibility="gone"
@@ -26,13 +26,13 @@
     android:paddingRight="0px"
     >
 
-    <com.android.systemui.statusbar.TrackingPatternView
+    <com.android.systemui.statusbar.phone.TrackingPatternView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         />
 
-    <com.android.systemui.statusbar.CloseDragHandle android:id="@+id/close"
+    <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
@@ -45,6 +45,6 @@
             android:src="@drawable/shade_handlebar"
             />
 
-    </com.android.systemui.statusbar.CloseDragHandle>
+    </com.android.systemui.statusbar.phone.CloseDragHandle>
 
-</com.android.systemui.statusbar.TrackingView>
+</com.android.systemui.statusbar.phone.TrackingView>
diff --git a/packages/SystemUI/res/values-xlarge/config.xml b/packages/SystemUI/res/values-xlarge/config.xml
index 6df883c..e6af4f5 100644
--- a/packages/SystemUI/res/values-xlarge/config.xml
+++ b/packages/SystemUI/res/values-xlarge/config.xml
@@ -24,7 +24,7 @@
 
     <!-- Component to be used as the status bar service.  Must implement the IStatusBar
      interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_statusBarComponent">com.android.systemui.statusbar.tablet.TabletStatusBarService</string>
+    <string name="config_statusBarComponent">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
 
 </resources>
 
diff --git a/packages/SystemUI/res/values-xlarge/strings.xml b/packages/SystemUI/res/values-xlarge/strings.xml
index 3c59c92..e305681 100644
--- a/packages/SystemUI/res/values-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-xlarge/strings.xml
@@ -23,13 +23,6 @@
 
     <!-- System panel ("Quick Settings") -->
 
-    <!-- Text to display underneath the graphical battery meter. Should
-         include the word for "battery" and a place for the percentage charge
-         available. [CHAR LIMIT=20] -->
-    <string name="system_panel_battery_meter_format">
-        Battery: <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>
-    </string>
-
     <!-- Text to display underneath the graphical signal strength meter when
          no connection is available. [CHAR LIMIT=20] -->
     <string name="system_panel_signal_meter_disconnected">
@@ -38,10 +31,9 @@
 
     <!-- Text to display underneath the graphical signal strength meter when
          it is displaying information about a connected, named Wi-Fi network.
-         Should include the word for "Wi-Fi" and a placeholder for the
-         wireless network's SSID. [CHAR LIMIT=20] -->
+         [CHAR LIMIT=20] -->
     <string name="system_panel_signal_meter_wifi_ssid_format">
-        Wi-Fi: <xliff:g id="ssid">%s</xliff:g>
+        <xliff:g id="ssid">%s</xliff:g>
     </string>
 
     <!-- Text to display underneath the graphical signal strength meter when
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 07cb52a..86beb14 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -33,7 +33,7 @@
 
     <!-- Component to be used as the status bar service.  Must implement the IStatusBar
      interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.PhoneStatusBarService</string>
+    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
 
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a65de37..e8c3c91 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Name of the status bar as seen in the applications info settings page. [CHAR LIMIT=12] -->
-    <string name="app_label">Status Bar</string>
+    <string name="app_label">System UI</string>
 
     <!-- The text for the button in the notification window-shade that clears
          all of the currently visible notifications. [CHAR LIMIT=10]-->
@@ -74,6 +74,10 @@
     <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
     <string name="system_panel_settings_button">Settings</string>
 
+    <!-- Text to display next to the graphical battery meter.  [CHAR LIMIT=3] -->
+    <string name="system_panel_battery_meter_format" translatable="false">
+        <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>
+    </string>
 
     <!-- Recent Tasks dialog: title [CHAR LIMIT=30] -->
     <string name="recent_tasks_title">Recent</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 5aefb02..86ffb4d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -39,4 +39,17 @@
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#FFFFFFFF</item>
     </style>
+
+    <style name="Animation" />
+
+    <style name="Animation.ShirtPocketPanel">
+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
+    </style>
+
+    <style name="Animation.RecentPanel">
+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
index faea3fc..ff2a4ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
@@ -29,6 +29,8 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
 import android.app.IThumbnailReceiver;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ActivityNotFoundException;
@@ -189,8 +191,15 @@
         public void onCardSelected(int n) {
             if (n < mActivityDescriptions.size()) {
                 ActivityDescription item = mActivityDescriptions.get(n);
-                // prepare a launch intent and send it
-                if (item.intent != null) {
+                if (item.id >= 0) {
+                    // This is an active task; it should just go to the foreground.
+                    IActivityManager am = ActivityManagerNative.getDefault();
+                    try {
+                        am.moveTaskToFront(item.id);
+                    } catch (RemoteException e) {
+                    }
+                } else if (item.intent != null) {
+                    // prepare a launch intent and send it
                     item.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
                     try {
                         if (DBG) Log.v(TAG, "Starting intent " + item.intent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
deleted file mode 100644
index 8105352..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2008 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.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.LinearLayout;
-
-
-public class NotificationLinearLayout extends LinearLayout {
-    public NotificationLinearLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 776b59c..731f6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -34,7 +34,6 @@
 
 import java.util.ArrayList;
 
-import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
@@ -43,8 +42,8 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.R;
 
-public abstract class StatusBarService extends SystemUI implements CommandQueue.Callbacks {
-    static final String TAG = "StatusBarService";
+public abstract class StatusBar extends SystemUI implements CommandQueue.Callbacks {
+    static final String TAG = "StatusBar";
     private static final boolean SPEW = false;
 
     protected CommandQueue mCommandQueue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 8419e56..9a61be6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -84,7 +84,7 @@
         if (!iconEquals) {
             Drawable drawable = getIcon(icon);
             if (drawable == null) {
-                Slog.w(StatusBarService.TAG, "No icon for slot " + mSlot);
+                Slog.w(StatusBar.TAG, "No icon for slot " + mSlot);
                 return false;
             }
             setImageDrawable(drawable);
@@ -130,7 +130,7 @@
             try {
                 r = context.getPackageManager().getResourcesForApplication(icon.iconPackage);
             } catch (PackageManager.NameNotFoundException ex) {
-                Slog.e(StatusBarService.TAG, "Icon package not found: " + icon.iconPackage);
+                Slog.e(StatusBar.TAG, "Icon package not found: " + icon.iconPackage);
                 return null;
             }
         } else {
@@ -144,7 +144,7 @@
         try {
             return r.getDrawable(icon.iconId);
         } catch (RuntimeException e) {
-            Slog.w(StatusBarService.TAG, "Icon not found in "
+            Slog.w(StatusBar.TAG, "Icon not found in "
                   + (icon.iconPackage != null ? icon.iconId : "<system>")
                   + ": " + Integer.toHexString(icon.iconId));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java
index 31b78b6..d8441f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CarrierLabel.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java
index 0f6723e..ba64282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CloseDragHandle.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -23,7 +23,7 @@
 
 
 public class CloseDragHandle extends LinearLayout {
-    PhoneStatusBarService mService;
+    PhoneStatusBar mService;
 
     public CloseDragHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index a2d4b95..92b8976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -27,7 +27,7 @@
 
 
 public class ExpandedView extends LinearLayout {
-    PhoneStatusBarService mService;
+    PhoneStatusBar mService;
     int mPrevHeight = -1;
 
     public ExpandedView(Context context, AttributeSet attrs) {
@@ -50,10 +50,10 @@
          super.onLayout(changed, left, top, right, bottom);
          int height = bottom - top;
          if (height != mPrevHeight) {
-             //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight
+             //Slog.d(StatusBar.TAG, "height changed old=" + mPrevHeight
              //     + " new=" + height);
              mPrevHeight = height;
-             mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
+             mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
          }
      }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index e87d003..e1d17a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.os.Handler;
@@ -26,7 +26,7 @@
 import com.android.internal.statusbar.StatusBarIcon;
 
 import com.android.systemui.R;
-
+import com.android.systemui.statusbar.StatusBarIconView;
 
 public class IconMerger extends LinearLayout {
     private static final String TAG = "IconMerger";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d3d2285..2dad81c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.app.Service;
 import android.app.ActivityManagerNative;
@@ -66,19 +66,19 @@
 import java.util.HashMap;
 import java.util.Set;
 
-import com.android.internal.statusbar.IStatusBar;
-import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.StatusBarPolicy;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.StatusBar;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.policy.DateView;
 
 
-
-public class PhoneStatusBarService extends StatusBarService {
-    static final String TAG = "PhoneStatusBarService";
+public class PhoneStatusBar extends StatusBar {
+    static final String TAG = "PhoneStatusBar";
     static final boolean SPEW = false;
 
     public static final String ACTION_STATUSBAR_START
@@ -95,12 +95,12 @@
     // will likely move to a resource or other tunable param at some point
     private static final int INTRUDER_ALERT_DECAY_MS = 10000;
 
-    StatusBarPolicy mIconPolicy;
+    PhoneStatusBarPolicy mIconPolicy;
 
     int mIconSize;
     Display mDisplay;
 
-    StatusBarView mStatusBarView;
+    PhoneStatusBarView mStatusBarView;
     int mPixelFormat;
     H mHandler = new H();
     Object mQueueLock = new Object();
@@ -202,7 +202,7 @@
         addIntruderView();
 
         // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new StatusBarPolicy(mContext);
+        mIconPolicy = new PhoneStatusBarPolicy(mContext);
     }
 
     // ================================================================================
@@ -223,7 +223,8 @@
         mIntruderAlertView.setVisibility(View.GONE);
         mIntruderAlertView.setClickable(true);
 
-        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+        PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
+                R.layout.status_bar, null);
         sb.mService = this;
 
         // figure out which pixel-format to use for the status bar.
@@ -1304,7 +1305,6 @@
     }
 
     void setDateViewVisibility(boolean visible, int anim) {
-        mDateView.setUpdates(visible);
         mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         mDateView.startAnimation(loadAnim(anim, null));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 4f5c3ae..73b6723 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.statusbar.phone;
 
 import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
@@ -71,8 +71,8 @@
  * bar at boot time.  It goes through the normal API for icons, even though it probably
  * strictly doesn't need to.
  */
-public class StatusBarPolicy {
-    private static final String TAG = "StatusBarPolicy";
+public class PhoneStatusBarPolicy {
+    private static final String TAG = "PhoneStatusBarPolicy";
 
     // message codes for the handler
     private static final int EVENT_BATTERY_CLOSE = 4;
@@ -368,7 +368,7 @@
         }
     };
 
-    public StatusBarPolicy(Context context) {
+    public PhoneStatusBarPolicy(Context context) {
         mContext = context;
         mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
         mSignalStrength = new SignalStrength();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 20fc41f..84c524a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -29,13 +29,14 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.FixedSizeDrawable;
 
-public class StatusBarView extends FrameLayout {
-    private static final String TAG = "StatusBarView";
+public class PhoneStatusBarView extends FrameLayout {
+    private static final String TAG = "PhoneStatusBarView";
 
     static final int DIM_ANIM_TIME = 400;
     
-    PhoneStatusBarService mService;
+    PhoneStatusBar mService;
     boolean mTracking;
     int mStartX, mStartY;
     ViewGroup mNotificationIcons;
@@ -50,7 +51,7 @@
     Rect mButtonBounds = new Rect();
     boolean mCapturingEvents = true;
 
-    public StatusBarView(Context context, AttributeSet attrs) {
+    public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
@@ -98,7 +99,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
index e7b0509..8ee12de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -36,7 +36,9 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.internal.util.CharSequences;
+
 import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
 
 public abstract class Ticker {
     private static final int TICKER_SEGMENT_DELAY = 3000;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
index 8140811..8aa3837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java
index ba6f15d..d2ed5ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingPatternView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
index c59eb6a..fd32a3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -26,7 +26,7 @@
 
 public class TrackingView extends LinearLayout {
     final Display mDisplay;
-    PhoneStatusBarService mService;
+    PhoneStatusBar mService;
     boolean mTracking;
     int mStartX, mStartY;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
new file mode 100644
index 0000000..a1efdd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -0,0 +1,74 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import java.util.ArrayList;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.util.Slog;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+public class BatteryController extends BroadcastReceiver {
+    private static final String TAG = "StatusBar.BatteryController";
+
+    private Context mContext;
+    private ArrayList<ImageView> mIconViews = new ArrayList<ImageView>();
+    private ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
+
+    public BatteryController(Context context) {
+        mContext = context;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        context.registerReceiver(this, filter);
+    }
+
+    public void addIconView(ImageView v) {
+        mIconViews.add(v);
+    }
+
+    public void addLabelView(TextView v) {
+        mLabelViews.add(v);
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+            final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+            int N = mIconViews.size();
+            for (int i=0; i<N; i++) {
+                final int icon = intent.getIntExtra(BatteryManager.EXTRA_ICON_SMALL, 0);
+                ImageView v = mIconViews.get(i);
+                v.setImageResource(icon);
+                v.setImageLevel(level);
+            }
+            N = mLabelViews.size();
+            for (int i=0; i<N; i++) {
+                //final boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+                TextView v = mLabelViews.get(i);
+                v.setText(mContext.getString(R.string.system_panel_battery_meter_format, level));
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 9fc8df5..69872df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.policy;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index e127038..136f4a94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.policy;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -24,6 +24,8 @@
 import android.util.Slog;
 import android.widget.TextView;
 import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
 
 import java.text.DateFormat;
 import java.util.Date;
@@ -31,7 +33,9 @@
 public final class DateView extends TextView {
     private static final String TAG = "DateView";
 
-    private boolean mUpdating = false;
+    private boolean mAttachedToWindow;
+    private boolean mWindowVisible;
+    private boolean mUpdating;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -51,12 +55,28 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+        mAttachedToWindow = true;
+        setUpdates();
     }
     
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        setUpdates(false);
+        mAttachedToWindow = false;
+        setUpdates();
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        mWindowVisible = visibility == VISIBLE;
+        setUpdates();
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        setUpdates();
     }
 
     @Override
@@ -67,10 +87,26 @@
 
     private final void updateClock() {
         Date now = new Date();
-        setText(DateFormat.getDateInstance(DateFormat.LONG).format(now));
+        setText(DateFormat.getDateInstance(DateFormat.FULL).format(now));
     }
 
-    public void setUpdates(boolean update) {
+    private boolean isVisible() {
+        View v = this;
+        while (true) {
+            if (v.getVisibility() != VISIBLE) {
+                return false;
+            }
+            final ViewParent parent = v.getParent();
+            if (parent instanceof View) {
+                v = (View)parent;
+            } else {
+                return true;
+            }
+        }
+    }
+
+    private void setUpdates() {
+        boolean update = mAttachedToWindow && mWindowVisible && isVisible();
         if (update != mUpdating) {
             mUpdating = update;
             if (update) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java
index eb22b61..8f2f5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FixedSizeDrawable.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.policy;
 
 import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
@@ -22,14 +22,14 @@
 import android.graphics.Rect;
 import android.util.Slog;
 
-class FixedSizeDrawable extends Drawable {
+public class FixedSizeDrawable extends Drawable {
     Drawable mDrawable;
     int mLeft;
     int mTop;
     int mRight;
     int mBottom;
 
-    FixedSizeDrawable(Drawable that) {
+    public FixedSizeDrawable(Drawable that) {
         mDrawable = that;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index b01c5e7..aed3dc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.policy;
 
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -37,6 +37,8 @@
 import com.android.systemui.R;
 
 public class KeyButtonView extends ImageView {
+    private static final String TAG = "StatusBar.KeyButtonView";
+
     IWindowManager mWindowManager;
     long mDownTime;
     boolean mSending, mLongPressed;
@@ -68,8 +70,7 @@
 
         mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
         if (mCode == 0) {
-            Slog.w(StatusBarService.TAG, "KeyButtonView without key code id=0x"
-                    + Integer.toHexString(getId()));
+            Slog.w(TAG, "KeyButtonView without key code id=0x" + Integer.toHexString(getId()));
         }
         
         a.recycle();
@@ -99,18 +100,20 @@
                 if (mSending) {
                     x = (int)ev.getX();
                     y = (int)ev.getY();
-                    if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
-                        mSending = false;
-                        sendEvent(KeyEvent.ACTION_UP,
-                                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
-                                        | KeyEvent.FLAG_CANCELED);
-                        setPressed(false);
-                        removeCallbacks(mCheckLongPress);
-                    }
+                    setPressed(x >= 0 && x < getWidth() && y >= 0 &&  y < getHeight());
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                setPressed(false);
+                if (mSending && !mLongPressed) {
+                    mSending = false;
+                    sendEvent(KeyEvent.ACTION_UP,
+                            KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
+                                | KeyEvent.FLAG_CANCELED);
+                    removeCallbacks(mCheckLongPress);
                 }
                 break;
             case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
                 setPressed(false);
                 if (mSending && !mLongPressed) {
                     mSending = false;
@@ -132,7 +135,7 @@
         final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
                 0, 0, 0, flags, InputDevice.SOURCE_KEYBOARD);
         try {
-            //Slog.d(StatusBarService.TAG, "injecting event " + ev);
+            //Slog.d(TAG, "injecting event " + ev);
             mWindowManager.injectInputEventNoWait(ev);
         } catch (RemoteException ex) {
             // System process is dead
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
new file mode 100644
index 0000000..4ff2429
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -0,0 +1,626 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.server.am.BatteryStatsService;
+
+import com.android.systemui.R;
+
+public class NetworkController extends BroadcastReceiver {
+    // debug
+    static final String TAG = "StatusBar.NetworkController";
+    static final boolean DEBUG = false;
+
+    // telephony
+    boolean mHspaDataDistinguishable;
+    final TelephonyManager mPhone;
+    boolean mDataConnected;
+    int mPhoneSignalIconId;
+    int mDataIconId;
+    IccCard.State mSimState = IccCard.State.READY;
+    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+    int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    ServiceState mServiceState;
+    SignalStrength mSignalStrength;
+    int[] mDataIconList = TelephonyIcons.DATA_G[0];
+ 
+    // wifi
+    final WifiManager mWifiManager;
+    boolean mWifiEnabled, mWifiConnected;
+    int mWifiLevel;
+    String mWifiSsid;
+    int mWifiIconId;
+
+    // data connectivity (regardless of state, can we access the internet?)
+    // state of inet connection - 0 not connected, 100 connected
+    private int mInetCondition = 0;
+    private static final int INET_CONDITION_THRESHOLD = 50;
+
+    // our ui
+    Context mContext;
+    ArrayList<ImageView> mPhoneIconViews = new ArrayList<ImageView>();
+    ArrayList<ImageView> mDataIconViews = new ArrayList<ImageView>();
+    ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
+    int mLastPhoneSignalIconId = -1;
+    int mLastCombinedDataIconId = -1;
+    String mLastLabel = "";
+    
+    // yuck -- stop doing this here and put it in the framework
+    IBatteryStats mBatteryStats;
+
+    /**
+     * Construct this controller object and register for updates.
+     */
+    public NetworkController(Context context) {
+        mContext = context;
+
+        // telephony
+        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhone.listen(mPhoneStateListener,
+                          PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+        mHspaDataDistinguishable = mContext.getResources().getBoolean(
+                R.bool.config_hspa_data_distinguishable);
+        
+
+        // wifi
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+
+        // broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        context.registerReceiver(this, filter);
+
+        // yuck
+        mBatteryStats = BatteryStatsService.getService();
+    }
+
+    public void addPhoneIconView(ImageView v) {
+        mPhoneIconViews.add(v);
+    }
+
+    public void addCombinedDataIconView(ImageView v) {
+        mDataIconViews.add(v);
+    }
+
+    public void addLabelView(TextView v) {
+        mLabelViews.add(v);
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+                || action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)
+                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            updateWifiState(intent);
+            refreshViews();
+        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+            updateSimState(intent);
+            updateDataIcon();
+            refreshViews();
+        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+            updateConnectivity(intent);
+            refreshViews();
+        }
+    }
+
+
+    // ===== Telephony ==============================================================
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            if (DEBUG) {
+                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength);
+            }
+            mSignalStrength = signalStrength;
+            updateTelephonySignalStrength();
+            refreshViews();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            if (DEBUG) {
+                Slog.d(TAG, "onServiceStateChanged state=" + state.getState());
+            }
+            mServiceState = state;
+            updateTelephonySignalStrength();
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (DEBUG) {
+                Slog.d(TAG, "onCallStateChanged state=" + state);
+            }
+            // In cdma, if a voice call is made, RSSI should switch to 1x.
+            if (isCdma()) {
+                updateTelephonySignalStrength();
+                refreshViews();
+            }
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            if (DEBUG) {
+                Slog.d(TAG, "onDataConnectionStateChanged: state=" + state 
+                        + " type=" + networkType);
+            }
+            mDataState = state;
+            updateDataNetType(networkType);
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            if (DEBUG) {
+                Slog.d(TAG, "onDataActivity: direction=" + direction);
+            }
+            mDataActivity = direction;
+            updateDataIcon();
+            refreshViews();
+        }
+    };
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
+        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCard.State.ABSENT;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCard.State.READY;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
+            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCard.State.PIN_REQUIRED;
+            }
+            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCard.State.PUK_REQUIRED;
+            }
+            else {
+                mSimState = IccCard.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCard.State.UNKNOWN;
+        }
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    private boolean isEvdo() {
+        return ((mServiceState != null)
+             && ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+                 || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+                 || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
+    }
+
+    private boolean hasService() {
+        if (mServiceState != null) {
+            switch (mServiceState.getState()) {
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_POWER_OFF:
+                    return false;
+                default:
+                    return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private int getCdmaLevel() {
+        if (mSignalStrength == null) return 0;
+        final int cdmaDbm = mSignalStrength.getCdmaDbm();
+        final int cdmaEcio = mSignalStrength.getCdmaEcio();
+        int levelDbm = 0;
+        int levelEcio = 0;
+
+        if (cdmaDbm >= -75) levelDbm = 4;
+        else if (cdmaDbm >= -85) levelDbm = 3;
+        else if (cdmaDbm >= -95) levelDbm = 2;
+        else if (cdmaDbm >= -100) levelDbm = 1;
+        else levelDbm = 0;
+
+        // Ec/Io are in dB*10
+        if (cdmaEcio >= -90) levelEcio = 4;
+        else if (cdmaEcio >= -110) levelEcio = 3;
+        else if (cdmaEcio >= -130) levelEcio = 2;
+        else if (cdmaEcio >= -150) levelEcio = 1;
+        else levelEcio = 0;
+
+        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
+    }
+
+    private int getEvdoLevel() {
+        if (mSignalStrength == null) return 0;
+        int evdoDbm = mSignalStrength.getEvdoDbm();
+        int evdoSnr = mSignalStrength.getEvdoSnr();
+        int levelEvdoDbm = 0;
+        int levelEvdoSnr = 0;
+
+        if (evdoDbm >= -65) levelEvdoDbm = 4;
+        else if (evdoDbm >= -75) levelEvdoDbm = 3;
+        else if (evdoDbm >= -90) levelEvdoDbm = 2;
+        else if (evdoDbm >= -105) levelEvdoDbm = 1;
+        else levelEvdoDbm = 0;
+
+        if (evdoSnr >= 7) levelEvdoSnr = 4;
+        else if (evdoSnr >= 5) levelEvdoSnr = 3;
+        else if (evdoSnr >= 3) levelEvdoSnr = 2;
+        else if (evdoSnr >= 1) levelEvdoSnr = 1;
+        else levelEvdoSnr = 0;
+
+        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+    }
+
+    private final void updateTelephonySignalStrength() {
+        // Display signal strength while in "emergency calls only" mode
+        if (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly())) {
+            //Slog.d(TAG, "updateTelephonySignalStrength: no service");
+            if (Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode;
+            } else {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            }
+        } else {
+            if (mSignalStrength == null) {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            } else if (isCdma()) {
+                // If 3G(EV) and 1x network are available than 3G should be
+                // displayed, displayed RSSI should be from the EV side.
+                // If a voice call is made then RSSI should switch to 1x.
+                int iconLevel;
+                if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
+                    iconLevel = getEvdoLevel();
+                } else {
+                    iconLevel = getCdmaLevel();
+                }
+                int[] iconList;
+                if (isCdmaEri()) {
+                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                } else {
+                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                }
+                mPhoneSignalIconId = iconList[iconLevel];
+            } else {
+                int asu = mSignalStrength.getGsmSignalStrength();
+
+                // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+                // asu = 0 (-113dB or less) is very weak
+                // signal, its better to show 0 bars to the user in such cases.
+                // asu = 99 is a special case, where the signal strength is unknown.
+                int iconLevel;
+                if (asu <= 2 || asu == 99) iconLevel = 0;
+                else if (asu >= 12) iconLevel = 4;
+                else if (asu >= 8)  iconLevel = 3;
+                else if (asu >= 5)  iconLevel = 2;
+                else iconLevel = 1;
+
+                // Though mPhone is a Manager, this call is not an IPC
+                int[] iconList;
+                if (mPhone.isNetworkRoaming()) {
+                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                } else {
+                    iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                }
+                mPhoneSignalIconId = iconList[iconLevel];
+            }
+        }
+    }
+
+    private final void updateDataNetType(int net) {
+        switch (net) {
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+                mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+                break;
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                if (mHspaDataDistinguishable) {
+                    mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+                } else {
+                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                }
+                break;
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+                // display 1xRTT for IS95A/B
+                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                break;
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+                mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                break;
+            case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                break;
+            // TODO - add support for NETWORK_TYPE_LTE and NETWORK_TYPE_EHRPD
+            default:
+                mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+            break;
+        }
+    }
+
+    boolean isCdmaEri() {
+        final int iconIndex = mServiceState.getCdmaEriIconIndex();
+        if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+            final int iconMode = mServiceState.getCdmaEriIconMode();
+            if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                    || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private final void updateDataIcon() {
+        int iconId;
+        boolean visible = true;
+
+        if (!isCdma()) {
+            // GSM case, we have to check also the sim state
+            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
+                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                    switch (mDataActivity) {
+                        case TelephonyManager.DATA_ACTIVITY_IN:
+                            iconId = mDataIconList[1];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_OUT:
+                            iconId = mDataIconList[2];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_INOUT:
+                            iconId = mDataIconList[3];
+                            break;
+                        default:
+                            iconId = mDataIconList[0];
+                            break;
+                    }
+                    mDataIconId = iconId;
+                } else {
+                    iconId = 0;
+                    visible = false;
+                }
+            } else {
+                iconId = R.drawable.stat_sys_no_sim;
+            }
+        } else {
+            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        iconId = mDataIconList[1];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        iconId = mDataIconList[2];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        iconId = mDataIconList[3];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                    default:
+                        iconId = mDataIconList[0];
+                        break;
+                }
+            } else {
+                iconId = 0;
+                visible = false;
+            }
+        }
+
+        // yuck - this should NOT be done by the status bar
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        mDataIconId = iconId;
+        mDataConnected = visible;
+    }
+
+    // ===== Wifi ===================================================================
+
+    private void updateWifiState(Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
+                || action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
+            final NetworkInfo networkInfo = (NetworkInfo)
+                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+            boolean wasConnected = mWifiConnected;
+            mWifiConnected = networkInfo != null && networkInfo.isConnected();
+            // If we just connected, grab the inintial signal strength and ssid
+            if (mWifiConnected && !wasConnected) {
+                WifiInfo info = mWifiManager.getConnectionInfo();
+                if (info != null) {
+                    mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(),
+                            WifiIcons.WIFI_LEVEL_COUNT);
+                    mWifiSsid = huntForSsid(info);
+                } else {
+                    mWifiLevel = 0;
+                    mWifiSsid = null;
+                }
+            } else if (!mWifiConnected) {
+                mWifiLevel = 0;
+                mWifiSsid = null;
+            }
+
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            if (mWifiConnected) {
+                final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+                mWifiLevel = WifiManager.calculateSignalLevel(newRssi, WifiIcons.WIFI_LEVEL_COUNT);
+            }
+        }
+
+        updateWifiIcons();
+    }
+
+    private void updateWifiIcons() {
+        if (mWifiConnected) {
+            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+        } else {
+            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[0][0];
+        }
+    }
+
+    private String huntForSsid(WifiInfo info) {
+        String ssid = info.getSSID();
+        if (ssid != null) {
+            return ssid;
+        }
+        // OK, it's not in the connectionInfo; we have to go hunting for it
+        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+        for (WifiConfiguration net : networks) {
+            if (net.networkId == info.getNetworkId()) {
+                return net.SSID;
+            }
+        }
+        return null;
+    }
+
+
+    // ===== Full or limited Internet connectivity ==================================
+
+    private void updateConnectivity(Intent intent) {
+        NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
+                ConnectivityManager.EXTRA_NETWORK_INFO));
+        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+
+        int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+
+        switch (info.getType()) {
+            case ConnectivityManager.TYPE_MOBILE:
+                mInetCondition = inetCondition;
+                updateDataNetType(info.getSubtype());
+                updateDataIcon();
+                updateTelephonySignalStrength(); // apply any change in connectionStatus
+                break;
+            case ConnectivityManager.TYPE_WIFI:
+                mInetCondition = inetCondition;
+                updateWifiIcons();
+                break;
+        }
+    }
+
+
+    // ===== Update the views =======================================================
+
+    // figure out what to show: first wifi, then 3G, then nothing
+    void refreshViews() {
+        Context context = mContext;
+
+        int combinedDataIconId;
+        String label;
+
+        if (mWifiConnected) {
+            if (mWifiSsid == null) {
+                label = context.getString(R.string.system_panel_signal_meter_wifi_nossid);
+            } else {
+                label = context.getString(R.string.system_panel_signal_meter_wifi_ssid_format,
+                                      mWifiSsid);
+            }
+            combinedDataIconId = mWifiIconId;
+        } else if (mDataConnected) {
+            label = context.getString(R.string.system_panel_signal_meter_data_connected);
+            combinedDataIconId = mDataIconId;
+        } else {
+            label = context.getString(R.string.system_panel_signal_meter_disconnected);
+            combinedDataIconId = 0;
+        }
+
+        int N;
+
+        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
+            mLastPhoneSignalIconId = mPhoneSignalIconId;
+            N = mPhoneIconViews.size();
+            for (int i=0; i<N; i++) {
+                ImageView v = mPhoneIconViews.get(i);
+                v.setImageResource(mPhoneSignalIconId);
+            }
+        }
+
+        if (mLastCombinedDataIconId != combinedDataIconId) {
+            mLastCombinedDataIconId = combinedDataIconId;
+            N = mDataIconViews.size();
+            for (int i=0; i<N; i++) {
+                ImageView v = mDataIconViews.get(i);
+                v.setImageResource(combinedDataIconId);
+            }
+        }
+
+        if (!mLastLabel.equals(label)) {
+            mLastLabel = label;
+            N = mLabelViews.size();
+            for (int i=0; i<N; i++) {
+                TextView v = mLabelViews.get(i);
+                v.setText(label);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
new file mode 100644
index 0000000..050a746
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar.policy;
+
+import com.android.systemui.R;
+
+class TelephonyIcons {
+    //***** Signal strength icons
+
+    //GSM/UMTS
+    static final int[][] TELEPHONY_SIGNAL_STRENGTH = {
+        { R.drawable.stat_sys_signal_0,
+          R.drawable.stat_sys_signal_1,
+          R.drawable.stat_sys_signal_2,
+          R.drawable.stat_sys_signal_3,
+          R.drawable.stat_sys_signal_4 },
+        { R.drawable.stat_sys_signal_0_fully,
+          R.drawable.stat_sys_signal_1_fully,
+          R.drawable.stat_sys_signal_2_fully,
+          R.drawable.stat_sys_signal_3_fully,
+          R.drawable.stat_sys_signal_4_fully }
+    };
+
+    static final int[][] TELEPHONY_SIGNAL_STRENGTH_ROAMING = {
+        { R.drawable.stat_sys_r_signal_0,
+          R.drawable.stat_sys_r_signal_1,
+          R.drawable.stat_sys_r_signal_2,
+          R.drawable.stat_sys_r_signal_3,
+          R.drawable.stat_sys_r_signal_4 },
+        { R.drawable.stat_sys_r_signal_0_fully,
+          R.drawable.stat_sys_r_signal_1_fully,
+          R.drawable.stat_sys_r_signal_2_fully,
+          R.drawable.stat_sys_r_signal_3_fully,
+          R.drawable.stat_sys_r_signal_4_fully }
+    };
+
+    //***** Data connection icons
+
+    //GSM/UMTS
+    static final int[][] DATA_G = {
+            { R.drawable.stat_sys_data_connected_g,
+              R.drawable.stat_sys_data_in_g,
+              R.drawable.stat_sys_data_out_g,
+              R.drawable.stat_sys_data_inandout_g },
+            { R.drawable.stat_sys_data_fully_connected_g,
+              R.drawable.stat_sys_data_fully_in_g,
+              R.drawable.stat_sys_data_fully_out_g,
+              R.drawable.stat_sys_data_fully_inandout_g }
+        };
+
+    static final int[][] DATA_3G = {
+            { R.drawable.stat_sys_data_connected_3g,
+              R.drawable.stat_sys_data_in_3g,
+              R.drawable.stat_sys_data_out_3g,
+              R.drawable.stat_sys_data_inandout_3g },
+            { R.drawable.stat_sys_data_fully_connected_3g,
+              R.drawable.stat_sys_data_fully_in_3g,
+              R.drawable.stat_sys_data_fully_out_3g,
+              R.drawable.stat_sys_data_fully_inandout_3g }
+        };
+
+    static final int[][] DATA_E = {
+            { R.drawable.stat_sys_data_connected_e,
+              R.drawable.stat_sys_data_in_e,
+              R.drawable.stat_sys_data_out_e,
+              R.drawable.stat_sys_data_inandout_e },
+            { R.drawable.stat_sys_data_fully_connected_e,
+              R.drawable.stat_sys_data_fully_in_e,
+              R.drawable.stat_sys_data_fully_out_e,
+              R.drawable.stat_sys_data_fully_inandout_e }
+        };
+
+    //3.5G
+    static final int[][] DATA_H = {
+            { R.drawable.stat_sys_data_connected_h,
+              R.drawable.stat_sys_data_in_h,
+              R.drawable.stat_sys_data_out_h,
+              R.drawable.stat_sys_data_inandout_h },
+            { R.drawable.stat_sys_data_fully_connected_h,
+              R.drawable.stat_sys_data_fully_in_h,
+              R.drawable.stat_sys_data_fully_out_h,
+              R.drawable.stat_sys_data_fully_inandout_h }
+    };
+
+    //CDMA
+    // Use 3G icons for EVDO data and 1x icons for 1XRTT data
+    static final int[][] DATA_1X = {
+            { R.drawable.stat_sys_data_connected_1x,
+              R.drawable.stat_sys_data_in_1x,
+              R.drawable.stat_sys_data_out_1x,
+              R.drawable.stat_sys_data_inandout_1x },
+            { R.drawable.stat_sys_data_fully_connected_1x,
+              R.drawable.stat_sys_data_fully_in_1x,
+              R.drawable.stat_sys_data_fully_out_1x,
+              R.drawable.stat_sys_data_fully_inandout_1x }
+            };
+
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
new file mode 100644
index 0000000..0787289
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar.policy;
+
+import com.android.systemui.R;
+
+class WifiIcons {
+    static final int[][] WIFI_SIGNAL_STRENGTH = {
+            { R.drawable.stat_sys_wifi_signal_1,
+              R.drawable.stat_sys_wifi_signal_2,
+              R.drawable.stat_sys_wifi_signal_3,
+              R.drawable.stat_sys_wifi_signal_4 },
+            { R.drawable.stat_sys_wifi_signal_1_fully,
+              R.drawable.stat_sys_wifi_signal_2_fully,
+              R.drawable.stat_sys_wifi_signal_3_fully,
+              R.drawable.stat_sys_wifi_signal_4_fully }
+        };
+
+    static final int WIFI_LEVEL_COUNT = WIFI_SIGNAL_STRENGTH[0].length;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index eee0a16..ce81fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -17,10 +17,25 @@
 package com.android.systemui.statusbar.tablet;
 
 import android.content.Context;
-import android.widget.LinearLayout;
 import android.util.AttributeSet;
+import android.util.Slog;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.view.View;
+import android.widget.FrameLayout;
 
-public class NotificationPanel extends LinearLayout implements StatusBarPanel {
+import com.android.systemui.R;
+
+public class NotificationPanel extends RelativeLayout implements StatusBarPanel,
+        View.OnClickListener {
+    static final String TAG = "NotificationPanel";
+
+    View mSettingsButton;
+    View mNotificationButton;
+    View mNotificationScroller;
+    FrameLayout mSettingsFrame;
+    View mSettingsPanel;
 
     public NotificationPanel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -30,6 +45,51 @@
         super(context, attrs, defStyle);
     }
 
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+
+        mSettingsButton = (ImageView)findViewById(R.id.settings_button);
+        mSettingsButton.setOnClickListener(this);
+        mNotificationButton = (ImageView)findViewById(R.id.notification_button);
+        mNotificationButton.setOnClickListener(this);
+
+        mNotificationScroller = findViewById(R.id.notificationScroller);
+        mSettingsFrame = (FrameLayout)findViewById(R.id.settings_frame);
+    }
+
+    @Override
+    public void onVisibilityChanged(View v, int vis) {
+        super.onVisibilityChanged(v, vis);
+        // when we hide, put back the notifications
+        if (!isShown()) {
+            switchToNotificationMode();
+        }
+    }
+
+    public void onClick(View v) {
+        if (v == mSettingsButton) {
+            switchToSettingsMode();
+        } else if (v == mNotificationButton) {
+            switchToNotificationMode();
+        }
+    }
+
+    public void switchToSettingsMode() {
+        removeSettingsPanel();
+        addSettingsPanel();
+        mSettingsButton.setVisibility(View.INVISIBLE);
+        mNotificationScroller.setVisibility(View.GONE);
+        mNotificationButton.setVisibility(View.VISIBLE);
+    }
+
+    public void switchToNotificationMode() {
+        removeSettingsPanel();
+        mSettingsButton.setVisibility(View.VISIBLE);
+        mNotificationScroller.setVisibility(View.VISIBLE);
+        mNotificationButton.setVisibility(View.INVISIBLE);
+    }
+
     public boolean isInContentArea(int x, int y) {
         final int l = getPaddingLeft();
         final int r = getWidth() - getPaddingRight();
@@ -37,5 +97,16 @@
         final int b = getHeight() - getPaddingBottom();
         return x >= l && x < r && y >= t && y < b;
     }
+
+    void removeSettingsPanel() {
+        if (mSettingsPanel != null) {
+            mSettingsFrame.removeViewAt(0);
+            mSettingsPanel = null;
+        }
+    }
+
+    void addSettingsPanel() {
+        mSettingsPanel = View.inflate(getContext(), R.layout.sysbar_panel_settings, mSettingsFrame);
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
new file mode 100644
index 0000000..744f667
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+
+public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel {
+    public NotificationPeekPanel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationPeekPanel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public boolean isInContentArea(int x, int y) {
+        final int l = getPaddingLeft();
+        final int r = getWidth() - getPaddingRight();
+        final int t = getPaddingTop();
+        final int b = getHeight() - getPaddingBottom();
+        return x >= l && x < r && y >= t && y < b;
+    }
+
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index 1831eda..e0b05f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -20,6 +20,8 @@
 import java.util.List;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
 import android.app.IThumbnailReceiver;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
@@ -43,11 +45,11 @@
 
 public class RecentAppsPanel extends LinearLayout implements StatusBarPanel, OnClickListener {
     private static final String TAG = "RecentAppsPanel";
-    private static final boolean DEBUG = TabletStatusBarService.DEBUG;
+    private static final boolean DEBUG = TabletStatusBar.DEBUG;
     private static final int DISPLAY_TASKS = 4; // number of recent tasks to display
     private static final int MAX_TASKS = 2 * DISPLAY_TASKS; // give some slack for non-apps
     private static final boolean DBG = true;
-    private TabletStatusBarService mBar;
+    private TabletStatusBar mBar;
     private TextView mNoRecents;
     private LinearLayout mRecentsContainer;
     private ArrayList<ActivityDescription> mActivityDescriptions;
@@ -98,7 +100,7 @@
         return x >= l && x < r && y >= t && y < b;
     }
 
-    public void setBar(TabletStatusBarService bar) {
+    public void setBar(TabletStatusBar bar) {
         mBar = bar;
     }
 
@@ -236,7 +238,7 @@
             appIcon.setImageDrawable(activityDescription.icon);
             appDescription.setText(activityDescription.label);
             view.setOnClickListener(this);
-            view.setTag(activityDescription.intent);
+            view.setTag(activityDescription);
             Log.v(TAG, "Adding task: " + activityDescription.label);
             mRecentsContainer.addView(view);
         }
@@ -247,9 +249,19 @@
     }
 
     public void onClick(View v) {
-        Intent intent = (Intent) v.getTag();
-        if (DEBUG) Log.v(TAG, "Starting activity " + intent);
-        getContext().startActivity(intent);
+        ActivityDescription ad = (ActivityDescription)v.getTag();
+        if (ad.id >= 0) {
+            // This is an active task; it should just go to the foreground.
+            IActivityManager am = ActivityManagerNative.getDefault();
+            try {
+                am.moveTaskToFront(ad.id);
+            } catch (RemoteException e) {
+            }
+        } else {
+            Intent intent = ad.intent;
+            if (DEBUG) Log.v(TAG, "Starting activity " + intent);
+            getContext().startActivity(intent);
+        }
         mBar.animateCollapse();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java
new file mode 100644
index 0000000..9013f5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java
@@ -0,0 +1,38 @@
+/*
+ * 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.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.widget.LinearLayout;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public class SettingsPanel extends LinearLayout {
+    static final String TAG = "SettingsPanel";
+
+    public SettingsPanel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SettingsPanel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index 09c8cd2..0cb9249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -206,7 +206,7 @@
 //        lp.x = pos[1];
 //        lp.y = 0;
         lp.setTitle("ShirtPocket");
-        lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
+        lp.windowAnimations = R.style.Animation_ShirtPocketPanel;
 
         WindowManagerImpl.getDefault().addView(mWindow, lp);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
index c9a8d56..41b44c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SystemPanel.java
@@ -16,60 +16,31 @@
 
 package com.android.systemui.statusbar.tablet;
 
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.location.LocationManager;
 import android.media.AudioManager;
-import android.net.NetworkInfo;
-import android.net.wifi.SupplicantState;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.IBinder;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
 import android.os.IPowerManager;
-import android.os.Message;
-import android.os.RemoteException;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Slog;
-import android.view.Gravity;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
-import android.widget.Button;
 import android.widget.ImageButton;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextSwitcher;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.util.List;
-
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.EriInfo;
@@ -82,14 +53,13 @@
 
 public class SystemPanel extends LinearLayout implements StatusBarPanel {
     private static final String TAG = "SystemPanel";
-    private static final boolean DEBUG = TabletStatusBarService.DEBUG;
-    private static final boolean DEBUG_SIGNAL = false;
+    private static final boolean DEBUG = TabletStatusBar.DEBUG;
 
     private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 5;
     private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
     private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
 
-    private TabletStatusBarService mBar;
+    private TabletStatusBar mBar;
     private boolean mAirplaneMode;
 
     private ImageButton mBrightnessButton;
@@ -99,34 +69,11 @@
     private ImageButton mGpsButton;
     private ImageButton mBluetoothButton;
 
-    private ImageView mBatteryMeter;
-    private ImageView mSignalMeter;
-
-    private TextView mBatteryText;
-    private TextView mSignalText;
-
     private final IWindowManager mWM;
 
     private final AudioManager mAudioManager;
-    private final WifiManager mWifiManager;
-    private final TelephonyManager mPhone;
     private final BluetoothAdapter mBluetoothAdapter;
 
-    // state trackers for telephony code
-    IccCard.State mSimState = IccCard.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-
-    // state for the meters
-    boolean mWifiEnabled, mWifiConnected;
-    int mWifiLevel;
-    String mWifiSsid;
-
-    boolean mDataEnabled, mDataConnected, mDataRoaming;
-    int mDataLevel;
-
     public boolean isInContentArea(int x, int y) {
         final int l = getPaddingLeft();
         final int r = getWidth() - getPaddingRight();
@@ -141,260 +88,16 @@
             final String action = intent.getAction();
             if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
                 refreshSound();
-            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                updateBattery(intent);
-            } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
-                    || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
-                    || action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)
-                    || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                updateWifiState(intent);
-            } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-                updateSimState(intent);
             } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                 refreshBluetooth();
             }
         }
     };
 
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
-        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCard.State.ABSENT;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCard.State.READY;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
-            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCard.State.PIN_REQUIRED;
-            }
-            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCard.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCard.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCard.State.UNKNOWN;
-        }
-        updateDataState();
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    private boolean isEvdo() {
-        return ( (mServiceState != null)
-                 && ((mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
-    }
-
-    private boolean hasService() {
-        if (mServiceState != null) {
-            switch (mServiceState.getState()) {
-                case ServiceState.STATE_OUT_OF_SERVICE:
-                case ServiceState.STATE_POWER_OFF:
-                    return false;
-                default:
-                    return true;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    private int getCdmaLevel() {
-        if (mSignalStrength == null) return 0;
-        final int cdmaDbm = mSignalStrength.getCdmaDbm();
-        final int cdmaEcio = mSignalStrength.getCdmaEcio();
-        int levelDbm = 0;
-        int levelEcio = 0;
-
-        if (cdmaDbm >= -75) levelDbm = 4;
-        else if (cdmaDbm >= -85) levelDbm = 3;
-        else if (cdmaDbm >= -95) levelDbm = 2;
-        else if (cdmaDbm >= -100) levelDbm = 1;
-        else levelDbm = 0;
-
-        // Ec/Io are in dB*10
-        if (cdmaEcio >= -90) levelEcio = 4;
-        else if (cdmaEcio >= -110) levelEcio = 3;
-        else if (cdmaEcio >= -130) levelEcio = 2;
-        else if (cdmaEcio >= -150) levelEcio = 1;
-        else levelEcio = 0;
-
-        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
-    }
-
-    private int getEvdoLevel() {
-        if (mSignalStrength == null) return 0;
-        int evdoDbm = mSignalStrength.getEvdoDbm();
-        int evdoSnr = mSignalStrength.getEvdoSnr();
-        int levelEvdoDbm = 0;
-        int levelEvdoSnr = 0;
-
-        if (evdoDbm >= -65) levelEvdoDbm = 4;
-        else if (evdoDbm >= -75) levelEvdoDbm = 3;
-        else if (evdoDbm >= -90) levelEvdoDbm = 2;
-        else if (evdoDbm >= -105) levelEvdoDbm = 1;
-        else levelEvdoDbm = 0;
-
-        if (evdoSnr >= 7) levelEvdoSnr = 4;
-        else if (evdoSnr >= 5) levelEvdoSnr = 3;
-        else if (evdoSnr >= 3) levelEvdoSnr = 2;
-        else if (evdoSnr >= 1) levelEvdoSnr = 1;
-        else levelEvdoSnr = 0;
-
-        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-    }
-
-    private void updateDataState() {
-        mDataConnected = hasService() && (mDataState == TelephonyManager.DATA_CONNECTED);
-
-        if (isCdma()) {
-            // these functions return a value from 0 to 4, inclusive
-            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
-                mDataLevel = getEvdoLevel() * 25;
-            } else {
-                mDataLevel = getCdmaLevel() * 25;
-            }
-        } else {
-            // GSM
-            
-            int asu = (mSignalStrength == null) ? 0 : mSignalStrength.getGsmSignalStrength();
-
-            // asu on [0,31]; 99 = unknown
-            // Android has historically shown anything >=12 as "full"
-            // XXX: tune this based on Industry Best Practices(TM)
-            if (asu <= 2 || asu == 99) mDataLevel = 0;
-            else mDataLevel = (int)(((float)Math.max(asu, 15) / 15) * 100);
-
-            mDataRoaming = mPhone.isNetworkRoaming();
-
-            mDataConnected = mDataConnected
-                && (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN);
-        }
-
-        if (DEBUG_SIGNAL || DEBUG) {
-            Slog.d(TAG, "updateDataState: connected=" + mDataConnected 
-                    + " level=" + mDataLevel
-                    + " isEvdo=" + isEvdo()
-                    + " isCdma=" + isCdma()
-                    + " mPhoneState=" + mPhoneState
-                    + " mDataState=" + mDataState
-                    );
-        }
-
-        refreshSignalMeters();
-    }
-
-    private void updateWifiState(Intent intent) {
-        if (DEBUG)
-            Slog.d(TAG, "updateWifiState: " + intent);
-
-        final String action = intent.getAction();
-        final boolean wasConnected = mWifiConnected;
-
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            final NetworkInfo networkInfo = (NetworkInfo)
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-            mWifiConnected = networkInfo != null && networkInfo.isConnected();
-        } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
-            final NetworkInfo.DetailedState detailedState = WifiInfo.getDetailedStateOf(
-                    (SupplicantState)intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE));
-            mWifiConnected = detailedState == NetworkInfo.DetailedState.CONNECTED;
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 101);
-            mWifiLevel = mWifiConnected ? newSignalLevel : 0;
-        }
-
-        if (mWifiConnected && !wasConnected) {
-            WifiInfo info = mWifiManager.getConnectionInfo();
-            if (DEBUG)
-                Slog.d(TAG, "updateWifiState: just connected: info=" + info);
-
-            if (info != null) {
-                // grab the initial signal strength
-                mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(), 101);
-
-                // find the SSID
-                mWifiSsid = info.getSSID();
-                if (mWifiSsid == null) {
-                    // OK, it's not in the connectionInfo; we have to go hunting for it
-                    List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
-                    for (WifiConfiguration net : networks) {
-                        if (net.networkId == info.getNetworkId()) {
-                            mWifiSsid = net.SSID;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        refreshSignalMeters();
-    }
-
-    // figure out what to show: first wifi, then 3G, then nothing
-    void refreshSignalMeters() {
-        if (mSignalMeter == null) return; // no UI yet
-
-        Context ctxt = getContext();
-
-        String text = null;
-        int level = 0;
-
-        if (mWifiConnected) {
-            if (mWifiSsid == null) {
-                text = ctxt.getString(R.string.system_panel_signal_meter_wifi_nossid);
-            } else {
-                text = ctxt.getString(R.string.system_panel_signal_meter_wifi_ssid_format,
-                                      mWifiSsid);
-            }
-            level = mWifiLevel;
-        } else if (mDataConnected) {
-            text = ctxt.getString(R.string.system_panel_signal_meter_data_connected);
-            level = mDataLevel;
-        } else {
-            text = ctxt.getString(R.string.system_panel_signal_meter_disconnected);
-            level = 0;
-        }
-
-        mSignalMeter.setImageResource(R.drawable.sysbar_signal);
-        mSignalMeter.setImageLevel(level);
-        mSignalText.setText(text);
-
-        // hack for now
-        mBar.setSignalMeter(level, mWifiConnected);
-    }
-
-    public void setBar(TabletStatusBarService bar) {
+    public void setBar(TabletStatusBar bar) {
         mBar = bar;
     }
 
-    public void updateBattery(Intent intent) {
-        final int level = intent.getIntExtra("level", 0);
-        final boolean plugged = intent.getIntExtra("plugged", 0) != 0;
-
-        mBatteryMeter.setImageResource(R.drawable.sysbar_battery);
-        mBatteryMeter.setImageLevel(level);
-        mBatteryText.setText(getContext()
-                .getString(R.string.system_panel_battery_meter_format, level));
-
-        // hack for now
-        mBar.setBatteryMeter(level, plugged);
-    }
-    
     public SystemPanel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -406,34 +109,14 @@
         mWM = IWindowManager.Stub.asInterface(
                     ServiceManager.getService("window"));
 
-
-        // get notified of phone state changes
-        TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        telephonyManager.listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-
-        // wifi status info
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        
         // audio status 
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
 
-        // mobile data 
-        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-
         // Bluetooth
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
     }
 
     public void onAttachedToWindow() {
-        DateView date = (DateView)findViewById(R.id.date);
-        date.setUpdates(true);
-
         TextView settingsButton = (TextView)findViewById(R.id.settings_button);
         settingsButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
@@ -508,26 +191,9 @@
         // register for broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
         getContext().registerReceiver(mReceiver, filter);
         
-        mBatteryMeter = (ImageView)findViewById(R.id.battery_meter);
-        mBatteryMeter.setImageResource(R.drawable.sysbar_battery);
-        mBatteryMeter.setImageLevel(0);
-        mSignalMeter = (ImageView)findViewById(R.id.signal_meter);
-        mBatteryMeter.setImageResource(R.drawable.sysbar_signal);
-        mBatteryMeter.setImageLevel(0);
-
-        mBatteryText = (TextView)findViewById(R.id.battery_info);
-        mSignalText = (TextView)findViewById(R.id.signal_info);
-
-        refreshSignalMeters();
         refreshBluetooth();
         refreshGps();
     }
@@ -615,10 +281,9 @@
     PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
         public void onServiceStateChanged(ServiceState serviceState) {
-            if (DEBUG_SIGNAL || DEBUG) {
+            if (DEBUG) {
                 Slog.d(TAG, "phone service state changed: " + serviceState.getState());
             }
-            mServiceState = serviceState;
             mAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
             if (mAirplaneButton != null) {
                 mAirplaneButton.setImageResource(mAirplaneMode 
@@ -628,34 +293,6 @@
                                                  ? R.drawable.sysbar_toggle_bg_on
                                                  : R.drawable.sysbar_toggle_bg_off);
             }
-            updateDataState();
-        }
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            if (DEBUG_SIGNAL || DEBUG) {
-                Slog.d(TAG, "onSignalStrengthsChanged: " + signalStrength);
-            }
-            mSignalStrength = signalStrength;
-            updateDataState();
-        }
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            mPhoneState = state;
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateDataState();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            if (DEBUG_SIGNAL || DEBUG) {
-                Slog.d(TAG, "onDataConnectionStateChanged: state=" + state 
-                        + " type=" + networkType);
-            }
-            mDataState = state;
-//            updateDataNetType(networkType);
-            updateDataState();
         }
     };
 
@@ -745,7 +382,7 @@
             } else {
                 mWM.freezeRotation();
             }
-        } catch (android.os.RemoteException exc) {
+        } catch (RemoteException exc) {
         }
     }
 
@@ -759,7 +396,7 @@
     int getDisplayRotation() {
         try {
             return mWM.getRotation();
-        } catch (android.os.RemoteException exc) {
+        } catch (RemoteException exc) {
             return 0;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
similarity index 78%
rename from packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index da44f43..983215e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -59,20 +59,20 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 
-import com.android.systemui.statusbar.*;
-import com.android.systemui.recent.RecentApplicationsActivity;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.*;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.recent.RecentApplicationsActivity;
 
-public class TabletStatusBarService extends StatusBarService {
+public class TabletStatusBar extends StatusBar {
     public static final boolean DEBUG = false;
-    public static final String TAG = "TabletStatusBarService";
+    public static final String TAG = "TabletStatusBar";
 
     public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
     public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
     public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002;
     public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003;
-    public static final int MSG_OPEN_SYSTEM_PANEL = 1010;
-    public static final int MSG_CLOSE_SYSTEM_PANEL = 1011;
     public static final int MSG_OPEN_RECENTS_PANEL = 1020;
     public static final int MSG_CLOSE_RECENTS_PANEL = 1021;
     public static final int MSG_LIGHTS_ON = 1030;
@@ -89,10 +89,9 @@
     private NotificationData mNotns = new NotificationData();
 
     TabletStatusBarView mStatusBarView;
-    ImageView mNotificationTrigger;
+    View mNotificationArea;
+    View mNotificationTrigger;
     NotificationIconArea mNotificationIconArea;
-    View mNotificationButtons;
-    View mSystemInfo;
     View mNavigationArea;
     View mMenuButton;
     View mRecentButton;
@@ -100,8 +99,7 @@
     InputMethodButton mInputMethodButton;
 
     NotificationPanel mNotificationPanel;
-    SystemPanel mSystemPanel;
-    NotificationPanel mNotificationPeekWindow;
+    NotificationPeekPanel mNotificationPeekWindow;
     ViewGroup mNotificationPeekRow;
     int mNotificationPeekIndex;
     LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
@@ -110,12 +108,9 @@
     int mNotificationFlingVelocity;
 
     ViewGroup mPile;
-    TextView mClearButton;
-    TextView mDoNotDisturbButton;
 
-    ImageView mBatteryMeter;
-    ImageView mSignalMeter;
-    ImageView mSignalIcon;
+    BatteryController mBatteryController;
+    NetworkController mNetworkController;
 
     View mBarContents;
     View mCurtains;
@@ -146,6 +141,15 @@
         mNotificationPanel.setOnTouchListener(
                 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel));
 
+        // the battery and network icons
+        mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery));
+        mBatteryController.addLabelView(
+                (TextView)mNotificationPanel.findViewById(R.id.battery_text));
+        mNetworkController.addCombinedDataIconView(
+                (ImageView)mNotificationPanel.findViewById(R.id.network));
+        mNetworkController.addLabelView(
+                (TextView)mNotificationPanel.findViewById(R.id.network_text));
+
         mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
 
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -158,12 +162,11 @@
                 PixelFormat.TRANSLUCENT);
         lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
         lp.setTitle("NotificationPanel");
-        lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
 
         WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
 
         // Notification preview window
-        mNotificationPeekWindow = (NotificationPanel) View.inflate(context,
+        mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context,
                 R.layout.sysbar_panel_notification_peek, null);
         mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content);
         mNotificationPeekWindow.setVisibility(View.GONE);
@@ -198,29 +201,6 @@
 
         WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
 
-        // System Panel
-        mSystemPanel = (SystemPanel) View.inflate(context, R.layout.sysbar_panel_system, null);
-        mSystemPanel.setVisibility(View.GONE);
-        mSystemPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_SYSTEM_PANEL,
-                mSystemPanel));
-        mStatusBarView.setIgnoreChildren(1, mSystemInfo, mSystemPanel);
-
-        lp = new WindowManager.LayoutParams(
-                800,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-        lp.setTitle("SystemPanel");
-        lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
-
-        WindowManagerImpl.getDefault().addView(mSystemPanel, lp);
-        mSystemPanel.setBar(this);
-
-
         // Recents Panel
         if (USE_2D_RECENTS) {
             mRecentsPanel = (RecentAppsPanel) View.inflate(context, R.layout.sysbar_panel_recent,
@@ -240,7 +220,7 @@
                     PixelFormat.TRANSLUCENT);
             lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
             lp.setTitle("RecentsPanel");
-            lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
+            lp.windowAnimations = R.style.Animation_RecentPanel;
 
             WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
             mRecentsPanel.setBar(this);
@@ -266,10 +246,6 @@
 
         mBarContents = sb.findViewById(R.id.bar_contents);
         mCurtains = sb.findViewById(R.id.lights_out);
-        mSystemInfo = sb.findViewById(R.id.systemInfo);
-        mRecentButton = sb.findViewById(R.id.recent_apps);
-
-        mSystemInfo.setOnTouchListener(new ClockTouchListener());
 
         mRecentButton = sb.findViewById(R.id.recent_apps);
         mRecentButton.setOnClickListener(mOnClickListener);
@@ -278,20 +254,16 @@
         mCurtains.setOnClickListener(on);
         mCurtains.setOnLongClickListener(on);
 
+        // the whole right-hand side of the bar
+        mNotificationArea = sb.findViewById(R.id.notificationArea);
+
         // the button to open the notification area
-        mNotificationTrigger = (ImageView) sb.findViewById(R.id.notificationTrigger);
+        mNotificationTrigger = sb.findViewById(R.id.notificationTrigger);
         mNotificationTrigger.setOnClickListener(mOnClickListener);
 
         // the more notifications icon
         mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons);
 
-        // the clear and dnd buttons
-        mNotificationButtons = sb.findViewById(R.id.notificationButtons);
-        mClearButton = (TextView)mNotificationButtons.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mOnClickListener);
-        mDoNotDisturbButton = (TextView)mNotificationButtons.findViewById(R.id.do_not_disturb);
-        mDoNotDisturbButton.setOnClickListener(mOnClickListener);
-
         // where the icons go
         mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons);
         mIconLayout.setOnTouchListener(new NotificationIconTouchListener());
@@ -302,10 +274,11 @@
 
         mTicker = new TabletTicker(context, (FrameLayout)sb.findViewById(R.id.ticker));
 
-        // System info (center)
-        mBatteryMeter = (ImageView) sb.findViewById(R.id.battery);
-        mSignalMeter = (ImageView) sb.findViewById(R.id.signal);
-        mSignalIcon = (ImageView) sb.findViewById(R.id.signal_icon);
+        // The icons
+        mBatteryController = new BatteryController(mContext);
+        mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
+        mNetworkController = new NetworkController(mContext);
+        mNetworkController.addCombinedDataIconView((ImageView)sb.findViewById(R.id.network));
 
         // The navigation buttons
         mNavigationArea = sb.findViewById(R.id.navigationArea);
@@ -388,36 +361,17 @@
                     if (mNotificationPanel.getVisibility() == View.GONE) {
                         mNotificationPeekWindow.setVisibility(View.GONE);
 
-                        mDoNotDisturbButton.setText(mNotificationsOn
-                                ? R.string.status_bar_do_not_disturb_button
-                                : R.string.status_bar_please_disturb_button);
                         mNotificationPanel.setVisibility(View.VISIBLE);
-                        setViewVisibility(mNotificationIconArea, View.GONE,
-                                R.anim.notification_icons_out);
-                        setViewVisibility(mNotificationButtons, View.VISIBLE,
-                                R.anim.notification_buttons_in);
-                        refreshNotificationTrigger();
+                        mNotificationArea.setVisibility(View.GONE);
                     }
                     break;
                 case MSG_CLOSE_NOTIFICATION_PANEL:
                     if (DEBUG) Slog.d(TAG, "closing notifications panel");
                     if (mNotificationPanel.getVisibility() == View.VISIBLE) {
                         mNotificationPanel.setVisibility(View.GONE);
-                        setViewVisibility(mNotificationIconArea, View.VISIBLE,
-                                R.anim.notification_icons_in);
-                        setViewVisibility(mNotificationButtons, View.GONE,
-                                R.anim.notification_buttons_out);
-                        refreshNotificationTrigger();
+                        mNotificationArea.setVisibility(View.VISIBLE);
                     }
                     break;
-                case MSG_OPEN_SYSTEM_PANEL:
-                    if (DEBUG) Slog.d(TAG, "opening system panel");
-                    mSystemPanel.setVisibility(View.VISIBLE);
-                    break;
-                case MSG_CLOSE_SYSTEM_PANEL:
-                    if (DEBUG) Slog.d(TAG, "closing system panel");
-                    mSystemPanel.setVisibility(View.GONE);
-                    break;
                 case MSG_OPEN_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening recents panel");
                     if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.VISIBLE);
@@ -440,6 +394,7 @@
     }
 
     public void refreshNotificationTrigger() {
+        /*
         if (mNotificationTrigger == null) return;
 
         int resId;
@@ -452,29 +407,8 @@
         } else {
             resId = panel ? R.drawable.ic_sysbar_noti_none_open : R.drawable.ic_sysbar_noti_none;
         }
-        mNotificationTrigger.setImageResource(resId);
-    }
-
-    public void setBatteryMeter(int level, boolean plugged) {
-        if (DEBUG) Slog.d(TAG, "battery=" + level + (plugged ? " - plugged" : " - unplugged"));
-        mBatteryMeter.setImageResource(R.drawable.sysbar_batterymini);
-        // adjust percent to permyriad for ClipDrawable's sake
-        mBatteryMeter.setImageLevel(level * (MAX_IMAGE_LEVEL / 100));
-    }
-
-    public void setSignalMeter(int level, boolean isWifi) {
-        if (DEBUG) Slog.d(TAG, "signal=" + level);
-        if (level < 0) {
-            mSignalMeter.setImageDrawable(null);
-            mSignalMeter.setImageLevel(0);
-            mSignalIcon.setImageDrawable(null);
-        } else {
-            mSignalMeter.setImageResource(R.drawable.sysbar_wifimini);
-            // adjust to permyriad
-            mSignalMeter.setImageLevel(level * (MAX_IMAGE_LEVEL / 100));
-            mSignalIcon.setImageResource(isWifi ? R.drawable.ic_sysbar_wifi_mini
-                                                : R.drawable.ic_sysbar_wifi_mini); // XXX
-        }
+        //mNotificationTrigger.setImageResource(resId);
+        */
     }
 
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
@@ -599,9 +533,6 @@
     public void disable(int state) {
         int old = mDisabled;
         int diff = state ^ old;
-        Slog.d(TAG, "disable... old=0x" + Integer.toHexString(old)
-                + " diff=0x" + Integer.toHexString(diff)
-                + " state=0x" + Integer.toHexString(state));
         mDisabled = state;
 
         // act accordingly
@@ -614,39 +545,24 @@
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                setViewVisibility(mNotificationTrigger, View.GONE,
-                        R.anim.notification_icons_out);
-                setViewVisibility(mNotificationIconArea, View.GONE,
-                        R.anim.notification_icons_out);
+                mNotificationIconArea.setVisibility(View.GONE);
                 mTicker.halt();
             } else {
                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                setViewVisibility(mNotificationTrigger, View.VISIBLE,
-                        R.anim.notification_icons_in);
-                setViewVisibility(mNotificationIconArea, View.VISIBLE,
-                        R.anim.notification_icons_in);
+                mNotificationIconArea.setVisibility(View.VISIBLE);
             }
         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
                 mTicker.halt();
             }
         }
-        if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                Slog.d(TAG, "DISABLE_SYSTEM_INFO: yes");
-                setViewVisibility(mSystemInfo, View.GONE, R.anim.navigation_out);
-            } else {
-                Slog.d(TAG, "DISABLE_SYSTEM_INFO: no");
-                setViewVisibility(mSystemInfo, View.VISIBLE, R.anim.navigation_in);
-            }
-        }
         if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
             if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
                 Slog.d(TAG, "DISABLE_NAVIGATION: yes");
-                setViewVisibility(mNavigationArea, View.GONE, R.anim.navigation_out);
+                mNavigationArea.setVisibility(View.GONE);
             } else {
                 Slog.d(TAG, "DISABLE_NAVIGATION: no");
-                setViewVisibility(mNavigationArea, View.VISIBLE, R.anim.navigation_in);
+                mNavigationArea.setVisibility(View.VISIBLE);
             }
         }
     }
@@ -682,13 +598,11 @@
     public void animateCollapse() {
         mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL);
         mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
-        mHandler.removeMessages(MSG_CLOSE_SYSTEM_PANEL);
-        mHandler.sendEmptyMessage(MSG_CLOSE_SYSTEM_PANEL);
         mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
         mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
     }
 
-    // called by StatusBarService
+    // called by StatusBar
     @Override
     public void setLightsOn(boolean on) {
         mHandler.removeMessages(MSG_LIGHTS_OUT);
@@ -700,9 +614,7 @@
         if (DEBUG) {
             Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button");
         }
-        setViewVisibility(mMenuButton,
-                visible ? View.VISIBLE : View.INVISIBLE,
-                visible ? R.anim.navigation_in : R.anim.navigation_out);
+        mMenuButton.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
 
     public void setIMEButtonVisible(boolean visible) {
@@ -717,24 +629,6 @@
 
         //Slog.d(TAG, "setAreThereNotifications hasClerable=" + hasClearable);
 
-        // Show or hide the "Clear all" button.  Note that we don't do an animation
-        // if it's not on screen, so that if someone opens the bar right then they
-        // don't see the animation in progress.
-        // (no ongoing notifications are clearable)
-        if (hasClearable) {
-            if (mNotificationButtons.getVisibility() == View.VISIBLE) {
-                setViewVisibility(mClearButton, View.VISIBLE, R.anim.notification_buttons_in);
-            } else {
-                mClearButton.setVisibility(View.VISIBLE);
-            }
-        } else {
-            if (mNotificationButtons.getVisibility() == View.VISIBLE) {
-                setViewVisibility(mClearButton, View.GONE, R.anim.notification_buttons_out);
-            } else {
-                mClearButton.setVisibility(View.GONE);
-            }
-        }
-
         /*
         mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
         mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
@@ -759,55 +653,9 @@
         }
     }
 
-    private class ClockTouchListener implements View.OnTouchListener {
-        VelocityTracker mVT = null;
-        int mInitX, mInitY;
-        public boolean onTouch (View v, MotionEvent event) {
-            final int x = (int) event.getX();
-            final int y = (int) event.getY();
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mVT = VelocityTracker.obtain();
-                    mInitX = x;
-                    mInitY = y;
-                    mHandler.sendEmptyMessageDelayed(MSG_LIGHTS_OUT,
-                            ViewConfiguration.getLongPressTimeout());
-                    break;
-                case MotionEvent.ACTION_OUTSIDE:
-                case MotionEvent.ACTION_MOVE:
-                    final Rect r = new Rect();
-                    final float radius = mSystemInfo.getHeight() / 2;
-                    if (Math.abs(x - mInitX) > radius || Math.abs(y - mInitY) > radius) {
-                        mHandler.removeMessages(MSG_LIGHTS_OUT);
-                    }
-                    if (mVT == null) break;
-                    mVT.addMovement(event);
-                    mVT.computeCurrentVelocity(1000);
-                    if (mVT.getYVelocity() < -200 && mSystemPanel.getVisibility() == View.GONE) {
-                        mHandler.removeMessages(MSG_OPEN_SYSTEM_PANEL);
-                        mHandler.sendEmptyMessage(MSG_OPEN_SYSTEM_PANEL);
-                    } else if (mVT.getYVelocity() > 200) {
-                        mHandler.sendEmptyMessage(MSG_LIGHTS_OUT);
-                    }
-                    return true;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    mVT.recycle();
-                    mVT = null;
-                    mHandler.removeMessages(MSG_LIGHTS_OUT);
-                    return true;
-            }
-            return false;
-        }
-    }
-
     private View.OnClickListener mOnClickListener = new View.OnClickListener() {
         public void onClick(View v) {
-            if (v == mClearButton) {
-                onClickClearButton();
-            } else if (v == mDoNotDisturbButton) {
-                onClickDoNotDisturb();
-            } else if (v == mNotificationTrigger) {
+            if (v == mNotificationTrigger) {
                 onClickNotificationTrigger();
             } else if (v == mRecentButton) {
                 onClickRecentButton();
@@ -815,23 +663,6 @@
         }
     };
 
-    void onClickClearButton() {
-        try {
-            mBarService.onClearAllNotifications();
-        } catch (RemoteException ex) {
-            // system process is dead if we're here.
-        }
-        animateCollapse();
-        refreshNotificationTrigger();
-    }
-
-    void onClickDoNotDisturb() {
-        mNotificationsOn = !mNotificationsOn;
-        mIconLayout.setVisibility(mNotificationsOn ? View.VISIBLE : View.INVISIBLE); // TODO: animation
-        animateCollapse();
-        refreshNotificationTrigger();
-    }
-
     public void onClickNotificationTrigger() {
         if (DEBUG) Slog.d(TAG, "clicked notification icons");
         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
@@ -849,17 +680,6 @@
         }
     }
 
-    public void onClickSystemInfo() {
-        if (DEBUG) Slog.d(TAG, "clicked system info");
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
-            int msg = (mSystemPanel.getVisibility() == View.GONE)
-                ? MSG_OPEN_SYSTEM_PANEL
-                : MSG_CLOSE_SYSTEM_PANEL;
-            mHandler.removeMessages(msg);
-            mHandler.sendEmptyMessage(msg);
-        }
-    }
-
     public void onClickRecentButton() {
         if (DEBUG) Slog.d(TAG, "clicked recent apps");
         if (mRecentsPanel == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 15866fe..bd8266a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -40,12 +40,10 @@
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mHandler.removeMessages(TabletStatusBarService.MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_NOTIFICATION_PANEL);
-            mHandler.removeMessages(TabletStatusBarService.MSG_CLOSE_SYSTEM_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_SYSTEM_PANEL);
-            mHandler.removeMessages(TabletStatusBarService.MSG_CLOSE_RECENTS_PANEL);
-            mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_RECENTS_PANEL);
+            mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
+            mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_NOTIFICATION_PANEL);
+            mHandler.removeMessages(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
+            mHandler.sendEmptyMessage(TabletStatusBar.MSG_CLOSE_RECENTS_PANEL);
 
             for (int i=0; i < mPanels.length; i++) {
                 if (mPanels[i] != null && mPanels[i].getVisibility() == View.VISIBLE) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 71bf956..18815f5 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -37,9 +37,7 @@
 import com.android.internal.widget.ActionBarView;
 
 import android.app.KeyguardManager;
-import android.content.ActivityNotFoundException;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -51,7 +49,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.SystemClock;
 import android.util.AndroidRuntimeException;
 import android.util.Config;
 import android.util.EventLog;
@@ -60,6 +57,7 @@
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.Gravity;
+import android.view.HardwareRenderer;
 import android.view.InputQueue;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -72,14 +70,12 @@
 import android.view.ViewGroup;
 import android.view.ViewManager;
 import android.view.ViewStub;
-import android.view.VolumePanel;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.PopupWindow;
@@ -166,7 +162,6 @@
     private MenuDialogHelper mContextMenuHelper;
 
     private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
-    private long mVolumeKeyUpTime;
 
     private AudioManager mAudioManager;
     private KeyguardManager mKeyguardManager;
@@ -416,6 +411,8 @@
     public final void openPanel(int featureId, KeyEvent event) {
         if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
                 mActionBar.isOverflowReserved()) {
+            // Invalidate the options menu, we want a prepare event that the app can respond to.
+            invalidatePanelMenu(FEATURE_OPTIONS_PANEL);
             mActionBar.showOverflowMenu();
         } else {
             openPanel(getPanelState(featureId, true), event);
@@ -1835,7 +1832,12 @@
             }
 
             final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
-            ActionMode mode = getCallback().onStartActionMode(wrappedCallback);
+            ActionMode mode = null;
+            try {
+                mode = getCallback().onWindowStartingActionMode(wrappedCallback);
+            } catch (AbstractMethodError ame) {
+                // Older apps might not implement this callback method.
+            }
             if (mode != null) {
                 mActionMode = mode;
             } else {
@@ -1879,6 +1881,13 @@
                     }
                 }
             }
+            if (mActionMode != null) {
+                try {
+                    getCallback().onActionModeStarted(mActionMode);
+                } catch (AbstractMethodError ame) {
+                    // Older apps might not implement this callback method.
+                }
+            }
             return mActionMode;
         }
 
@@ -2094,6 +2103,11 @@
                 if (mActionModeView != null) {
                     mActionModeView.removeAllViews();
                 }
+                try {
+                    getCallback().onActionModeFinished(mActionMode);
+                } catch (AbstractMethodError ame) {
+                    // Older apps might not implement this callback method.
+                }
                 mActionMode = null;
             }
         }
@@ -2234,12 +2248,11 @@
             // XXX Remove this once action bar supports these features.
             removeFeature(FEATURE_ACTION_BAR);
             // System.out.println("Title Icons!");
-        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
+        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
+                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
             // Special case for a window with only a progress bar (and title).
             // XXX Need to have a no-title version of embedded windows.
             layoutResource = com.android.internal.R.layout.screen_progress;
-            // XXX Remove this once action bar supports these features.
-            removeFeature(FEATURE_ACTION_BAR);
             // System.out.println("Progress!");
         } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
             // Special case for a window with a custom title.
@@ -2352,6 +2365,13 @@
                     if (mActionBar.getTitle() == null) {
                         mActionBar.setWindowTitle(mTitle);
                     }
+                    final int localFeatures = getLocalFeatures();
+                    if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) {
+                        mActionBar.initProgress();
+                    }
+                    if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+                        mActionBar.initIndeterminateProgress();
+                    }
                     // Post the panel invalidate for later; avoid application onCreateOptionsMenu
                     // being called in the middle of onCreate or similar.
                     mDecor.post(new Runnable() {
@@ -2543,8 +2563,10 @@
         if (mContentParent == null && shouldInstallDecor) {
             installDecor();
         }
-        mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular);
-        mCircularProgressBar.setVisibility(View.INVISIBLE);
+        mCircularProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_circular);
+        if (mCircularProgressBar != null) {
+            mCircularProgressBar.setVisibility(View.INVISIBLE);
+        }
         return mCircularProgressBar;
     }
 
@@ -2555,8 +2577,10 @@
         if (mContentParent == null && shouldInstallDecor) {
             installDecor();
         }
-        mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal);
-        mHorizontalProgressBar.setVisibility(View.INVISIBLE);
+        mHorizontalProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_horizontal);
+        if (mHorizontalProgressBar != null) {
+            mHorizontalProgressBar.setVisibility(View.INVISIBLE);
+        }
         return mHorizontalProgressBar;
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 4bc7433..8c857da 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -117,7 +117,6 @@
 import android.media.IAudioService;
 import android.media.AudioManager;
 
-import java.io.File;
 import java.util.ArrayList;
 
 /**
@@ -962,7 +961,7 @@
     /** {@inheritDoc} */
     public View addStartingWindow(IBinder appToken, String packageName,
                                   int theme, CharSequence nonLocalizedLabel,
-                                  int labelRes, int icon) {
+                                  int labelRes, int icon, int windowFlags) {
         if (!SHOW_STARTING_ANIMATIONS) {
             return null;
         }
@@ -1006,9 +1005,11 @@
             // flag because we do know that the next window will take input
             // focus, so we want to get the IME window up on top of us right away.
             win.setFlags(
+                windowFlags|
                 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                windowFlags|
                 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
@@ -2304,12 +2305,8 @@
                     return getCurrentPortraitRotation(lastRotation);
             }
 
-            if (new File("/system/etc/allow_all_orientations").exists()) {
-                mOrientationListener.setAllow180Rotation(true);
-            } else {
-                mOrientationListener.setAllow180Rotation(
-                        orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
-            }
+            mOrientationListener.setAllow180Rotation(
+                    orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
 
             // case for nosensor meaning ignore sensor and consider only lid
             // or orientation sensor disabled
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index 9608b9a..d9e8c2b 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -17,7 +17,9 @@
 package com.android.internal.policy.impl;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
 import android.app.Dialog;
+import android.app.IActivityManager;
 import android.app.StatusBarManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -30,6 +32,8 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
 import android.util.Log;
 import android.view.View;
 import android.view.Window;
@@ -53,6 +57,22 @@
     View mNoAppsText;
     IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
 
+    class RecentTag {
+        ActivityManager.RecentTaskInfo info;
+        Intent intent;
+    }
+
+    Handler mHandler = new Handler();
+    Runnable mCleanup = new Runnable() {
+        public void run() {
+            // dump extra memory we're hanging on to
+            for (TextView icon: mIcons) {
+                icon.setCompoundDrawables(null, null, null, null);
+                icon.setTag(null);
+            }
+        }
+    };
+
     private int mIconSize;
 
     public RecentApplicationsDialog(Context context) {
@@ -115,12 +135,18 @@
 
         for (TextView b: mIcons) {
             if (b == v) {
-                // prepare a launch intent and send it
-                Intent intent = (Intent)b.getTag();
-                if (intent != null) {
-                    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+                RecentTag tag = (RecentTag)b.getTag();
+                if (tag.info.id >= 0) {
+                    // This is an active task; it should just go to the foreground.
+                    IActivityManager am = ActivityManagerNative.getDefault();
                     try {
-                        getContext().startActivity(intent);
+                        am.moveTaskToFront(tag.info.id);
+                    } catch (RemoteException e) {
+                    }
+                } else if (tag.intent != null) {
+                    tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+                    try {
+                        getContext().startActivity(tag.intent);
                     } catch (ActivityNotFoundException e) {
                         Log.w("Recent", "Unable to launch recent task", e);
                     }
@@ -144,6 +170,8 @@
 
         // receive broadcasts
         getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
+
+        mHandler.removeCallbacks(mCleanup);
     }
 
     /**
@@ -153,18 +181,14 @@
     public void onStop() {
         super.onStop();
 
-        // dump extra memory we're hanging on to
-        for (TextView icon: mIcons) {
-            icon.setCompoundDrawables(null, null, null, null);
-            icon.setTag(null);
-        }
-
         if (sStatusBar != null) {
             sStatusBar.disable(StatusBarManager.DISABLE_NONE);
         }
 
         // stop receiving broadcasts
         getContext().unregisterReceiver(mBroadcastReceiver);
+
+        mHandler.postDelayed(mCleanup, 100);
      }
 
     /**
@@ -224,7 +248,10 @@
                     tv.setText(title);
                     icon = iconUtilities.createIconDrawable(icon);
                     tv.setCompoundDrawables(null, icon, null, null);
-                    tv.setTag(intent);
+                    RecentTag tag = new RecentTag();
+                    tag.info = info;
+                    tag.intent = intent;
+                    tv.setTag(tag);
                     tv.setVisibility(View.VISIBLE);
                     tv.setPressed(false);
                     tv.clearFocus();
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 90ebf3f..6a86076 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -585,6 +585,7 @@
                     }
                 }
             }
+            tf.close();
         } catch (FileNotFoundException fnf) {
             // Probably innocuous
             Slog.v(TAG, "No ancestral data");
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1df4405..4f8862c 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -961,7 +961,12 @@
         // enabled.
         String id = Settings.Secure.getString(mContext.getContentResolver(),
                 Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (id != null && id.length() > 0) {
+        // There is no input method selected, try to choose new applicable input method.
+        if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
+            id = Settings.Secure.getString(mContext.getContentResolver(),
+                    Settings.Secure.DEFAULT_INPUT_METHOD);
+        }
+        if (!TextUtils.isEmpty(id)) {
             try {
                 setInputMethodLocked(id, getSelectedInputMethodSubtypeId(id));
             } catch (IllegalArgumentException e) {
@@ -983,8 +988,9 @@
         }
 
         if (id.equals(mCurMethodId)) {
-            if (subtypeId != NOT_A_SUBTYPE_ID) {
-                InputMethodSubtype subtype = info.getSubtypes().get(subtypeId);
+            ArrayList<InputMethodSubtype> subtypes = info.getSubtypes();
+            if (subtypeId >= 0 && subtypeId < subtypes.size()) {
+                InputMethodSubtype subtype = subtypes.get(subtypeId);
                 if (subtype != mCurrentSubtype) {
                     synchronized (mMethodMap) {
                         if (mCurMethod != null) {
@@ -1497,6 +1503,9 @@
                 }
             }
             InputMethodInfo imi = enabled.get(i);
+            if (DEBUG) {
+                Slog.d(TAG, "New default IME was selected: " + imi.getId());
+            }
             resetSelectedInputMethodAndSubtypeLocked(imi.getId());
             return true;
         }
@@ -1800,9 +1809,9 @@
                 // Disabled input method is currently selected, switch to another one.
                 String selId = Settings.Secure.getString(mContext.getContentResolver(),
                         Settings.Secure.DEFAULT_INPUT_METHOD);
-                if (id.equals(selId)) {
-                    resetSelectedInputMethodAndSubtypeLocked(enabledInputMethodsList.size() > 0
-                            ? enabledInputMethodsList.get(0).first : "");
+                if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
+                    Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
+                    resetSelectedInputMethodAndSubtypeLocked("");
                 }
                 // Previous state was enabled.
                 return true;
@@ -1926,7 +1935,7 @@
         // The first subtype applicable to the system locale will be defined as the most applicable
         // subtype.
         if (DEBUG) {
-            Slog.d(TAG, "Applicable InputMethodSubtype was found: " + applicableSubtypeId
+            Slog.d(TAG, "Applicable InputMethodSubtype was found: " + applicableSubtypeId + ","
                     + subtypes.get(applicableSubtypeId).getLocale());
         }
         return applicableSubtypeId;
@@ -1956,6 +1965,20 @@
         return mCurrentSubtype;
     }
 
+    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
+        synchronized (mMethodMap) {
+            if (subtype != null && mCurMethodId != null) {
+                InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+                int subtypeId = getSubtypeIdFromHashCode(imi, subtype.hashCode());
+                if (subtypeId != NOT_A_SUBTYPE_ID) {
+                    setInputMethodLocked(mCurMethodId, subtypeId);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
     /**
      * Utility class for putting and getting settings for InputMethod
      * TODO: Move all putters and getters of settings to this class.
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 4707bbf..a0a1974 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -7327,7 +7327,7 @@
                 pw.println(" ");
                 pw.println("Package warning messages:");
                 File fname = getSettingsProblemFile();
-                FileInputStream in;
+                FileInputStream in = null;
                 try {
                     in = new FileInputStream(fname);
                     int avail = in.available();
@@ -7336,6 +7336,13 @@
                     pw.print(new String(data));
                 } catch (FileNotFoundException e) {
                 } catch (IOException e) {
+                } finally {
+                    if (in != null) {
+                        try {
+                            in.close();
+                        } catch (IOException e)  {
+                        }
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index 43dbcc0..1a12a84 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -799,8 +799,9 @@
     }
     
     private String readFile(String file, char endChar) {
+        FileInputStream is = null;
         try {
-            FileInputStream is = new FileInputStream(file);
+            is = new FileInputStream(file);
             int len = is.read(mBuffer);
             is.close();
 
@@ -815,6 +816,13 @@
             }
         } catch (java.io.FileNotFoundException e) {
         } catch (java.io.IOException e) {
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (java.io.IOException e) {
+                }
+            }
         }
         return null;
     }
@@ -841,4 +849,3 @@
         }
     }
 }
-
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index fb87d69..5038770 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -3729,7 +3729,7 @@
 
     public void setAppStartingWindow(IBinder token, String pkg,
             int theme, CharSequence nonLocalizedLabel, int labelRes, int icon,
-            IBinder transferFrom, boolean createIfNeeded) {
+            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppStartingIcon()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3877,7 +3877,7 @@
             mStartingIconInTransition = true;
             wtoken.startingData = new StartingData(
                     pkg, theme, nonLocalizedLabel,
-                    labelRes, icon);
+                    labelRes, icon, windowFlags);
             Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
             // Note: we really want to do sendMessageAtFrontOfQueue() because we
             // want to process the message ASAP, before any other queued
@@ -8440,14 +8440,16 @@
         final CharSequence nonLocalizedLabel;
         final int labelRes;
         final int icon;
+        final int windowFlags;
 
         StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
-                int _labelRes, int _icon) {
+                int _labelRes, int _icon, int _windowFlags) {
             pkg = _pkg;
             theme = _theme;
             nonLocalizedLabel = _nonLocalizedLabel;
             labelRes = _labelRes;
             icon = _icon;
+            windowFlags = _windowFlags;
         }
     }
 
@@ -8568,7 +8570,7 @@
                         view = mPolicy.addStartingWindow(
                             wtoken.token, sd.pkg,
                             sd.theme, sd.nonLocalizedLabel, sd.labelRes,
-                            sd.icon);
+                            sd.icon, sd.windowFlags);
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when adding starting window", e);
                     }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 47be6a2..c2f8d67 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -36,6 +36,7 @@
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.IApplicationToken;
+import android.view.WindowManager;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -68,6 +69,7 @@
     int labelRes;           // the label information from the package mgr.
     int icon;               // resource identifier of activity's icon.
     int theme;              // resource identifier of activity's theme.
+    int windowFlags;        // custom window flags for preview window.
     TaskRecord task;        // the task this is in.
     long launchTime;        // when we starting launching this activity
     long startTime;         // last time this activity was started
@@ -244,6 +246,9 @@
             }
             icon = aInfo.getIconResource();
             theme = aInfo.getThemeResource();
+            if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+                windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            }
             if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
                     && _caller != null
                     && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 463493b..51dc84e 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1301,7 +1301,8 @@
                         mService.mWindowManager.setAppStartingWindow(
                                 next, next.packageName, next.theme,
                                 next.nonLocalizedLabel,
-                                next.labelRes, next.icon, null, true);
+                                next.labelRes, next.icon, next.windowFlags,
+                                null, true);
                     }
                 }
                 startSpecificActivityLocked(next, true, false);
@@ -1336,7 +1337,8 @@
                     mService.mWindowManager.setAppStartingWindow(
                             next, next.packageName, next.theme,
                             next.nonLocalizedLabel,
-                            next.labelRes, next.icon, null, true);
+                            next.labelRes, next.icon, next.windowFlags,
+                            null, true);
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
             }
@@ -1460,7 +1462,7 @@
                 }
                 mService.mWindowManager.setAppStartingWindow(
                         r, r.packageName, r.theme, r.nonLocalizedLabel,
-                        r.labelRes, r.icon, prev, showStartingIcon);
+                        r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
             }
         } else {
             // If this is the first activity, don't do any fancy animations,
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index b5e73ac..22a45df 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -464,6 +464,7 @@
 }
 
 bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
+    Mutex::Autolock _l(mConnectionLock);
     if (mSensorInfo.indexOfKey(handle) <= 0) {
         SensorInfo info;
         mSensorInfo.add(handle, info);
@@ -473,6 +474,7 @@
 }
 
 bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
+    Mutex::Autolock _l(mConnectionLock);
     if (mSensorInfo.removeItem(handle) >= 0) {
         return true;
     }
@@ -480,16 +482,19 @@
 }
 
 bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
+    Mutex::Autolock _l(mConnectionLock);
     return mSensorInfo.indexOfKey(handle) >= 0;
 }
 
 bool SensorService::SensorEventConnection::hasAnySensor() const {
+    Mutex::Autolock _l(mConnectionLock);
     return mSensorInfo.size() ? true : false;
 }
 
 status_t SensorService::SensorEventConnection::setEventRateLocked(
         int handle, nsecs_t ns)
 {
+    Mutex::Autolock _l(mConnectionLock);
     ssize_t index = mSensorInfo.indexOfKey(handle);
     if (index >= 0) {
         SensorInfo& info = mSensorInfo.editValueFor(handle);
@@ -506,6 +511,7 @@
     // filter out events not for this connection
     size_t count = 0;
     if (scratch) {
+        Mutex::Autolock _l(mConnectionLock);
         size_t i=0;
         while (i<numEvents) {
             const int32_t curr = buffer[i].sensor;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b442779..c0922f5 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -75,8 +75,9 @@
 
         sp<SensorService> const mService;
         sp<SensorChannel> const mChannel;
+        mutable Mutex mConnectionLock;
 
-        // protected by SensorService::mLock
+        // protected mConnectionLock
         struct SensorInfo {
             SensorInfo() : ns(DEFAULT_EVENTS_PERIOD) { }
             nsecs_t ns;
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 4464236..710ff30 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -164,7 +164,7 @@
         }
         
         try {
-            mWm.setAppStartingWindow(null, "foo", 0, null, 0, 0, null, false);
+            mWm.setAppStartingWindow(null, "foo", 0, null, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {