Merge "Implement allocation resizing."
diff --git a/api/current.xml b/api/current.xml
index c769794..07724ab 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -6268,17 +6268,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad56"
- type="int"
- transient="false"
- volatile="false"
- value="16843465"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad6"
  type="int"
  transient="false"
@@ -7687,6 +7676,17 @@
  visibility="public"
 >
 </field>
+<field name="popupAnimationStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843465"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="popupBackground"
  type="int"
  transient="false"
@@ -21025,6 +21025,21 @@
  visibility="public"
 >
 </constructor>
+<method name="addChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
 <method name="addTransitionListener"
  return="void"
  abstract="false"
@@ -21038,36 +21053,6 @@
 <parameter name="listener" type="android.animation.LayoutTransition.TransitionListener">
 </parameter>
 </method>
-<method name="childAdd"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="parent" type="android.view.ViewGroup">
-</parameter>
-<parameter name="child" type="android.view.View">
-</parameter>
-</method>
-<method name="childRemove"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="parent" type="android.view.ViewGroup">
-</parameter>
-<parameter name="child" type="android.view.View">
-</parameter>
-</method>
 <method name="getAnimator"
  return="android.animation.Animator"
  abstract="false"
@@ -21144,6 +21129,36 @@
  visibility="public"
 >
 </method>
+<method name="hideChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
+<method name="removeChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
 <method name="removeTransitionListener"
  return="void"
  abstract="false"
@@ -21245,6 +21260,21 @@
 <parameter name="delay" type="long">
 </parameter>
 </method>
+<method name="showChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
 <field name="APPEARING"
  type="int"
  transient="false"
@@ -55046,6 +55076,17 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_FULL_SENSOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_LANDSCAPE"
  type="int"
  transient="false"
@@ -55079,6 +55120,28 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_REVERSE_LANDSCAPE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_ORIENTATION_REVERSE_PORTRAIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_SENSOR"
  type="int"
  transient="false"
@@ -55090,6 +55153,28 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_SENSOR_LANDSCAPE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_ORIENTATION_SENSOR_PORTRAIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_UNSPECIFIED"
  type="int"
  transient="false"
@@ -134925,6 +135010,17 @@
  visibility="public"
 >
 </method>
+<method name="isExternalStorageRemovable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <field name="DIRECTORY_ALARMS"
  type="java.lang.String"
  transient="false"
@@ -189868,6 +189964,16 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="action" type="int">
+</parameter>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="description" type="android.content.ClipDescription">
+</parameter>
+<parameter name="data" type="android.content.ClipData">
+</parameter>
 </method>
 <method name="obtain"
  return="android.view.DragEvent"
@@ -189879,15 +189985,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="action" type="int">
-</parameter>
-<parameter name="x" type="float">
-</parameter>
-<parameter name="y" type="float">
-</parameter>
-<parameter name="description" type="android.content.ClipDescription">
-</parameter>
-<parameter name="data" type="android.content.ClipData">
+<parameter name="source" type="android.view.DragEvent">
 </parameter>
 </method>
 <method name="recycle"
@@ -203374,6 +203472,53 @@
 >
 </field>
 </class>
+<class name="View.DragThumbnailBuilder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="View.DragThumbnailBuilder"
+ type="android.view.View.DragThumbnailBuilder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</constructor>
+<method name="onDrawThumbnail"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="canvas" type="android.graphics.Canvas">
+</parameter>
+</method>
+<method name="onProvideThumbnailMetrics"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="thumbnailSize" type="android.graphics.Point">
+</parameter>
+<parameter name="thumbnailTouchPoint" type="android.graphics.Point">
+</parameter>
+</method>
+</class>
 <class name="View.MeasureSpec"
  extends="java.lang.Object"
  abstract="false"
@@ -223693,7 +223838,7 @@
 >
 </method>
 <method name="getInAnimation"
- return="android.view.animation.Animation"
+ return="android.animation.ObjectAnimator&lt;?&gt;"
  abstract="false"
  native="false"
  synchronized="false"
@@ -223704,7 +223849,7 @@
 >
 </method>
 <method name="getOutAnimation"
- return="android.view.animation.Animation"
+ return="android.animation.ObjectAnimator&lt;?&gt;"
  abstract="false"
  native="false"
  synchronized="false"
@@ -223820,7 +223965,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="inAnimation" type="android.view.animation.Animation">
+<parameter name="inAnimation" type="android.animation.ObjectAnimator&lt;?&gt;">
 </parameter>
 </method>
 <method name="setInAnimation"
@@ -223848,7 +223993,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="outAnimation" type="android.view.animation.Animation">
+<parameter name="outAnimation" type="android.animation.ObjectAnimator&lt;?&gt;">
 </parameter>
 </method>
 <method name="setOutAnimation"
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 69ad67e..52f0f16 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -459,21 +459,22 @@
      * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
      * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
      * duration is being set.
-     * @param animator The animation being assigned.
+     * @param animator The animation being assigned. A value of <code>null</code> means that no
+     * animation will be run for the specified transitionType.
      */
     public void setAnimator(int transitionType, Animator animator) {
         switch (transitionType) {
             case CHANGE_APPEARING:
-                mChangingAppearingAnim = (animator != null) ? animator : defaultChangeIn;
+                mChangingAppearingAnim = animator;
                 break;
             case CHANGE_DISAPPEARING:
-                mChangingDisappearingAnim = (animator != null) ? animator : defaultChangeOut;
+                mChangingDisappearingAnim = animator;
                 break;
             case APPEARING:
-                mAppearingAnim = (animator != null) ? animator : defaultFadeIn;
+                mAppearingAnim = animator;
                 break;
             case DISAPPEARING:
-                mDisappearingAnim = (animator != null) ? animator : defaultFadeOut;
+                mDisappearingAnim = animator;
                 break;
         }
     }
@@ -516,6 +517,14 @@
      * transition is occuring because an item is being added to or removed from the parent.
      */
     private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
+
+        Animator baseAnimator = (changeReason == APPEARING) ?
+                mChangingAppearingAnim : mChangingDisappearingAnim;
+        // If the animation is null, there's nothing to do
+        if (baseAnimator == null) {
+            return;
+        }
+
         // reset the inter-animation delay, in case we use it later
         staggerDelay = 0;
 
@@ -540,9 +549,10 @@
                 }
 
                 // Make a copy of the appropriate animation
-                final Animator anim = (changeReason == APPEARING) ?
-                        mChangingAppearingAnim.clone() :
-                        mChangingDisappearingAnim.clone();
+                final Animator anim = baseAnimator.clone();
+
+                // Cache the animation in case we need to cancel it later
+                currentAnimations.put(child, anim);
 
                 // Set the target object for the animation
                 anim.setTarget(child);
@@ -553,13 +563,10 @@
 
                 // Add a listener to track layout changes on this view. If we don't get a callback,
                 // then there's nothing to animate.
-                View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
+                final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
                     public void onLayoutChange(View v, int left, int top, int right, int bottom,
                             int oldLeft, int oldTop, int oldRight, int oldBottom) {
 
-                        // Cache the animation in case we need to cancel it later
-                        currentAnimations.put(child, anim);
-
                         // Tell the animation to extract end values from the changed object
                         anim.setupEndValues();
 
@@ -577,19 +584,6 @@
                         anim.setStartDelay(startDelay);
                         anim.setDuration(duration);
 
-                        // Remove the animation from the cache when it ends
-                        anim.addListener(new AnimatorListenerAdapter() {
-                            private boolean canceled = false;
-                            public void onAnimationCancel(Animator animator) {
-                                // we remove canceled animations immediately, not here
-                                canceled = true;
-                            }
-                            public void onAnimationEnd(Animator animator) {
-                                if (!canceled) {
-                                    currentAnimations.remove(child);
-                                }
-                            }
-                        });
                         if (anim instanceof ObjectAnimator) {
                             ((ObjectAnimator) anim).setCurrentPlayTime(0);
                         }
@@ -601,6 +595,22 @@
                         layoutChangeListenerMap.remove(child);
                     }
                 };
+                // Remove the animation from the cache when it ends
+                anim.addListener(new AnimatorListenerAdapter() {
+                    private boolean canceled = false;
+                    public void onAnimationCancel(Animator animator) {
+                        // we remove canceled animations immediately, not here
+                        canceled = true;
+                        child.removeOnLayoutChangeListener(listener);
+                        layoutChangeListenerMap.remove(child);
+                    }
+                    public void onAnimationEnd(Animator animator) {
+                        if (!canceled) {
+                            currentAnimations.remove(child);
+                        }
+                    }
+                });
+
                 child.addOnLayoutChangeListener(listener);
                 // cache the listener for later removal
                 layoutChangeListenerMap.put(child, listener);
@@ -630,6 +640,14 @@
      * @param child The View being added to the ViewGroup.
      */
     private void runAppearingTransition(final ViewGroup parent, final View child) {
+        if (mAppearingAnim == null) {
+            if (mListeners != null) {
+                for (TransitionListener listener : mListeners) {
+                    listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
+                }
+            }
+            return;
+        }
         Animator anim = mAppearingAnim.clone();
         anim.setTarget(child);
         anim.setStartDelay(mAppearingDelay);
@@ -656,13 +674,22 @@
      * @param child The View being removed from the ViewGroup.
      */
     private void runDisappearingTransition(final ViewGroup parent, final View child) {
+        if (mDisappearingAnim == null) {
+            if (mListeners != null) {
+                for (TransitionListener listener : mListeners) {
+                    listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
+                }
+            }
+            return;
+        }
         Animator anim = mDisappearingAnim.clone();
         anim.setStartDelay(mDisappearingDelay);
         anim.setDuration(mDisappearingDuration);
         anim.setTarget(child);
         if (mListeners != null) {
             anim.addListener(new AnimatorListenerAdapter() {
-                public void onAnimationEnd() {
+                @Override
+                public void onAnimationEnd(Animator anim) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
@@ -684,7 +711,7 @@
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
      */
-    public void childAdd(ViewGroup parent, View child) {
+    public void addChild(ViewGroup parent, View child) {
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, APPEARING);
@@ -695,6 +722,19 @@
     }
 
     /**
+     * This method is called by ViewGroup when a child view is about to be added to the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup to which the View is being added.
+     * @param child The View being added to the ViewGroup.
+     */
+    public void showChild(ViewGroup parent, View child) {
+        addChild(parent, child);
+    }
+
+    /**
      * This method is called by ViewGroup when a child view is about to be removed from the
      * container. This callback starts the process of a transition; we grab the starting
      * values, listen for changes to all of the children of the container, and start appropriate
@@ -703,7 +743,7 @@
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
      */
-    public void childRemove(ViewGroup parent, View child) {
+    public void removeChild(ViewGroup parent, View child) {
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
@@ -714,6 +754,19 @@
     }
 
     /**
+     * This method is called by ViewGroup when a child view is about to be removed from the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup from which the View is being removed.
+     * @param child The View being removed from the ViewGroup.
+     */
+    public void hideChild(ViewGroup parent, View child) {
+        removeChild(parent, child);
+    }
+
+    /**
      * Add a listener that will be called when the bounds of the view change due to
      * layout processing.
      *
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e21cb97..e688c86 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -216,10 +216,41 @@
     public static final int SCREEN_ORIENTATION_SENSOR = 4;
   
     /**
-     * Constant corresponding to <code>sensor</code> in
+     * Constant corresponding to <code>nosensor</code> in
      * the {@link android.R.attr#screenOrientation} attribute.
      */
     public static final int SCREEN_ORIENTATION_NOSENSOR = 5;
+
+    /**
+     * Constant corresponding to <code>sensorLandscape</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6;
+
+    /**
+     * Constant corresponding to <code>sensorPortrait</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7;
+
+    /**
+     * Constant corresponding to <code>reverseLandscape</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
+
+    /**
+     * Constant corresponding to <code>reversePortrait</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
+
+    /**
+     * Constant corresponding to <code>fullSensor</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10;
+
     /**
      * The preferred screen orientation this activity would like to run in.
      * From the {@link android.R.attr#screenOrientation} attribute, one of
@@ -229,7 +260,12 @@
      * {@link #SCREEN_ORIENTATION_USER},
      * {@link #SCREEN_ORIENTATION_BEHIND},
      * {@link #SCREEN_ORIENTATION_SENSOR},
-     * {@link #SCREEN_ORIENTATION_NOSENSOR}.
+     * {@link #SCREEN_ORIENTATION_NOSENSOR},
+     * {@link #SCREEN_ORIENTATION_SENSOR_LANDSCAPE},
+     * {@link #SCREEN_ORIENTATION_SENSOR_PORTRAIT},
+     * {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
+     * {@link #SCREEN_ORIENTATION_REVERSE_PORTRAIT},
+     * {@link #SCREEN_ORIENTATION_FULL_SENSOR}.
      */
     public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
     
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index f0d0fb4..a98a305 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -410,8 +410,16 @@
      * @see #unlock()
      */
     /* package */ void lock() {
+        lock(false);
+    }
+    private void lock(boolean forced) {
+        // make sure this method is NOT being called from a 'synchronized' method
+        if (Thread.holdsLock(this)) {
+            // STOPSHIP change the following line to Log.w()
+            throw new IllegalStateException("don't lock() while in a synchronized method");
+        }
         verifyDbIsOpen();
-        if (!mLockingEnabled) return;
+        if (!forced && !mLockingEnabled) return;
         mLock.lock();
         if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
             if (mLock.getHoldCount() == 1) {
@@ -421,7 +429,6 @@
             }
         }
     }
-
     /**
      * Locks the database for exclusive access. The database lock must be held when
      * touch the native sqlite3* object since it is single threaded and uses
@@ -431,15 +438,7 @@
      * @see #unlockForced()
      */
     private void lockForced() {
-        verifyDbIsOpen();
-        mLock.lock();
-        if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
-            if (mLock.getHoldCount() == 1) {
-                // Use elapsed real-time since the CPU may sleep when waiting for IO
-                mLockAcquiredWallTime = SystemClock.elapsedRealtime();
-                mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
-            }
-        }
+        lock(true);
     }
 
     /**
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index c7cbed6..e8ae7e6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -18,6 +18,7 @@
 
 import java.io.File;
 
+import android.content.res.Resources;
 import android.os.storage.IMountService;
 
 /**
@@ -116,6 +117,19 @@
      * happened.  You can determine its current state with
      * {@link #getExternalStorageState()}.
      * 
+     * <p><em>Note: don't be confused by the word "external" here.  This
+     * directory can better be thought as media/shared storage.  It is a
+     * filesystem that can hold a relatively large amount of data and that
+     * is shared across all applications (does not enforce permissions).
+     * Traditionally this is an SD card, but it may also be implemented as
+     * built-in storage in a device that is distinct from the protected
+     * internal storage and can be mounted as a filesystem on a computer.</em></p>
+     *
+     * <p>In devices with multiple "external" storage directories (such as
+     * both secure app storage and mountable shared storage), this directory
+     * represents the "primary" external storage that the user will interact
+     * with.</p>
+     *
      * <p>Applications should not directly use this top-level directory, in
      * order to avoid polluting the user's root namespace.  Any files that are
      * private to the application should be placed in a directory returned
@@ -130,6 +144,9 @@
      * 
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * monitor_storage}
+     *
+     * @see #getExternalStorageState()
+     * @see #isExternalStorageRemovable()
      */
     public static File getExternalStorageDirectory() {
         return EXTERNAL_STORAGE_DIRECTORY;
@@ -359,11 +376,9 @@
     public static final String MEDIA_UNMOUNTABLE = "unmountable";
 
     /**
-     * Gets the current state of the external storage device.
-     * Note: This call should be deprecated as it doesn't support
-     * multiple volumes.
+     * Gets the current state of the primary "external" storage device.
      * 
-     * <p>See {@link #getExternalStorageDirectory()} for an example of its use.
+     * <p>See {@link #getExternalStorageDirectory()} for more information.
      */
     public static String getExternalStorageState() {
         try {
@@ -377,6 +392,19 @@
         }
     }
 
+    /**
+     * Returns whether the primary "external" storage device is removable.
+     * If true is returned, this device is for example an SD card that the
+     * user can remove.  If false is returned, the storage is built into
+     * the device and can not be physically removed.
+     *
+     * <p>See {@link #getExternalStorageDirectory()} for more information.
+     */
+    public static boolean isExternalStorageRemovable() {
+        return Resources.getSystem().getBoolean(
+                com.android.internal.R.bool.config_externalStorageRemovable);
+    }
+
     static File getDirectory(String variableName, String defaultPath) {
         String path = System.getenv(variableName);
         return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 47c6d3c..93598cd 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -50,10 +50,10 @@
     public static final int ACTION_DRAG_EXITED = 6;
 
     /* hide the constructor behind package scope */
-    DragEvent() {
+    private DragEvent() {
     }
 
-    public static DragEvent obtain() {
+    static DragEvent obtain() {
         return DragEvent.obtain(0, 0f, 0f, null, null);
     }
 
@@ -81,6 +81,11 @@
         return ev;
     }
 
+    public static DragEvent obtain(DragEvent source) {
+        return obtain(source.mAction, source.mX, source.mY,
+                source.mClipDescription, source.mClipData);
+    }
+
     public int getAction() {
         return mAction;
     }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 6b9cda0..85a8c1a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,8 +17,6 @@
 
 package android.view;
 
-import android.content.ClipData;
-import android.content.ClipDescription;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4c01f4f..63450de 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -615,7 +615,6 @@
  */
 public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
     private static final boolean DBG = false;
-    static final boolean DEBUG_DRAG = true;
 
     /**
      * The logging tag used by this class with android.util.Log.
@@ -3957,6 +3956,12 @@
         return true;
     }
 
+    /** Gets the ViewRoot, or null if not attached. */
+    /*package*/ ViewRoot getViewRoot() {
+        View root = getRootView();
+        return root != null ? (ViewRoot)root.getParent() : null;
+    }
+
     /**
      * Call this to try to give focus to a specific view or to one of its descendants. This is a
      * special variant of {@link #requestFocus() } that will allow views that are not focuable in
@@ -3970,12 +3975,9 @@
     public final boolean requestFocusFromTouch() {
         // Leave touch mode if we need to
         if (isInTouchMode()) {
-            View root = getRootView();
-            if (root != null) {
-               ViewRoot viewRoot = (ViewRoot)root.getParent();
-               if (viewRoot != null) {
-                   viewRoot.ensureTouchMode(false);
-               }
+            ViewRoot viewRoot = getViewRoot();
+            if (viewRoot != null) {
+                viewRoot.ensureTouchMode(false);
             }
         }
         return requestFocus(View.FOCUS_DOWN);
@@ -4905,6 +4907,9 @@
         }
 
         if ((changed & VISIBILITY_MASK) != 0) {
+            if (mParent instanceof ViewGroup) {
+                ((ViewGroup)mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+            }
             dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK));
         }
 
@@ -5147,7 +5152,7 @@
     /**
      * Recomputes the transform matrix if necessary.
      */
-    private final void updateMatrix() {
+    private void updateMatrix() {
         if (mMatrixDirty) {
             // transform-related properties have changed since the last time someone
             // asked for the matrix; recalculate it with the current values
@@ -6202,7 +6207,8 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
+                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
             mPrivateFlags &= ~DRAWING_CACHE_VALID;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
@@ -6233,7 +6239,8 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
+                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
             mPrivateFlags &= ~DRAWING_CACHE_VALID;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
@@ -6272,7 +6279,8 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
+                (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID)) {
             mPrivateFlags &= ~DRAWN;
             if (invalidateCache) {
                 mPrivateFlags &= ~DRAWING_CACHE_VALID;
@@ -7422,8 +7430,7 @@
 
                 final int restoreCount = canvas.save();
 
-                mPrivateFlags |= DRAWN;
-                mPrivateFlags |= DRAWING_CACHE_VALID;
+                mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
     
                 // Fast path for layouts with no backgrounds
                 if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
@@ -9830,40 +9837,99 @@
     }
 
     /**
+     * !!! TODO: real docs
+     *
+     * The base class implementation makes the thumbnail the same size and appearance
+     * as the view itself, and positions it with its center at the touch point.
+     */
+    public class DragThumbnailBuilder {
+        private View mView;
+
+        /**
+         * Construct a thumbnail builder object for use with the given view.
+         * @param view
+         */
+        public DragThumbnailBuilder(View view) {
+            mView = view;
+        }
+
+        /**
+         * Provide the draggable-thumbnail metrics for the operation: the dimensions of
+         * the thumbnail image itself, and the point within that thumbnail that should
+         * be centered under the touch location while dragging.
+         * <p>
+         * The default implementation sets the dimensions of the thumbnail to be the
+         * same as the dimensions of the View itself and centers the thumbnail under
+         * the touch point.
+         *
+         * @param thumbnailSize The application should set the {@code x} member of this
+         *        parameter to the desired thumbnail width, and the {@code y} member to
+         *        the desired height.
+         * @param thumbnailTouchPoint The application should set this point to be the
+         *        location within the thumbnail that should track directly underneath
+         *        the touch point on the screen during a drag.
+         */
+        public void onProvideThumbnailMetrics(Point thumbnailSize, Point thumbnailTouchPoint) {
+            thumbnailSize.set(mView.getWidth(), mView.getHeight());
+            thumbnailTouchPoint.set(thumbnailSize.x / 2, thumbnailSize.y / 2);
+        }
+
+        /**
+         * Draw the thumbnail image for the upcoming drag.  The thumbnail canvas was
+         * created with the dimensions supplied by the onProvideThumbnailMetrics()
+         * callback.
+         *
+         * @param canvas
+         */
+        public void onDrawThumbnail(Canvas canvas) {
+            mView.draw(canvas);
+        }
+    }
+
+    /**
      * Drag and drop.  App calls startDrag(), then callbacks to onMeasureDragThumbnail()
      * and onDrawDragThumbnail() happen, then the drag operation is handed over to the
      * OS.
      * !!! TODO: real docs
      * @hide
      */
-    public final boolean startDrag(ClipData data, float touchX, float touchY,
-            float thumbnailTouchX, float thumbnailTouchY, boolean myWindowOnly) {
-        if (DEBUG_DRAG) {
-            Log.d(VIEW_LOG_TAG, "startDrag: touch=(" + touchX + "," + touchY
-                    + ") thumb=(" + thumbnailTouchX + "," + thumbnailTouchY
-                    + ") data=" + data + " local=" + myWindowOnly);
+    public final boolean startDrag(ClipData data, DragThumbnailBuilder thumbBuilder,
+            boolean myWindowOnly) {
+        if (ViewDebug.DEBUG_DRAG) {
+            Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " local=" + myWindowOnly);
         }
         boolean okay = false;
 
-        measureThumbnail();     // throws if the view fails to specify dimensions
+        Point thumbSize = new Point();
+        Point thumbTouchPoint = new Point();
+        thumbBuilder.onProvideThumbnailMetrics(thumbSize, thumbTouchPoint);
+
+        if ((thumbSize.x < 0) || (thumbSize.y < 0) ||
+                (thumbTouchPoint.x < 0) || (thumbTouchPoint.y < 0)) {
+            throw new IllegalStateException("Drag thumb dimensions must not be negative");
+        }
 
         Surface surface = new Surface();
         try {
             IBinder token = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
                     myWindowOnly, mThumbnailWidth, mThumbnailHeight, surface);
-            if (DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token
+            if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token
                     + " surface=" + surface);
             if (token != null) {
                 Canvas canvas = surface.lockCanvas(null);
                 try {
-                    onDrawDragThumbnail(canvas);
+                    thumbBuilder.onDrawThumbnail(canvas);
                 } finally {
                     surface.unlockCanvasAndPost(canvas);
                 }
 
+                // repurpose 'thumbSize' for the last touch point
+                getViewRoot().getLastTouchPoint(thumbSize);
+
                 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
-                        touchX, touchY, thumbnailTouchX, thumbnailTouchY, data);
-                if (DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+                        (float) thumbSize.x, (float) thumbSize.y,
+                        (float) thumbTouchPoint.x, (float) thumbTouchPoint.y, data);
+                if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
             }
         } catch (Exception e) {
             Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
@@ -9885,7 +9951,7 @@
                     + " measured dimension by calling setDragThumbnailDimension()");
         }
 
-        if (DEBUG_DRAG) {
+        if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "Drag thumb measured: w=" + mThumbnailWidth
                     + " h=" + mThumbnailHeight);
         }
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index b1d5272..727cf17 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -136,6 +136,12 @@
     public static final boolean DEBUG_SHOW_FPS = false;
 
     /**
+     * Enables detailed logging of drag/drop operations.
+     * @hide
+     */
+    public static final boolean DEBUG_DRAG = true;
+
+    /**
      * <p>Enables or disables views consistency check. Even when this property is enabled,
      * view consistency checks happen only if {@link android.util.Config#DEBUG} is set
      * to true. The value of this property can be configured externally in one of the
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8a3db38..e71a4d6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -36,7 +36,6 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.Animation;
@@ -72,7 +71,6 @@
 public abstract class ViewGroup extends View implements ViewParent, ViewManager {
 
     private static final boolean DBG = false;
-    private static final String TAG = "ViewGroup";
 
     /**
      * Views which have been hidden or removed which need to be animated on
@@ -323,6 +321,10 @@
     // being animated.
     private ArrayList<View> mTransitioningViews;
 
+    // List of children changing visibility. This is used to potentially keep rendering
+    // views during a transition when they otherwise would have become gone/invisible
+    private ArrayList<View> mVisibilityChangingChildren;
+
     public ViewGroup(Context context) {
         super(context);
         initViewGroup();
@@ -758,6 +760,32 @@
     }
 
     /**
+     * @hide
+     * @param child
+     * @param visibility
+     */
+    void onChildVisibilityChanged(View child, int visibility) {
+        if (mTransition != null) {
+            if (visibility == VISIBLE) {
+                mTransition.showChild(this, child);
+            } else {
+                mTransition.hideChild(this, child);
+            }
+            if (visibility != VISIBLE) {
+                // Only track this on disappearing views - appearing views are already visible
+                // and don't need special handling during drawChild()
+                if (mVisibilityChangingChildren == null) {
+                    mVisibilityChangingChildren = new ArrayList<View>();
+                }
+                mVisibilityChangingChildren.add(child);
+                if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
+                    addDisappearingView(child);
+                }
+            }
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -838,9 +866,7 @@
         final float tx = event.mX;
         final float ty = event.mY;
 
-        // !!! BUGCHECK: If we have a ViewGroup, we must necessarily have a ViewRoot,
-        // so we don't need to check getRootView() for null here?
-        ViewRoot root = (ViewRoot)(getRootView().getParent());
+        ViewRoot root = getViewRoot();
 
         // Dispatch down the view hierarchy
         switch (event.mAction) {
@@ -853,10 +879,13 @@
             final int count = mChildrenCount;
             final View[] children = mChildren;
             for (int i = 0; i < count; i++) {
-                final boolean handled = children[i].dispatchDragEvent(event);
-                children[i].mCanAcceptDrop = handled;
-                if (handled) {
-                    mChildAcceptsDrag = true;
+                final View child = children[i];
+                if (child.getVisibility() == VISIBLE) {
+                    final boolean handled = children[i].dispatchDragEvent(event);
+                    children[i].mCanAcceptDrop = handled;
+                    if (handled) {
+                        mChildAcceptsDrag = true;
+                    }
                 }
             }
 
@@ -871,7 +900,10 @@
             final int count = mChildrenCount;
             final View[] children = mChildren;
             for (int i = 0; i < count; i++) {
-                children[i].dispatchDragEvent(event);
+                final View child = children[i];
+                if (child.getVisibility() == VISIBLE) {
+                    child.dispatchDragEvent(event);
+                }
             }
             // We consider drag-ended to have been handled if one of our children
             // had offered to handle the drag.
@@ -891,7 +923,7 @@
                 root.setDragFocus(event, target);
                 mCurrentDragView = target;
             }
-            
+
             // Dispatch the actual drag location notice, localized into its coordinates
             if (target != null) {
                 event.mX = mLocalPoint.x;
@@ -905,7 +937,7 @@
         } break;
 
         case DragEvent.ACTION_DROP: {
-            if (View.DEBUG_DRAG) Slog.d(TAG, "Drop event: " + event);
+            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
             View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
             if (target != null) {
                 event.mX = mLocalPoint.x;
@@ -927,8 +959,6 @@
     // Find the frontmost child view that lies under the given point, and calculate
     // the position within its own local coordinate system.
     View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
-        final float scrolledX = x + mScrollX;
-        final float scrolledY = y + mScrollY;
         final int count = mChildrenCount;
         final View[] children = mChildren;
         for (int i = count - 1; i >= 0; i--) {
@@ -937,20 +967,7 @@
                 continue;
             }
 
-            float localX = scrolledX - child.mLeft;
-            float localY = scrolledY - child.mTop;
-            if (!child.hasIdentityMatrix() && mAttachInfo != null) {
-                // non-identity matrix: transform the point into the view's coordinates
-                final float[] localXY = mAttachInfo.mTmpTransformLocation;
-                localXY[0] = localX;
-                localXY[1] = localY;
-                child.getInverseMatrix().mapPoints(localXY);
-                localX = localXY[0];
-                localY = localXY[1];
-            }
-            if (localX >= 0 && localY >= 0 && localX < (child.mRight - child.mLeft) &&
-                    localY < (child.mBottom - child.mTop)) {
-                outLocalPoint.set(localX, localY);
+            if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
                 return child;
             }
         }
@@ -1078,7 +1095,7 @@
                             continue;
                         }
 
-                        if (!isTransformedTouchPointInView(x, y, child)) {
+                        if (!isTransformedTouchPointInView(x, y, child, null)) {
                             // New pointer is out of child's bounds.
                             continue;
                         }
@@ -1262,7 +1279,8 @@
     /* Returns true if a child view contains the specified point when transformed
      * into its coordinate space.
      * Child must not be null. */
-    private final boolean isTransformedTouchPointInView(float x, float y, View child) {
+    private final boolean isTransformedTouchPointInView(float x, float y, View child,
+            PointF outLocalPoint) {
         float localX = x + mScrollX - child.mLeft;
         float localY = y + mScrollY - child.mTop;
         if (! child.hasIdentityMatrix() && mAttachInfo != null) {
@@ -1273,7 +1291,11 @@
             localX = localXY[0];
             localY = localXY[1];
         }
-        return child.pointInView(localX, localY);
+        final boolean isInView = child.pointInView(localX, localY);
+        if (isInView && outLocalPoint != null) {
+            outLocalPoint.set(localX, localY);
+        }
+        return isInView;
     }
 
     /* Transforms a motion event into the coordinate space of a particular child view,
@@ -2598,7 +2620,7 @@
         }
 
         if (mTransition != null) {
-            mTransition.childAdd(this, child);
+            mTransition.addChild(this, child);
         }
 
         if (!checkLayoutParams(params)) {
@@ -2817,7 +2839,7 @@
     private void removeViewInternal(int index, View view) {
 
         if (mTransition != null) {
-            mTransition.childRemove(this, view);
+            mTransition.removeChild(this, view);
         }
 
         boolean clearChildFocus = false;
@@ -2893,7 +2915,7 @@
             final View view = children[i];
 
             if (mTransition != null) {
-                mTransition.childRemove(this, view);
+                mTransition.removeChild(this, view);
             }
 
             if (view == focused) {
@@ -2962,7 +2984,7 @@
             final View view = children[i];
 
             if (mTransition != null) {
-                mTransition.childRemove(this, view);
+                mTransition.removeChild(this, view);
             }
 
             if (view == focused) {
@@ -3005,7 +3027,7 @@
      */
     protected void removeDetachedView(View child, boolean animate) {
         if (mTransition != null) {
-            mTransition.childRemove(this, child);
+            mTransition.removeChild(this, child);
         }
 
         if (child == mFocused) {
@@ -4025,11 +4047,16 @@
             final ArrayList<View> disappearingChildren = mDisappearingChildren;
             if (disappearingChildren != null && disappearingChildren.contains(view)) {
                 disappearingChildren.remove(view);
-                if (view.mAttachInfo != null) {
-                    view.dispatchDetachedFromWindow();
-                }
-                if (view.mParent != null) {
-                    view.mParent = null;
+                if (mVisibilityChangingChildren != null &&
+                        mVisibilityChangingChildren.contains(view)) {
+                    mVisibilityChangingChildren.remove(view);
+                } else {
+                    if (view.mAttachInfo != null) {
+                        view.dispatchDetachedFromWindow();
+                    }
+                    if (view.mParent != null) {
+                        view.mParent = null;
+                    }
                 }
                 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
             }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c63f7d6..155122f 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -24,6 +24,7 @@
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -205,6 +206,7 @@
     ClipDescription mDragDescription;
     View mCurrentDragView;
     final PointF mDragPoint = new PointF();
+    final PointF mLastTouchPoint = new PointF();
 
     /**
      * see {@link #playSoundEffect(int)}
@@ -2024,6 +2026,9 @@
             if (MEASURE_LATENCY) {
                 lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
             }
+            // cache for possible drag-initiation
+            mLastTouchPoint.x = event.getRawX();
+            mLastTouchPoint.y = event.getRawY();
             handled = mView.dispatchTouchEvent(event);
             if (MEASURE_LATENCY) {
                 lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
@@ -2509,6 +2514,11 @@
         event.recycle();
     }
 
+    public void getLastTouchPoint(Point outLocation) {
+        outLocation.x = (int) mLastTouchPoint.x;
+        outLocation.y = (int) mLastTouchPoint.y;
+    }
+
     public void setDragFocus(DragEvent event, View newDragTarget) {
         final int action = event.mAction;
         // If we've dragged off of a view, send it the EXITED message
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 8ffa158..3e2e92b 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -28,6 +28,11 @@
  * A special helper class used by the WindowManager
  *  for receiving notifications from the SensorManager when
  * the orientation of the device has changed.
+ *
+ * NOTE: If changing anything here, please run the API demo
+ * "App/Activity/Screen Orientation" to ensure that all orientation
+ * modes still work correctly.
+ *
  * @hide
  */
 public abstract class WindowOrientationListener {
@@ -103,6 +108,10 @@
         }
     }
 
+    public void setAllow180Rotation(boolean allowed) {
+        mSensorEventListener.setAllow180Rotation(allowed);
+    }
+
     public int getCurrentRotation(int lastRotation) {
         if (mEnabled) {
             return mSensorEventListener.getCurrentRotation(lastRotation);
@@ -151,19 +160,20 @@
         private static final int ROTATION_0 = 0;
         private static final int ROTATION_90 = 1;
         private static final int ROTATION_270 = 2;
+        private static final int ROTATION_180 = 3;
 
         // Mapping our internal aliases into actual Surface rotation values
         private static final int[] INTERNAL_TO_SURFACE_ROTATION = new int[] {
-            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270};
+            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270,
+            Surface.ROTATION_180};
 
         // Mapping Surface rotation values to internal aliases.
-        // We have no constant for Surface.ROTATION_180.  That should never happen, but if it
-        // does, we'll arbitrarily choose a mapping.
         private static final int[] SURFACE_TO_INTERNAL_ROTATION = new int[] {
-            ROTATION_0, ROTATION_90, ROTATION_90, ROTATION_270};
+            ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270};
 
         // Threshold ranges of orientation angle to transition into other orientation states.
-        // The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc.
+        // The first list is for transitions from ROTATION_0, ROTATION_90, ROTATION_270,
+        // and then ROTATION_180.
         // ROTATE_TO defines the orientation each threshold range transitions to, and must be kept
         // in sync with this.
         // We generally transition about the halfway point between two states with a swing of 30
@@ -172,13 +182,32 @@
                 {{60, 180}, {180, 300}},
                 {{0, 30}, {195, 315}, {315, 360}},
                 {{0, 45}, {45, 165}, {330, 360}},
-        };
 
+                // Handle situation where we are currently doing 180 rotation
+                // but that is no longer allowed.
+                {{0, 45}, {45, 135}, {135, 225}, {225, 315}, {315, 360}},
+        };
         // See THRESHOLDS
         private static final int[][] ROTATE_TO = new int[][] {
                 {ROTATION_90, ROTATION_270},
                 {ROTATION_0, ROTATION_270, ROTATION_0},
                 {ROTATION_0, ROTATION_90, ROTATION_0},
+                {ROTATION_0, ROTATION_90, ROTATION_0, ROTATION_270, ROTATION_0},
+        };
+
+        // Thresholds that allow all 4 orientations.
+        private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {
+            {{60, 165}, {165, 195}, {195, 300}},
+            {{0, 30}, {165, 195}, {195, 315}, {315, 360}},
+            {{0, 45}, {45, 165}, {165, 195}, {330, 360}},
+            {{0, 45}, {45, 135}, {225, 315}, {315, 360}},
+        };
+        // See THRESHOLDS_WITH_180
+        private static final int[][] ROTATE_TO_WITH_180 = new int[][] {
+            {ROTATION_90, ROTATION_180, ROTATION_270},
+            {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},
+            {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
+            {ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},
         };
 
         // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
@@ -188,7 +217,7 @@
         // Additional limits on tilt angle to transition to each new orientation.  We ignore all
         // data with tilt beyond MAX_TILT, but we can set stricter limits on transitions to a
         // particular orientation here.
-        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65};
+        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65, 40};
 
         // Between this tilt angle and MAX_TILT, we'll allow orientation changes, but we'll filter
         // with a higher time constant, making us less sensitive to change.  This primarily helps
@@ -228,6 +257,8 @@
         private static final float ACCELERATING_LOWPASS_ALPHA =
             computeLowpassAlpha(ACCELERATING_TIME_CONSTANT_MS);
 
+        private boolean mAllow180Rotation = false;
+
         private WindowOrientationListener mOrientationListener;
         private int mRotation = ROTATION_0; // Current orientation state
         private float mTiltAngle = 0; // low-pass filtered
@@ -249,6 +280,10 @@
             return (float) SAMPLING_PERIOD_MS / (timeConstantMs + SAMPLING_PERIOD_MS);
         }
 
+        void setAllow180Rotation(boolean allowed) {
+            mAllow180Rotation = allowed;
+        }
+
         int getCurrentRotation(int lastRotation) {
             if (mTiltDistrust > 0) {
                 // we really don't know the current orientation, so trust what's currently displayed
@@ -259,7 +294,9 @@
 
         private void calculateNewRotation(float orientation, float tiltAngle) {
             if (localLOGV) Log.i(TAG, orientation + ", " + tiltAngle + ", " + mRotation);
-            int thresholdRanges[][] = THRESHOLDS[mRotation];
+            final boolean allow180Rotation = mAllow180Rotation;
+            int thresholdRanges[][] = allow180Rotation
+                    ? THRESHOLDS_WITH_180[mRotation] : THRESHOLDS[mRotation];
             int row = -1;
             for (int i = 0; i < thresholdRanges.length; i++) {
                 if (orientation >= thresholdRanges[i][0] && orientation < thresholdRanges[i][1]) {
@@ -269,13 +306,15 @@
             }
             if (row == -1) return; // no matching transition
 
-            int rotation = ROTATE_TO[mRotation][row];
+            int rotation = allow180Rotation
+                    ? ROTATE_TO_WITH_180[mRotation][row] : ROTATE_TO[mRotation][row];
             if (tiltAngle > MAX_TRANSITION_TILT[rotation]) {
                 // tilted too far flat to go to this rotation
                 return;
             }
 
-            if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
+            if (localLOGV) Log.i(TAG, "orientation " + orientation + " gives new rotation = "
+                    + rotation);
             mRotation = rotation;
             mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]);
         }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 20aafbd..7b9af5b 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1081,6 +1081,7 @@
         if (mBlockNetworkLoads != flag) {
             mBlockNetworkLoads = flag;
             verifyNetworkAccess();
+            postSync();
         }
     }
 
diff --git a/core/java/android/widget/Adapter.java b/core/java/android/widget/Adapter.java
index f2b3e2a..9b6c5a4 100644
--- a/core/java/android/widget/Adapter.java
+++ b/core/java/android/widget/Adapter.java
@@ -72,7 +72,7 @@
     long getItemId(int position);
     
     /**
-     * Indicated whether the item ids are stable across changes to the
+     * Indicates whether the item ids are stable across changes to the
      * underlying data.
      * 
      * @return True if the same id always refers to the same object.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index ab75420..f5afb94 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -172,7 +172,7 @@
     int mItemCount;
 
     /**
-     * The number of items in the adapter before a data changed event occured.
+     * The number of items in the adapter before a data changed event occurred.
      */
     int mOldItemCount;
 
@@ -557,7 +557,7 @@
     /**
      * @return The number of items owned by the Adapter associated with this
      *         AdapterView. (This is the number of data items, which may be
-     *         larger than the number of visible view.)
+     *         larger than the number of visible views.)
      */
     @ViewDebug.CapturedViewProperty
     public int getCount() {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 9983d54..1d1e601 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -19,6 +19,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 
+import android.animation.AnimatorInflater;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.Intent;
@@ -135,12 +136,15 @@
     int mReferenceChildHeight = -1;
 
     /**
-     * TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit.
+     * In and out animations.
      */
-    Animation mInAnimation;
-    Animation mOutAnimation;
+    ObjectAnimator<?> mInAnimation;
+    ObjectAnimator<?> mOutAnimation;
+
     private  ArrayList<View> mViewsToBringToFront;
 
+    private static final int DEFAULT_ANIMATION_DURATION = 200;
+
     public AdapterViewAnimator(Context context) {
         super(context);
         initViewAnimator();
@@ -155,11 +159,15 @@
                 com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0);
         if (resource > 0) {
             setInAnimation(context, resource);
+        } else {
+            setInAnimation(getDefaultInAnimation());
         }
 
         resource = a.getResourceId(com.android.internal.R.styleable.AdapterViewAnimator_outAnimation, 0);
         if (resource > 0) {
             setOutAnimation(context, resource);
+        } else {
+            setOutAnimation(getDefaultOutAnimation());
         }
 
         boolean flag = a.getBoolean(
@@ -229,17 +237,23 @@
      * @param view The view that is being animated
      */
     void animateViewForTransition(int fromIndex, int toIndex, View view) {
-        ObjectAnimator pa;
         if (fromIndex == -1) {
-            view.setAlpha(0.0f);
-            pa = new ObjectAnimator(400, view, "alpha", 0.0f, 1.0f);
-            pa.start();
+            mInAnimation.setTarget(view);
+            mInAnimation.start();
         } else if (toIndex == -1) {
-            pa = new ObjectAnimator(400, view, "alpha", 1.0f, 0.0f);
-            pa.start();
+            mOutAnimation.setTarget(view);
+            mOutAnimation.start();
         }
     }
 
+    ObjectAnimator<?> getDefaultInAnimation() {
+        return new ObjectAnimator<Float>(DEFAULT_ANIMATION_DURATION, null, "alpha", 0.0f, 1.0f);
+    }
+
+    ObjectAnimator<?> getDefaultOutAnimation() {
+        return new ObjectAnimator<Float>(DEFAULT_ANIMATION_DURATION, null, "alpha", 1.0f, 0.0f);
+    }
+
     /**
      * Sets which child view will be displayed.
      *
@@ -265,20 +279,6 @@
     }
 
     /**
-     * Return default inAnimation. To be overriden by subclasses.
-     */
-    Animation getDefaultInAnimation() {
-        return null;
-    }
-
-    /**
-     * Return default outAnimation. To be overridden by subclasses.
-     */
-    Animation getDefaultOutAnimation() {
-        return null;
-    }
-
-    /**
      * To be overridden by subclasses. This method applies a view / index specific
      * transform to the child view.
      *
@@ -690,7 +690,7 @@
      * @see #setInAnimation(android.view.animation.Animation)
      * @see #setInAnimation(android.content.Context, int)
      */
-    public Animation getInAnimation() {
+    public ObjectAnimator<?> getInAnimation() {
         return mInAnimation;
     }
 
@@ -702,7 +702,7 @@
      * @see #getInAnimation()
      * @see #setInAnimation(android.content.Context, int)
      */
-    public void setInAnimation(Animation inAnimation) {
+    public void setInAnimation(ObjectAnimator<?> inAnimation) {
         mInAnimation = inAnimation;
     }
 
@@ -714,7 +714,7 @@
      * @see #setOutAnimation(android.view.animation.Animation)
      * @see #setOutAnimation(android.content.Context, int)
      */
-    public Animation getOutAnimation() {
+    public ObjectAnimator<?> getOutAnimation() {
         return mOutAnimation;
     }
 
@@ -726,7 +726,7 @@
      * @see #getOutAnimation()
      * @see #setOutAnimation(android.content.Context, int)
      */
-    public void setOutAnimation(Animation outAnimation) {
+    public void setOutAnimation(ObjectAnimator<?> outAnimation) {
         mOutAnimation = outAnimation;
     }
 
@@ -740,7 +740,7 @@
      * @see #setInAnimation(android.view.animation.Animation)
      */
     public void setInAnimation(Context context, int resourceID) {
-        setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
+        setInAnimation((ObjectAnimator<?>) AnimatorInflater.loadAnimator(context, resourceID));
     }
 
     /**
@@ -753,7 +753,7 @@
      * @see #setOutAnimation(android.view.animation.Animation)
      */
     public void setOutAnimation(Context context, int resourceID) {
-        setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
+        setOutAnimation((ObjectAnimator<?>) AnimatorInflater.loadAnimator(context, resourceID));
     }
 
     /**
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 95ebdd3..b09ade7 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.animation.ObjectAnimator;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -43,10 +44,8 @@
     private static final boolean LOGD = false;
 
     private static final int DEFAULT_INTERVAL = 10000;
-    private static final int DEFAULT_ANIMATION_DURATION = 200;
 
     private int mFlipInterval = DEFAULT_INTERVAL;
-    private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
     private boolean mAutoStart = false;
 
     private boolean mRunning = false;
@@ -56,7 +55,6 @@
 
     public AdapterViewFlipper(Context context) {
         super(context);
-        initDefaultAnimations();
     }
 
     public AdapterViewFlipper(Context context, AttributeSet attrs) {
@@ -74,19 +72,6 @@
                 com.android.internal.R.styleable.AdapterViewAnimator_loopViews, true);
 
         a.recycle();
-        initDefaultAnimations();
-    }
-
-    private void initDefaultAnimations() {
-        // Set the default animations to be fade in/out
-        if (mInAnimation == null) {
-            mInAnimation = new AlphaAnimation(0.0f, 1.0f);
-            mInAnimation.setDuration(mAnimationDuration);
-        }
-        if (mOutAnimation == null) {
-            mOutAnimation = new AlphaAnimation(1.0f, 0.0f);
-            mOutAnimation.setDuration(mAnimationDuration);
-        }
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6799ffd..d6c2db1 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -178,7 +178,10 @@
                 attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
 
         mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
-        mAnimationStyle = a.getResourceId(R.styleable.PopupWindow_windowAnimationStyle, -1);
+
+        final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
+        mAnimationStyle = animStyle == com.android.internal.R.style.Animation_PopupWindow ? -1 :
+                animStyle;
 
         // If this is a StateListDrawable, try to find and store the drawable to be
         // used when the drop-down is placed above its anchor view, and the one to be
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0c50742..70c6378 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -64,7 +64,6 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.TextWatcher;
-import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.DateKeyListener;
 import android.text.method.DateTimeKeyListener;
 import android.text.method.DialerKeyListener;
@@ -1160,7 +1159,7 @@
 
         fixFocusableAndClickableSettings();
 
-        // SelectionModifierCursorController depends on canSelectText, which depends on mMovement
+        // SelectionModifierCursorController depends on textCanBeSelected, which depends on mMovement
         prepareCursorControllers();
     }
 
@@ -2730,7 +2729,7 @@
             sendAfterTextChanged((Editable) text);
         }
 
-        // SelectionModifierCursorController depends on canSelectText, which depends on text
+        // SelectionModifierCursorController depends on textCanBeSelected, which depends on text
         prepareCursorControllers();
     }
 
@@ -6667,6 +6666,8 @@
             } else {
                 terminateSelectionActionMode();
             }
+
+            mLastTouchOffset = -1;
         }
 
         startStopMarquee(focused);
@@ -6899,7 +6900,7 @@
             mInsertionPointCursorController = null;
         }
 
-        if (canSelectText() && mLayout != null) {
+        if (textCanBeSelected() && mLayout != null) {
             if (mSelectionModifierCursorController == null) {
                 mSelectionModifierCursorController = new SelectionModifierCursorController();
             }
@@ -7119,7 +7120,7 @@
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
         switch (keyCode) {
         case KeyEvent.KEYCODE_A:
-            if (canSelectAll()) {
+            if (canSelectText()) {
                 return onTextContextMenuItem(ID_SELECT_ALL);
             }
 
@@ -7150,11 +7151,11 @@
         return super.onKeyShortcut(keyCode, event);
     }
 
-    private boolean canSelectAll() {
-        return canSelectText() && mText.length() != 0;
+    private boolean canSelectText() {
+        return textCanBeSelected() && mText.length() != 0;
     }
 
-    private boolean canSelectText() {
+    private boolean textCanBeSelected() {
         // prepareCursorController() relies on this method.
         // If you change this condition, make sure prepareCursorController is called anywhere
         // the value of this condition might be changed.
@@ -7624,7 +7625,7 @@
 
             boolean atLeastOne = false;
 
-            if (canSelectAll()) {
+            if (canSelectText()) {
                 menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
                     setIcon(com.android.internal.R.drawable.ic_menu_select_all).
                     setAlphabeticShortcut('a');
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 05e1ff3..1b68ba9 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -77,7 +77,7 @@
 
 static void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) {
     // skip printing this message if it is due to certain types of errors
-    if (iErrCode == SQLITE_CONSTRAINT) return;
+    if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT) return;
     LOGI("sqlite returned: error code = %d, msg = %s\n", iErrCode, zMsg);
 }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index cb1556b1..7521af4 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -50,7 +50,20 @@
  */
 #ifdef USE_OPENGL_RENDERER
 
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
 #define DEBUG_RENDERER 0
+#define PROFILE_RENDERER 0
+
+// Debug
+#if DEBUG_RENDERER
+    #define RENDERER_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define RENDERER_LOGD(...)
+#endif
 
 // ----------------------------------------------------------------------------
 // Java APIs
@@ -66,7 +79,8 @@
 // ----------------------------------------------------------------------------
 
 static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject canvas) {
-#if DEBUG_RENDERER
+    RENDERER_LOGD("Create OpenGLRenderer");
+#if PROFILE_RENDERER
     return new OpenGLDebugRenderer;
 #else
     return new OpenGLRenderer;
@@ -75,6 +89,7 @@
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer) {
+    RENDERER_LOGD("Destroy OpenGLRenderer");
     delete renderer;
 }
 
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png
index 53ed136..abb91cc 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png
index 6455790..7c4f40e 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png
index 49bb9c1..6dbf925 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png
index b3c4c4c..b05a49f 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png
index 00dea6ec..109be42 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png
index 45b1850..2800cab 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png
index 35b3529..51cbfa6 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png
index 720de7f..ca51ccc 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png
index b3387be..fd98571 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png
index 7ddfbcc..723815b 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png
index 1855e5f..030c9e9 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png
index 844f304..ffc5433 100644
--- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_pressed.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_pressed.9.png
index 0cfd09d..75c8162 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_pressed.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_small_pressed.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_small_pressed.9.png
index ee030fbe..aebfa29 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_small_pressed.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_small_unpressed.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_small_unpressed.9.png
index 7140957..ed416f1 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_small_unpressed.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_small_unpressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_unpressed.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_unpressed.9.png
index 1eeabf4..d063229 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_unpressed.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_unpressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
index e85f524..e49448d 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_100.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_40.png b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
index ca70784..441bbfb 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_40.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_60.png b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
index fee28db..d9467ed 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_60.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_80.png b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
index 7f4a38f..e3f4805 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_80.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
index 2277096..426a66b 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
index 7a3b19e..21582ca 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
index 5c23c13..8a94763 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
index 321545f..fad0d65 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim1.png b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
index 4f47db0..851eff9 100755
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim2.png b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
index e50d3c3..2d06bb1 100755
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim3.png b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
index 6c1029c..5c0ae7a 100755
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim4.png b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
index 693f085..f8d5c8a 100755
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim5.png b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
index eabe0ef..32b1425 100755
--- a/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
index d72afbe..32b5077 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
index 5de2873..8387b45 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
index dd0b49f..c9a56a0 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
index 8ac29b3..972808a 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
index 26c3e714..d47c761 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
index 431ac6b..7aeafbe 100755
--- a/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5df95de..8e2b762 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2363,7 +2363,7 @@
     </declare-styleable>
     <declare-styleable name="PopupWindow">
         <attr name="popupBackground" format="reference|color" />
-        <attr name="windowAnimationStyle" />
+        <attr name="popupAnimationStyle" format="reference" />
     </declare-styleable>
     <declare-styleable name="ViewAnimator">
         <!-- Identifier for the animation to use when a view is shown. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8cf65ae..949d960 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -497,10 +497,10 @@
              orientation will changed based on how the user rotates the device -->
         <enum name="unspecified" value="-1" />
         <!-- Would like to have the screen in a landscape orientation: that
-             is, with the display wider than it is tall. -->
+             is, with the display wider than it is tall, ignoring sensor data. -->
         <enum name="landscape" value="0" />
         <!-- Would like to have the screen in a portrait orientation: that
-             is, with the display taller than it is wide. -->
+             is, with the display taller than it is wide, ignoring sensor data. -->
         <enum name="portrait" value="1" />
         <!-- Use the user's current preferred orientation of the handset. -->
         <enum name="user" value="2" />
@@ -513,6 +513,24 @@
         <!-- Always ignore orientation determined by orientation sensor:
              the display will not rotate when the user moves the device. -->
         <enum name="nosensor" value="5" />
+        <!-- Would like to have the screen in landscape orientation, but can
+             use the sensor to change which direction the screen is facing. -->
+        <enum name="sensorLandscape" value="6" />
+        <!-- Would like to have the screen in portrait orientation, but can
+             use the sensor to change which direction the screen is facing. -->
+        <enum name="sensorPortait" value="7" />
+        <!-- Would like to have the screen in landscape orientation, turned in
+             the opposite direction from normal landscape. -->
+        <enum name="reverseLandscape" value="8" />
+        <!-- Would like to have the screen in portrait orientation, turned in
+             the opposite direction from normal portrait. -->
+        <enum name="reversePortait" value="9" />
+        <!-- Orientation is determined by a physical orientation sensor:
+             the display will rotate based on how the user moves the device.
+             This allows any of the 4 possible rotations, regardless of what
+             the device will normally do (for example some devices won't
+             normally use 180 degree rotation). -->
+        <enum name="fullSensor" value="10" />
     </attr>
     
     <!-- Specify one or more configuration changes that the activity will
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f704874..71967d4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -82,6 +82,15 @@
     <!-- Set to true if external storage is case sensitive.
          Typically external storage is FAT, which is case insensitive. -->
     <bool name="config_caseSensitiveExternalStorage">false</bool>
+    
+    <!-- A product with no SD card == not removable. -->
+    <bool name="config_externalStorageRemovable" product="nosdcard">false</bool>
+    <!-- Configures whether the primary external storage device is
+         removable.  For example, if external storage is on an SD card,
+         it is removable; if it is built in to the device, it is not removable.
+         The default product has external storage on an SD card, which is
+         removable. -->
+    <bool name="config_externalStorageRemovable" product="default">true</bool>
 
     <!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
          Please don't copy them, copy anything else. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8592820..35f8df5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1256,6 +1256,7 @@
   <public type="attr" name="textSelectHandleRight" id="0x010102c6" />
   <public type="attr" name="textSelectHandle" id="0x010102c7" />
   <public type="attr" name="textSelectHandleWindowStyle" id="0x010102c8" />
+  <public type="attr" name="popupAnimationStyle" id="0x010102c9" />
 
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6e9530c..3dfaf7f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -196,6 +196,9 @@
         <item name="windowExitAnimation">@anim/fade_out</item>
     </style>
 
+    <!-- A special animation value used internally for popup windows. -->
+    <style name="Animation.PopupWindow" />
+
     <!-- Status Bar Styles -->
 
     <style name="TextAppearance.StatusBar">
@@ -564,6 +567,7 @@
     
     <style name="Widget.PopupWindow">
         <item name="android:popupBackground">@android:drawable/editbox_dropdown_background_dark</item>
+        <item name="android:popupAnimationStyle">@android:style/Animation.PopupWindow</item>
     </style>
 
     <!-- Default style for {@link android.app.FragmentBreadCrumbs} view. -->
@@ -587,7 +591,7 @@
     </style>
 
     <style name="Widget.QuickContactBadge">
-        <item name="android:layout_width">50dip</item>
+        <item name="android:layout_width">47.33333dip</item>
         <item name="android:layout_height">56dip</item>
         <item name="android:background">@android:drawable/quickcontact_badge</item>
         <item name="android:clickable">true</item>
@@ -883,7 +887,7 @@
 
     <!-- Style for the small popup windows that contain text selection anchors. -->
     <style name="Widget.TextSelectHandle">
-        <item name="android:windowAnimationStyle">@android:style/Animation.TextSelectHandle</item>
+        <item name="android:popupAnimationStyle">@android:style/Animation.TextSelectHandle</item>
     </style>
 
     <!-- Style for animating text selection handles. -->
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
index 0797892..e74cefb 100644
--- a/docs/html/guide/appendix/market-filters.jd
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">

 <div id="qv">

 

-<h2 align="left">Market filters quickview</h2>

+<h2>Quickview</h2>

 <ul> <li>Android Market applies filters to that let you control whether your app is shown to a

 user who is browing or searching for apps.</li> 

 <li>Filtering is determined by elements in an app's manifest file,

diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index 56872a7..f5588ac 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -1,6 +1,30 @@
 page.title=Designing for Performance
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#intro">Introduction</a></li>
+  <li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
+  <li><a href="#object_creation">Avoid Creating Objects</a></li>
+  <li><a href="#myths">Performance Myths</a></li>
+  <li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
+  <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
+  <li><a href="#use_final">Use Static Final For Constants</a></li>
+  <li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
+  <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
+  <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
+  <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
+  <li><a href="#library">Know And Use The Libraries</a></li>
+  <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
+  <li><a href="#closing_notes">Closing Notes</a></li>
+</ol>
+
+</div>
+</div>
+
 <p>An Android application will run on a mobile device with limited computing
 power and storage, and constrained battery life. Because of
 this, it should be <em>efficient</em>. Battery life is one reason you might
@@ -8,24 +32,6 @@
 Battery life is important to users, and Android's battery usage breakdown
 means users will know if your app is responsible draining their battery.</p>
 
-<p>This document covers these topics: </p>
-<ul>
-    <li><a href="#intro">Introduction</a></li>
-    <li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
-    <li><a href="#object_creation">Avoid Creating Objects</a></li>
-    <li><a href="#myths">Performance Myths</a></li>
-    <li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
-    <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
-    <li><a href="#use_final">Use Static Final For Constants</a></li>
-    <li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
-    <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
-    <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
-    <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
-    <li><a href="#library">Know And Use The Libraries</a></li>
-    <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
-    <li><a href="#closing_notes">Closing Notes</a></li>
-</ul>
-
 <p>Note that although this document primarily covers micro-optimizations,
 these will almost never make or break your software. Choosing the right
 algorithms and data structures should always be your priority, but is
diff --git a/docs/html/guide/practices/design/responsiveness.jd b/docs/html/guide/practices/design/responsiveness.jd
index 9858e36..2c7633d 100644
--- a/docs/html/guide/practices/design/responsiveness.jd
+++ b/docs/html/guide/practices/design/responsiveness.jd
@@ -1,11 +1,37 @@
 page.title=Designing for Responsiveness
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#anr">What Triggers ANR?</a></li>
+  <li><a href="#avoiding">How to Avoid ANR</a></li>
+  <li><a href="#reinforcing">Reinforcing Responsiveness</a></li>
+</ol>
+
+</div>
+</div>
+
 <div class="figure">
 <img src="{@docRoot}images/anr.png" alt="Screenshot of ANR dialog box" width="240" height="320"/>
 <p><strong>Figure 1.</strong> An ANR dialog displayed to the user.</p>
 </div>
 
+<p>It's possible to write code that wins every performance test in the world, but still sends users
+in a fiery rage when they try to use the application. These are the applications that aren't
+<em>responsive</em> enough &mdash; the ones that feel
+sluggish, hang or freeze for significant periods, or take too long to process
+input. </p>
+
+<p>In Android, the system guards against applications that are insufficiently responsive for a
+period of time by displaying a dialog to the user, called the Application Not Responding (ANR)
+dialog. The user can choose to let the application continue, but the user won't appreciate having to
+act on this dialog every time he or she uses your application. So it's important to design
+responsiveness into your application, so that the system never has cause to display an ANR to the
+user. </p>
+
 <p>It's possible to write code that wins every performance test in the world,
 but still sends users in a fiery rage when they try to use the application.
 These are the applications that aren't <em>responsive</em> enough &mdash; the
diff --git a/docs/html/guide/practices/design/seamlessness.jd b/docs/html/guide/practices/design/seamlessness.jd
index a6c1641..dedc16f 100644
--- a/docs/html/guide/practices/design/seamlessness.jd
+++ b/docs/html/guide/practices/design/seamlessness.jd
@@ -1,6 +1,26 @@
 page.title=Designing for Seamlessness
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#drop">Don't Drop Data</a></li>
+  <li><a href="#expose">Don't Expose Raw Data</a></li>
+  <li><a href="#interrupt">Don't Interrupt the User</a></li>
+  <li><a href="#threads">Got a Lot to Do? Do it in a Thread</a></li>
+  <li><a href="#multiple-activities">Don't Overload a Single Activity Screen</a></li>
+  <li><a href="#themes">Extend System Themes</a></li>
+  <li><a href="#flexui">Design Your UI to Work with Multiple Screen Resolutions</a></li>
+  <li><a href="#network">Assume the Network is Slow</a></li>
+  <li><a href="#keyboard">Don't Assume Touchscreen or Keyboard</a></li>
+  <li><a href="#battery">Do Conserve the Device Battery</a></li>
+</ol>
+
+</div>
+</div>
+
 <p>Even if your application is fast and responsive, certain design decisions can
 still cause problems for users &mdash; because of unplanned interactions with
 other applications or dialogs, inadvertent loss of data, unintended blocking,
@@ -42,20 +62,7 @@
 by allowing you to integrate cleanly and seamlessly with other applications, and
 so you should design your own code to return the favor.</p>
 
-<p>This document discusses common seamlessness problems and how to avoid them.
-It covers these topics: </p>
-<ul>
-    <li><a href="#drop">Don't Drop Data</a></li>
-    <li><a href="#expose">Don't Expose Raw Data</a></li>
-    <li><a href="#interrupt">Don't Interrupt the User</a></li>
-    <li><a href="#threads">Got a Lot to Do? Do it in a Thread</a></li>
-    <li><a href="#multiple-activities">Don't Overload a Single Activity Screen</a></li>
-    <li><a href="#themes">Extend System Themes</a></li>
-    <li><a href="#flexui">Design Your UI to Work with Multiple Screen Resolutions</a></li>
-    <li><a href="#network">Assume the Network is Slow</a></li>
-    <li><a href="#keyboard">Don't Assume Touchscreen or Keyboard</a></li>
-    <li><a href="#battery">Do Conserve the Device Battery</a></li>
-</ul>
+<p>This document discusses common seamlessness problems and how to avoid them.</p>
 
 <h2 id="drop">Don't Drop Data</h2>
 
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 11ad1b8..13b5e3a 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -5,7 +5,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Multiple screens quickview: </h2>
+  <h2>Quickview</h2>
   <ul>
     <li>Android runs on devices that have different screen sizes and resolutions.</li>
     <li>The screen on which your application is displayed can affect its user interface.</li>
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index c8d241c..6cb98e6 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Activity and task design quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>Activities are the main building blocks of Android applications. </li>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index 51ccfaf..389d5fa 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Icon design quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>You can use several types of icons in an Android application.</li>
@@ -35,25 +35,30 @@
 
 </ol>
 
-<h2>See also</h2>
-
-<ol>
-<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-Screens</a></li>
-<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
-Templates Pack, v2.0 &raquo;</a></li>
-</ol>
-
 <h2>Older versions</h2>
 
 <ol>
 <li style="margin-top:4px;"><a
 href="{@docRoot}guide/practices/ui_guidelines/icon_design_1.html">Icon Design
 Guidelines, Android 1.0</a></li>
+</ol>
+
+<h2>Downloads</h2>
+
+<ol>
+<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
+Templates Pack, v2.0 &raquo;</a></li>
 <li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
 Templates Pack, v1.0 &raquo;</a></li>
 </ol>
 
+<h2>See also</h2>
+
+<ol>
+<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+</ol>
+
 
 </div>
 </div>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_1.jd b/docs/html/guide/practices/ui_guidelines/icon_design_1.jd
index 1c75843..995cfea 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_1.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_1.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Icon design quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>You can use several types of icons in an Android application.</li>
@@ -35,12 +35,17 @@
 
 </ol>
 
+<h2>Downloads</h2>
+
+<ol>
+<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
+Templates Pack, v1.0 &raquo;</a></li>
+</ol>
+
 <h2>See also</h2>
 
 <ol>
 <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
-<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
-Templates Pack, v1.0 &raquo;</a></li>
 </ol>
 
 
diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd
index ebf8a4b..840ee66 100644
--- a/docs/html/guide/practices/ui_guidelines/menu_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 			
-<h2>Menu design quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
   <li>An Options menu is for any commands that are global to the current activity. </li>
diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd
index fc62fe6..e978069 100644
--- a/docs/html/guide/practices/ui_guidelines/widget_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Widget design quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>Widgets have six standard sizes on the Home screen</li>
@@ -27,7 +27,7 @@
 <h2>See also</h2>
 
 <ol>
-<li><a href="{@docRoot}guide/topics/appwidgets/index.html">AppWidgets</a> topic in the <em>Dev Guide</em></li>
+<li><a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a></li>
 <li><a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html">AppWidgets blog post</a></li>
 </ol>
 
diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd
index 34d9419..6758054 100644
--- a/docs/html/guide/publishing/app-signing.jd
+++ b/docs/html/guide/publishing/app-signing.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Signing quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>All Android apps <em>must</em> be signed</a></li>
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index 07af68d..fc83ec0 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Market Licensing quickview: </h2>
+  <h2>Quickview</h2>
   <ul>
     <li>Licensing lets you protect your application on any device that includes Android Market.</li>
     <li>Your app maintains control of how it enforces its licensing status. </li>
diff --git a/docs/html/guide/publishing/preparing.jd b/docs/html/guide/publishing/preparing.jd
index 442c12a..45a5b77 100644
--- a/docs/html/guide/publishing/preparing.jd
+++ b/docs/html/guide/publishing/preparing.jd
@@ -1,20 +1,6 @@
 page.title=Preparing to Publish: A Checklist
 @jd:body
 
-<!--
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>In this document</h2>
-
-<ol>
-<li><a href=""></a></li>
-</ol>
-
-</div>
-</div>
--->
-
 <p>Publishing an application means testing it, packaging it appropriately, and 
 making it available to users of Android-powered mobile devices.</p>
 
@@ -34,7 +20,7 @@
 
 <div class="special">
 
-<p>Before you consider your application ready for release:</p>
+<p><a href="#releaseready">Before you consider your application ready for release</a>:</p>
 
 <ol>
 <li>Test your application extensively on an actual device </li>
@@ -44,7 +30,7 @@
 <li>Turn off logging and debugging and clean up data/files</li>
 </ol>
 
-<p>Before you do the final compile of your application:</p>
+<p><a href="#finalcompile">Before you do the final compile of your application</a>:</p>
 
 <ol start="6">
 <li>Version your application</li>
@@ -52,8 +38,9 @@
 <li>Register for a Maps API Key, if your application is using MapView elements</li>
 </ol>
 
-<p><em>Compile your application...</em></p>
-<p>After compiling your application:</p>
+<p><a href="#compile">Compile your application</a></p>
+
+<p><a href="#post-compile">After you compile your application</a>:</p>
 <ol start="9">
 <li>Sign your application</li>
 <li>Test your compiled application</li>
@@ -242,7 +229,7 @@
 you can compile your application for release.</p>
 
 
-<h2 id="post-compile">After compiling your application</h2>
+<h2 id="post-compile">After you compile your application</h2>
 
 <h3 id="signapp">9. Sign your application</h3>
 
diff --git a/docs/html/guide/publishing/publishing.jd b/docs/html/guide/publishing/publishing.jd
index 9b470c8..af1ea74 100644
--- a/docs/html/guide/publishing/publishing.jd
+++ b/docs/html/guide/publishing/publishing.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Publishing quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>You can publish your application using a hosted service such as Android Market or through a web server.</li>
diff --git a/docs/html/guide/publishing/versioning.jd b/docs/html/guide/publishing/versioning.jd
index 1d55f8a..b646247 100644
--- a/docs/html/guide/publishing/versioning.jd
+++ b/docs/html/guide/publishing/versioning.jd
@@ -4,7 +4,7 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Versioning quickview</h2>
+<h2>Quickview</h2>
 
 <ul>
 <li>Your application <em>must</em> be versioned</a></li>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 7a8dd59..3de5627 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -3,12 +3,14 @@
 
 <div id="qv-wrapper">
   <div id="qv">
-    <h2>Key classes</h2>
-    <ol>
-      <li>{@link android.appwidget.AppWidgetProvider}</li>
-      <li>{@link android.appwidget.AppWidgetProviderInfo}</li>
-      <li>{@link android.appwidget.AppWidgetManager}</li>
-    </ol>
+    <h2>Quickview</h2>
+    <ul>
+      <li>App Widgets provide users access to some of your application features
+directly from the Home screen (without the need to launch an activity)</li>
+      <li>App Widgets are backed by a special kind of broadcast receiver that handles the App
+Widget lifecycle</li>
+    </ul>
+    
     <h2>In this document</h2>
     <ol>
       <li><a href="#Basics">The Basics</a></li>
@@ -28,6 +30,13 @@
       </li>
     </ol>
 
+    <h2>Key classes</h2>
+    <ol>
+      <li>{@link android.appwidget.AppWidgetProvider}</li>
+      <li>{@link android.appwidget.AppWidgetProviderInfo}</li>
+      <li>{@link android.appwidget.AppWidgetManager}</li>
+    </ol>
+    
     <h2>See also</h2>
     <ol>
       <li><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design 
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index db06efc..84c2ed2 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -3,14 +3,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.app.Activity}</li>
-<li>{@link android.app.Service}</li>
-<li>{@link android.content.BroadcastReceiver}</li>
-<li>{@link android.content.ContentProvider}</li>
-<li>{@link android.content.Intent}</li>
-</ol>
 
 <h2>In this document</h2>
 <ol>
@@ -43,6 +35,16 @@
     <li><a href="#proclife">Processes and lifecycles</a></li>
   </ol></li>
 </ol>
+
+<h2>Key classes</h2>
+<ol>
+<li>{@link android.app.Activity}</li>
+<li>{@link android.app.Service}</li>
+<li>{@link android.content.BroadcastReceiver}</li>
+<li>{@link android.content.ContentProvider}</li>
+<li>{@link android.content.Intent}</li>
+</ol>
+
 </div>
 </div>
 
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index bd1d694..5905214 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -3,15 +3,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.content.Intent}</li>
-<li>{@link android.content.IntentFilter}</li>
-<li>{@link android.app.Activity}</li>
-<li>{@link android.app.Service}</li>
-<li>{@link android.content.BroadcastReceiver}</li>
-<li>{@link android.content.pm.PackageManager}</li>
-</ol>
 
 <h2>In this document</h2>
 <ol>
@@ -22,6 +13,15 @@
 <li style="margin-left: 2em"><a href="#imatch">Using intent matching</a></li>
 <li><a href="#npex">Note Pad Example</a></li>
 </ol>
+
+<h2>Key classes</h2>
+<ol>
+<li>{@link android.content.Intent}</li>
+<li>{@link android.content.IntentFilter}</li>
+<li>{@link android.content.BroadcastReceiver}</li>
+<li>{@link android.content.pm.PackageManager}</li>
+</ol>
+
 </div>
 </div>
 
diff --git a/docs/html/guide/topics/media/index.jd b/docs/html/guide/topics/media/index.jd
index 96c500c..558d453 100644
--- a/docs/html/guide/topics/media/index.jd
+++ b/docs/html/guide/topics/media/index.jd
@@ -4,7 +4,7 @@
     <div id="qv-wrapper">
     <div id="qv">
 
-<h2>Audio/Video quickview</h2>
+<h2>Quickview</h2>
 <ul>
 <li>Audio playback and record</li>
 <li>Video playback</li>
@@ -12,14 +12,6 @@
 <li>Built-in codecs for a variety of media. See <a href="{@docRoot}guide/appendix/media-formats.html">Android Supported Media Formats</a></li>
 </ul>
 
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.media.MediaPlayer MediaPlayer} (all available formats)</li>
-<li>{@link android.media.MediaRecorder MediaRecorder} (all available formats)</li>
-<li>{@link android.media.JetPlayer JetPlayer} (playback, JET content)</li>
-<li>{@link android.media.SoundPool SoundPool} (sound management)</li>
-</ol>
-
 <h2>In this document</h2>
 <ol>
 <li><a href="#playback.html">Audio and Video Playback</a>
@@ -32,6 +24,14 @@
 <li><a href="#capture">Audio Capture</a></li>
 </ol>
 
+<h2>Key classes</h2>
+<ol>
+<li>{@link android.media.MediaPlayer MediaPlayer}</li>
+<li>{@link android.media.MediaRecorder MediaRecorder}</li>
+<li>{@link android.media.JetPlayer JetPlayer}</li>
+<li>{@link android.media.SoundPool SoundPool}</li>
+</ol>
+
 <h2>See also</h2>
 <ol>
 <li><a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a></li>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index da4e7a1..2aed5e1 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -3,12 +3,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.content.ContentProvider}</li>
-<li>{@link android.content.ContentResolver}</li>
-<li>{@link android.database.Cursor}</li>
-</ol>
 
 <h2>In this document</h2>
 <ol>
@@ -18,6 +12,13 @@
 <li><a href="#creating">Creating a content provider</a></li>
 <li><a href="#urisum">Content URI summary</a></li>
 </ol>
+
+<h2>Key classes</h2>
+<ol>
+<li>{@link android.content.ContentProvider}</li>
+<li>{@link android.content.ContentResolver}</li>
+<li>{@link android.database.Cursor}</li>
+</ol>
 </div>
 </div>
 
diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd
index ce0c619..c8f06b9 100644
--- a/docs/html/guide/topics/search/adding-custom-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd
@@ -33,7 +33,7 @@
 <li>{@link android.content.ContentProvider}</li>
 </ol>
 
-<h2>Related Samples</h2>
+<h2>Related samples</h2>
 <ol>
 <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
 Dictionary</a></li>
diff --git a/docs/html/guide/topics/search/index.jd b/docs/html/guide/topics/search/index.jd
index 78e0be2..f563715 100644
--- a/docs/html/guide/topics/search/index.jd
+++ b/docs/html/guide/topics/search/index.jd
@@ -13,7 +13,7 @@
 <ol>
 <li><a href="searchable-config.html">Searchable Configuration</a></li>
 </ol>
-<h2>Related Samples</h2>
+<h2>Related samples</h2>
 <ol>
 <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
 Dictionary</a></li>
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index 49c6627..49938b4 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -29,7 +29,7 @@
 <li>{@link android.app.SearchManager}</li>
 </ol>
 
-<h2>Related Samples</h2>
+<h2>Related samples</h2>
 <ol>
 <li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
 Dictionary</a></li>
diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd
index 513e472..1d5f911 100755
--- a/docs/html/guide/topics/testing/testing_android.jd
+++ b/docs/html/guide/topics/testing/testing_android.jd
@@ -50,14 +50,14 @@
         <a href="#NextSteps">Next Steps</a>
     </li>
   </ol>
-  <h2>Key Classes and Packages</h2>
+  <h2>Key classes</h2>
     <ol>
       <li>{@link android.test.InstrumentationTestRunner}</li>
       <li>{@link android.test}</li>
       <li>{@link android.test.mock}</li>
       <li>{@link junit.framework}</li>
     </ol>
-  <h2>Related Tutorials</h2>
+  <h2>Related tutorials</h2>
     <ol>
         <li>
             <a href="{@docRoot}resources/tutorials/testing/helloandroid_test.html">
@@ -67,7 +67,7 @@
             <a href="{@docRoot}resources/tutorials/testing/activity_test.html">Activity Testing</a>
         </li>
     </ol>
-  <h2>See Also</h2>
+  <h2>See also</h2>
       <ol>
         <li>
           <a href="{@docRoot}guide/developing/testing/testing_eclipse.html">
diff --git a/docs/html/guide/topics/ui/binding.jd b/docs/html/guide/topics/ui/binding.jd
index 6ac0bb0..26364ee 100644
--- a/docs/html/guide/topics/ui/binding.jd
+++ b/docs/html/guide/topics/ui/binding.jd
@@ -11,11 +11,11 @@
     <li><a href="#HandlingUserSelections">Handling User Selections</a></li>
   </ol>
   
-  <h2>See also</h2>
+  <h2>Related tutorials</h2>
   <ol>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Hello Spinner tutorial</a></li>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-listview.html">Hello ListView tutorial</a></li>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Hello GridView tutorial</a></li>
+    <li><a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner</a></li>
+    <li><a href="{@docRoot}resources/tutorials/views/hello-listview.html">List View</a></li>
+    <li><a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid View</a></li>
   </ol>
 </div>
 </div>
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 5c12db9..fe641a2 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -5,12 +5,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.view.View}</li>
-    <li>{@link android.view.ViewGroup}</li>
-    <li>{@link android.view.ViewGroup.LayoutParams}</li>
-  </ol>
   <h2>In this document</h2>
   <ol>
     <li><a href="#write">Write the XML</a></li>
@@ -26,6 +20,12 @@
     <li><a href="#example">Example Layout</a></li>
   </ol>
 
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.view.View}</li>
+    <li>{@link android.view.ViewGroup}</li>
+    <li>{@link android.view.ViewGroup.LayoutParams}</li>
+  </ol>
 </div>
 </div>
 
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index f47a709..879eb8b 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -5,10 +5,6 @@
 
 <div id="qv-wrapper">
   <div id="qv">
-    <h2>Key classes</h2>
-    <ol>
-      <li>{@link android.app.Dialog}</li>
-    </ol>
     <h2>In this document</h2>
     <ol>
       <li><a href="#ShowingADialog">Showing a Dialog</a></li>
@@ -26,6 +22,11 @@
       </li>
       <li><a href="#CustomDialog">Creating a Custom Dialog</a></li>
     </ol>
+    
+    <h2>Key classes</h2>
+    <ol>
+      <li>{@link android.app.Dialog}</li>
+    </ol>
   </div>
 </div>
 
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index abcf6be..375c9fe 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -4,13 +4,6 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.view.View}</li>
-    <li>{@link android.view.ViewGroup}</li>
-    <li>{@link android.widget Widget classes}</li>
-  </ol>
-
   <h2>In this document</h2>
   <ol>
     <li><a href="#ViewHierarchy">View Hierarchy</a></li>
@@ -25,6 +18,13 @@
       </ol>
     </li>
   </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.view.View}</li>
+    <li>{@link android.view.ViewGroup}</li>
+    <li>{@link android.widget Widget classes}</li>
+  </ol>
 </div>
 </div>
 
diff --git a/docs/html/guide/topics/ui/notifiers/index.jd b/docs/html/guide/topics/ui/notifiers/index.jd
index f7ccce7..d29324c 100644
--- a/docs/html/guide/topics/ui/notifiers/index.jd
+++ b/docs/html/guide/topics/ui/notifiers/index.jd
@@ -3,13 +3,7 @@
 
 <div id="qv-wrapper">
   <div id="qv">
-    <h2>In this document</h2>
-    <ol>
-      <li><a href="#Toast">Toast Notification</a></li>
-      <li><a href="#StatusBarNotification">Status Bar Notification</a></li>
-      <li><a href="#Dialog">Dialog Notification</a></li>
-    </ol>
-    <h2>More about</h2>
+    <h2>Topics</h2>
     <ol>
       <li><a href="toasts.html">Creating Toast Notifications</a></li>
       <li><a href="notifications.html">Creating Status Bar Notifications</a></li>
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index a0dd9f1..abc945a 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -5,18 +5,21 @@
 
 <div id="qv-wrapper">
   <div id="qv">
-    <h2>Key classes</h2>
-    <ol>
-      <li>{@link android.app.Notification}</li>
-      <li>{@link android.app.NotificationManager}</li>
-    </ol>
+    <h2>Quickview</h2>
+    <ul>
+      <li>A status bar notification allows your application to notify the user of an event
+without interupting their current activity</li>
+      <li>You can attach an intent to your notification that the system will initiate when the
+user clicks it</li>
+    </ul>
+    
     <h2>In this document</h2>
     <ol>
       <li><a href="#Basics">The Basics</a></li>
       <li><a href="#ManageYourNotifications">Managing your Notifications</a></li>
       <li><a href="#CreateANotification">Creating a Notification</a>
         <ol>
-          <li><a href="#Update">Updating the notification</a></li>
+          <li><a href="#Updating">Updating the notification</a></li>
           <li><a href="#Sound">Adding a sound</a></li>
           <li><a href="#Vibration">Adding vibration</a></li>
           <li><a href="#Lights">Adding flashing lights</a></li>
@@ -25,6 +28,11 @@
       </li>
       <li><a href="#CustomExpandedView">Creating a Custom Expanded View</a></li>
     </ol>
+    <h2>Key classes</h2>
+    <ol>
+      <li>{@link android.app.Notification}</li>
+      <li>{@link android.app.NotificationManager}</li>
+    </ol>
   </div>
 </div>
 
diff --git a/docs/html/guide/topics/ui/notifiers/toasts.jd b/docs/html/guide/topics/ui/notifiers/toasts.jd
index 5b324d2..0d3e10c 100644
--- a/docs/html/guide/topics/ui/notifiers/toasts.jd
+++ b/docs/html/guide/topics/ui/notifiers/toasts.jd
@@ -5,16 +5,24 @@
 
 <div id="qv-wrapper">
   <div id="qv">
-    <h2>Key classes</h2>
+    <h2>Quickview</h2>
     <ol>
-      <li>{@link android.widget.Toast}</li>
+      <li>A toast is a message that appears on the surface of the screen for a moment, but it
+does not take focus (or pause the current activity), so it cannot accept user input</li>
+      <li>You can customize the toast layout to include images</li>
     </ol>
+    
     <h2>In this document</h2>
     <ol>
       <li><a href="#Basics">The Basics</a></li>
-      <li><a href="#Position">Positioning your Toast</a></li>
+      <li><a href="#Positioning">Positioning your Toast</a></li>
       <li><a href="#CustomToastView">Creating a Custom Toast View</a></li>
     </ol>
+    
+    <h2>Key classes</h2>
+    <ol>
+      <li>{@link android.widget.Toast}</li>
+    </ol>
   </div>
 </div>
 
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
index ccef64f..7d7bfaf 100644
--- a/docs/html/guide/topics/ui/ui-events.jd
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -13,9 +13,9 @@
     <li><a href="#HandlingFocus">Handling Focus</a></li>
   </ol>
 
-  <h2>See also</h2>
+  <h2>Related tutorials</h2>
   <ol>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Hello Form Stuff tutorial</a></li>
+    <li><a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff</a></li>
   </ol>
 </div>
 </div>
diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd
index a8ff007..fa2875b 100644
--- a/docs/html/guide/topics/wireless/bluetooth.jd
+++ b/docs/html/guide/topics/wireless/bluetooth.jd
@@ -3,14 +3,13 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-  <h2>Key Classes</h2>
-  <ol>
-    <li>{@link android.bluetooth.BluetoothAdapter}</li>
-    <li>{@link android.bluetooth.BluetoothDevice}</li>
-    <li>{@link android.bluetooth.BluetoothSocket}</li>
-    <li>{@link android.bluetooth.BluetoothServerSocket}</li>
-  </ol>
 
+  <h2>Quickview</h2>
+  <ul>
+    <li>Android's bluetooth APIs allow your application to perform wireless data transactions with
+other devices</li>
+  </ul>
+  
   <h2>In this document</h2>
   <ol>
     <li><a href="#TheBasics">The Basics</a></li>
@@ -33,11 +32,18 @@
     </li>
     <li><a href="#ManagingAConnection">Managing a Connection</a></li>
   </ol>
-
-  <h2>See also</h2>
+  
+  <h2>Key classes</h2>
   <ol>
-    <li><a href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat sample
-      app</a></li>
+    <li>{@link android.bluetooth.BluetoothAdapter}</li>
+    <li>{@link android.bluetooth.BluetoothDevice}</li>
+    <li>{@link android.bluetooth.BluetoothSocket}</li>
+    <li>{@link android.bluetooth.BluetoothServerSocket}</li>
+  </ol>
+
+  <h2>Related samples</h2>
+  <ol>
+    <li><a href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat</a></li>
   </ol>
 
 </div>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 9a19056..d283dea3 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -346,6 +346,15 @@
         return b;
     }
 
+    /**
+     * Creates a new bitmap, scaled from an existing bitmap.
+     *
+     * @param src       The source bitmap.
+     * @param dstWidth  The new bitmap's desired width.
+     * @param dstHeight The new bitmap's desired height.
+     * @param filter    true if the source should be filtered.
+     * @return the new scaled bitmap.
+     */
     public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
             int dstHeight, boolean filter) {
         Matrix m;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index a4933c0..2952a66 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -65,8 +65,8 @@
     PathCache pathCache;
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
-    GammaFontRenderer fontRenderer;
     FboCache fboCache;
+    GammaFontRenderer fontRenderer;
 
     Line line;
 }; // class Caches
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5485113..8389e56 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -437,8 +437,9 @@
     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
             GL_ALPHA, GL_UNSIGNED_BYTE, 0);
 
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    mLinearFiltering = false;
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 4fb8f8d..f10efad 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -156,8 +156,16 @@
     DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, uint32_t radius);
 
-    GLuint getTexture() {
+    GLuint getTexture(bool linearFiltering = false) {
         checkInit();
+        if (linearFiltering != mLinearFiltering) {
+            mLinearFiltering = linearFiltering;
+            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
+
+            glBindTexture(GL_TEXTURE_2D, mTextureId);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+        }
         return mTextureId;
     }
 
@@ -252,6 +260,8 @@
 
     bool mInitialized;
 
+    bool mLinearFiltering;
+
     void computeGaussianWeights(float* weights, int32_t radius);
     void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
             int32_t width, int32_t height);
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index c698b5a..219fd5e 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -53,6 +53,15 @@
     mSimpleMatrix = true;
 }
 
+#define EPSILON 0.00001f
+#define almost(u, v) (fabs((u) - (v)) < EPSILON)
+
+bool Matrix4::changesBounds() {
+    return !(almost(data[0], 1.0f) && almost(data[1], 0.0f) && almost(data[2], 0.0f) &&
+             almost(data[4], 0.0f) && almost(data[5], 1.0f) && almost(data[6], 0.0f) &&
+             almost(data[8], 0.0f) && almost(data[9], 0.0f) && almost(data[10], 1.0f));
+}
+
 void Matrix4::load(const float* v) {
     memcpy(data, v, sizeof(data));
     mSimpleMatrix = false;
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 0608efe..fe81159 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -103,6 +103,8 @@
         multiply(u);
     }
 
+    bool changesBounds();
+
     void copyTo(float* v) const;
     void copyTo(SkMatrix& v) const;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 0810fb8..e3790f5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -113,8 +113,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
-    LOGD("Create OpenGLRenderer");
-
     mShader = NULL;
     mColorFilter = NULL;
     mHasShadow = false;
@@ -133,7 +131,6 @@
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
-    LOGD("Destroy OpenGLRenderer");
     // The context has already been destroyed at this point, do not call
     // GL APIs. All GL state should be kept in Caches.h
 }
@@ -767,8 +764,10 @@
     GLuint textureUnit = 0;
     glActiveTexture(gTextureUnits[textureUnit]);
 
-    setupTextureAlpha8(fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
-            mode, false, true);
+    // Assume that the modelView matrix does not force scales, rotates, etc.
+    const bool linearFilter = mSnapshot->transform->changesBounds();
+    setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit,
+            x, y, r, g, b, a, mode, false, true);
 
     const Rect& clip = mSnapshot->getLocalClip();
     clearLayerRegions();
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 062c986..c736a1c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -141,6 +141,7 @@
         }
 
         if (clipped) {
+            clipRect->snapToPixelBoundaries();
             flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip;
         }
 
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
index a15c4a1..0990da3 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
@@ -84,8 +84,6 @@
     private Allocation mTexTransparent;
     private Allocation mTexChecker;
 
-    private Allocation mAllocPV;
-
     private Mesh mMbyNMesh;
     private Mesh mTorus;
 
@@ -95,7 +93,6 @@
     Font mFontSerifItalic;
     Font mFontSerifBoldItalic;
     Font mFontMono;
-
     private Allocation mTextAlloc;
 
     private ScriptC_rsrenderstates mScript;
@@ -267,12 +264,15 @@
         mFontSerifBoldItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
         mFontMono = Font.createFromFamily(mRS, mRes, "mono", Font.Style.NORMAL, 8);
 
+        mTextAlloc = Allocation.createFromString(mRS, "String from allocation");
+
         mScript.set_gFontSans(mFontSans);
         mScript.set_gFontSerif(mFontSerif);
         mScript.set_gFontSerifBold(mFontSerifBold);
         mScript.set_gFontSerifItalic(mFontSerifItalic);
         mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic);
         mScript.set_gFontMono(mFontMono);
+        mScript.set_gTextAlloc(mTextAlloc);
     }
 
     private void initMesh() {
diff --git a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
index b471504..77384ef 100644
--- a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
+++ b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
@@ -42,6 +42,7 @@
 rs_font gFontSerifItalic;
 rs_font gFontSerifBoldItalic;
 rs_font gFontMono;
+rs_allocation gTextAlloc;
 
 int gDisplayMode;
 
@@ -70,7 +71,7 @@
 #pragma rs export_var(gProgStoreBlendNoneDepth, gProgStoreBlendNone, gProgStoreBlendAlpha, gProgStoreBlendAdd)
 #pragma rs export_var(gTexOpaque, gTexTorus, gTexTransparent, gTexChecker)
 #pragma rs export_var(gMbyNMesh, gTorusMesh)
-#pragma rs export_var(gFontSans, gFontSerif, gFontSerifBold, gFontSerifItalic, gFontSerifBoldItalic, gFontMono)
+#pragma rs export_var(gFontSans, gFontSerif, gFontSerifBold, gFontSerifItalic, gFontSerifBoldItalic, gFontMono, gTextAlloc)
 #pragma rs export_var(gLinearClamp, gLinearWrap, gMipLinearWrap, gMipLinearAniso8, gMipLinearAniso15, gNearestClamp)
 #pragma rs export_var(gCullBack, gCullFront, gCullNone)
 #pragma rs export_var(gVSConstants, gFSConstants, gVSInputs, gProgVertexCustom, gProgFragmentCustom, gProgFragmentMultitex)
@@ -85,7 +86,7 @@
 
 void displayFontSamples() {
     rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    int yPos = 30;
+    int yPos = 100;
     rsgBindFont(gFontSans);
     rsgDrawText("Sans font sample", 30, yPos);
     yPos += 30;
@@ -107,6 +108,47 @@
     yPos += 30;
     rsgBindFont(gFontMono);
     rsgDrawText("Monospace font sample", 30, yPos);
+    yPos += 50;
+
+    // Now use text metrics to center the text
+    uint width = rsgGetWidth();
+    uint height = rsgGetHeight();
+    int left = 0, right = 0, top = 0, bottom = 0;
+
+    rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
+    rsgBindFont(gFontSerifBoldItalic);
+
+    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
+    int centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(gTextAlloc, centeredPos, yPos);
+    yPos += 30;
+
+    const char* text = "Centered Text Sample";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, yPos);
+    yPos += 30;
+
+    rsgBindFont(gFontSans);
+    text = "More Centered Text Samples";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, yPos);
+    yPos += 30;
+
+    // Now draw bottom and top right aligned text
+    text = "Top-right aligned text";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, width - right, top);
+
+    text = "Top-left";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, -left, top);
+
+    text = "Bottom-right aligned text";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    rsgDrawText(text, width - right, height + bottom);
+
 }
 
 void bindProgramVertexOrtho() {
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 6940033..493a092 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -258,14 +258,14 @@
     sprintf(buffer, "Frame %i ms, Script %i ms", mTimeMSLastFrame, mTimeMSLastScript);
     float oldR, oldG, oldB, oldA;
     mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA);
+    uint32_t bufferLen = strlen(buffer);
 
-    float shadowCol = 0.2f;
+    float shadowCol = 0.1f;
     mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f);
-    mStateFont.renderText(buffer, 5, getHeight() - 5);
+    mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 5);
 
-    float textCol = 0.9f;
-    mStateFont.setFontColor(textCol, textCol, textCol, 1.0f);
-    mStateFont.renderText(buffer, 4, getHeight() - 6);
+    mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f);
+    mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 6);
 
     mStateFont.setFontColor(oldR, oldG, oldB, oldA);
 }
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index c516ea9..cc2b76a 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -84,34 +84,95 @@
     }
 }
 
-void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
+void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
 {
     FontState *state = &mRSC->mStateFont;
 
-    int nPenX = x + glyph->mBitmapLeft;
-    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
+    int32_t nPenX = x + glyph->mBitmapLeft;
+    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
 
-    state->appendMeshQuad(nPenX, nPenY, 0,
-                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
+    float u1 = glyph->mBitmapMinU;
+    float u2 = glyph->mBitmapMaxU;
+    float v1 = glyph->mBitmapMinV;
+    float v2 = glyph->mBitmapMaxV;
 
-                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
-                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
+    int32_t width = (int32_t) glyph->mBitmapWidth;
+    int32_t height = (int32_t) glyph->mBitmapHeight;
 
-                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
-                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
-
-                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
-                            glyph->mBitmapMinU, glyph->mBitmapMinV);
+    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
+                          nPenX + width, nPenY, 0, u2, v2,
+                          nPenX + width, nPenY - height, 0, u2, v1,
+                          nPenX, nPenY - height, 0, u1, v1);
 }
 
-void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
+void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
+                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
+    int32_t nPenX = x + glyph->mBitmapLeft;
+    int32_t nPenY = y + glyph->mBitmapTop;
+
+    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
+    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
+
+    FontState *state = &mRSC->mStateFont;
+    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
+    const uint8_t* cacheBuffer = state->getTextTextureData();
+
+    uint32_t cacheX = 0, cacheY = 0;
+    int32_t bX = 0, bY = 0;
+    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
+        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
+                LOGE("Skipping invalid index");
+                continue;
+            }
+            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
+            bitmap[bY * bitmapW + bX] = tempCol;
+        }
+    }
+
+}
+
+void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
+    int32_t nPenX = x + glyph->mBitmapLeft;
+    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
+
+    int32_t width = (int32_t) glyph->mBitmapWidth;
+    int32_t height = (int32_t) glyph->mBitmapHeight;
+
+    if (bounds->bottom > nPenY) {
+        bounds->bottom = nPenY;
+    }
+    if (bounds->left > nPenX) {
+        bounds->left = nPenX;
+    }
+    if (bounds->right < nPenX + width) {
+        bounds->right = nPenX + width;
+    }
+    if (bounds->top < nPenY + height) {
+        bounds->top = nPenY + height;
+    }
+}
+
+void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
+                     uint32_t start, int32_t numGlyphs,
+                     RenderMode mode, Rect *bounds,
+                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
 {
     if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
         return;
     }
 
-    int penX = x, penY = y;
-    int glyphsLeft = 1;
+    if(mode == Font::MEASURE) {
+        if (bounds == NULL) {
+            LOGE("No return rectangle provided to measure text");
+            return;
+        }
+        // Reset min and max of the bounding box to something large
+        bounds->set(1e6, -1e6, -1e6, 1e6);
+    }
+
+    int32_t penX = x, penY = y;
+    int32_t glyphsLeft = 1;
     if(numGlyphs > 0) {
         glyphsLeft = numGlyphs;
     }
@@ -135,7 +196,17 @@
 
         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
         if(cachedGlyph->mIsValid) {
-            drawCachedGlyph(cachedGlyph, penX, penY);
+            switch(mode) {
+            case FRAMEBUFFER:
+                drawCachedGlyph(cachedGlyph, penX, penY);
+                break;
+            case BITMAP:
+                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
+                break;
+            case MEASURE:
+                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
+                break;
+            }
         }
 
         penX += (cachedGlyph->mAdvance.x >> 6);
@@ -283,7 +354,7 @@
     }
 
     // Get the black gamma threshold
-    int blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
+    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
     if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
         LOGD("  Setting text black gamma threshold to %s", property);
         blackThreshold = atoi(property);
@@ -294,7 +365,7 @@
     mBlackThreshold = (float)(blackThreshold) / 255.0f;
 
     // Get the white gamma threshold
-    int whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
+    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
     if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
         LOGD("  Setting text white gamma threshold to %s", property);
         whiteThreshold = atoi(property);
@@ -397,13 +468,13 @@
 
     uint32_t cacheWidth = getCacheTextureType()->getDimX();
 
-    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
-    unsigned char *bitmapBuffer = bitmap->buffer;
+    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
+    uint8_t *bitmapBuffer = bitmap->buffer;
 
     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
     for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
         for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
-            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
+            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
             cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
         }
     }
@@ -487,7 +558,7 @@
     mTextTexture->deferedUploadToTexture(mRSC, false, 0);
 
     // Split up our cache texture into lines of certain widths
-    int nextLine = 0;
+    int32_t nextLine = 0;
     mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
     nextLine += mCacheLines.top()->mMaxHeight;
     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
@@ -519,8 +590,8 @@
 
     // Four verts, two triangles , six indices per quad
     for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
-        int i6 = i * 6;
-        int i4 = i * 4;
+        int32_t i6 = i * 6;
+        int32_t i4 = i * 4;
 
         indexPtr[i6 + 0] = i4 + 0;
         indexPtr[i6 + 1] = i4 + 1;
@@ -713,7 +784,11 @@
 }
 
 
-void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
+void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
+                           uint32_t startIndex, int32_t numGlyphs,
+                           Font::RenderMode mode,
+                           Font::Rect *bounds,
+                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
 {
     checkInit();
 
@@ -730,7 +805,8 @@
         return;
     }
 
-    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
+    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
+                           mode, bounds, bitmap, bitmapW, bitmapH);
 
     if(mCurrentQuadIndex != 0) {
         issueDrawCommand();
@@ -738,32 +814,8 @@
     }
 }
 
-void FontState::renderText(const char *text, int x, int y)
-{
-    size_t textLen = strlen(text);
-    renderText(text, textLen, 0, -1, x, y);
-}
-
-void FontState::renderText(Allocation *alloc, int x, int y)
-{
-    if(!alloc) {
-        return;
-    }
-
-    const char *text = (const char *)alloc->getPtr();
-    size_t allocSize = alloc->getType()->getSizeBytes();
-    renderText(text, allocSize, 0, -1, x, y);
-}
-
-void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
-{
-    if(!alloc) {
-        return;
-    }
-
-    const char *text = (const char *)alloc->getPtr();
-    size_t allocSize = alloc->getType()->getSizeBytes();
-    renderText(text, allocSize, start, len, x, y);
+void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
+    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
 }
 
 void FontState::setFontColor(float r, float g, float b, float a) {
@@ -773,7 +825,7 @@
     mConstants.mFontColor[3] = a;
 
     mConstants.mGamma = 1.0f;
-    const int luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
+    const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
     if (luminance <= mBlackThreshold) {
         mConstants.mGamma = mBlackGamma;
     } else if (luminance >= mWhiteThreshold) {
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 16009ef..0012b84 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -45,12 +45,26 @@
 class Font : public ObjectBase
 {
 public:
-    ~Font();
+    enum RenderMode {
+        FRAMEBUFFER,
+        BITMAP,
+        MEASURE,
+    };
 
-    // Pointer to the utf data, length of data, where to start, number of glyphs ot read
-    // (each glyph may be longer than a char because we are dealing with utf data)
-    // Last two variables are the initial pen position
-    void renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y);
+    struct Rect {
+        int32_t left;
+        int32_t top;
+        int32_t right;
+        int32_t bottom;
+        void set(int32_t l, int32_t r, int32_t t, int32_t b) {
+            left = l;
+            right = r;
+            top = t;
+            bottom = b;
+        }
+    };
+
+    ~Font();
 
     // Currently files do not get serialized,
     // but we need to inherit from ObjectBase for ref tracking
@@ -66,6 +80,14 @@
 
     friend class FontState;
 
+    // Pointer to the utf data, length of data, where to start, number of glyphs ot read
+    // (each glyph may be longer than a char because we are dealing with utf data)
+    // Last two variables are the initial pen position
+    void renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
+                   uint32_t start, int32_t numGlyphs,
+                   RenderMode mode = FRAMEBUFFER, Rect *bounds = NULL,
+                   uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);
+
     void invalidateTextureCache();
     struct CachedGlyphInfo
     {
@@ -106,7 +128,10 @@
 
     CachedGlyphInfo *cacheGlyph(uint32_t glyph);
     void updateGlyphCache(CachedGlyphInfo *glyph);
-    void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
+    void measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds);
+    void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y);
+    void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y,
+                         uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);
 };
 
 class FontState
@@ -121,10 +146,13 @@
     ObjectBaseRef<Font> mDefault;
     ObjectBaseRef<Font> mLast;
 
-    void renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y);
-    void renderText(const char *text, int x, int y);
-    void renderText(Allocation *alloc, int x, int y);
-    void renderText(Allocation *alloc, uint32_t start, int len, int x, int y);
+    void renderText(const char *text, uint32_t len, int32_t x, int32_t y,
+                    uint32_t startIndex = 0, int numGlyphs = -1,
+                    Font::RenderMode mode = Font::FRAMEBUFFER,
+                    Font::Rect *bounds = NULL,
+                    uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);
+
+    void measureText(const char *text, uint32_t len, Font::Rect *bounds);
 
     void setFontColor(float r, float g, float b, float a);
     void getFontColor(float *r, float *g, float *b, float *a) const;
@@ -198,6 +226,9 @@
     // Texture to cache glyph bitmaps
     ObjectBaseRef<Allocation> mTextTexture;
     void initTextTexture();
+    const uint8_t* getTextTextureData() const {
+        return (uint8_t*)mTextTexture->getPtr();
+    }
 
     bool cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
     const Type* getCacheTextureType() {
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 88db761..b991cab 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -351,13 +351,59 @@
     CHECK_OBJ(va);
     GET_TLS();
     Allocation *alloc = static_cast<Allocation *>(va);
-    rsc->mStateFont.renderText(alloc, x, y);
+    const char *text = (const char *)alloc->getPtr();
+    size_t allocSize = alloc->getType()->getSizeBytes();
+    rsc->mStateFont.renderText(text, allocSize, x, y);
 }
 
 static void SC_DrawText(const char *text, int x, int y)
 {
     GET_TLS();
-    rsc->mStateFont.renderText(text, x, y);
+    size_t textLen = strlen(text);
+    rsc->mStateFont.renderText(text, textLen, x, y);
+}
+
+static void SC_setMetrics(Font::Rect *metrics,
+                          int32_t *left, int32_t *right,
+                          int32_t *top, int32_t *bottom)
+{
+    if(left) {
+        *left = metrics->left;
+    }
+    if(right) {
+        *right = metrics->right;
+    }
+    if(top) {
+        *top = metrics->top;
+    }
+    if(bottom) {
+        *bottom = metrics->bottom;
+    }
+}
+
+static void SC_MeasureTextAlloc(RsAllocation va,
+                                int32_t *left, int32_t *right,
+                                int32_t *top, int32_t *bottom)
+{
+    CHECK_OBJ(va);
+    GET_TLS();
+    Allocation *alloc = static_cast<Allocation *>(va);
+    const char *text = (const char *)alloc->getPtr();
+    size_t textLen = alloc->getType()->getSizeBytes();
+    Font::Rect metrics;
+    rsc->mStateFont.measureText(text, textLen, &metrics);
+    SC_setMetrics(&metrics, left, right, top, bottom);
+}
+
+static void SC_MeasureText(const char *text,
+                           int32_t *left, int32_t *right,
+                           int32_t *top, int32_t *bottom)
+{
+    GET_TLS();
+    size_t textLen = strlen(text);
+    Font::Rect metrics;
+    rsc->mStateFont.measureText(text, textLen, &metrics);
+    SC_setMetrics(&metrics, left, right, top, bottom);
 }
 
 static void SC_BindFont(RsFont font)
@@ -432,6 +478,8 @@
 
     { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText },
     { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc },
+    { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText },
+    { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc },
 
     { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont },
     { "_Z12rsgFontColorffff", (void *)&SC_FontColor },
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index c0b2d2d..ac6f8cc 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -79,6 +79,12 @@
     rsgBindFont(rs_font);
 extern void __attribute__((overloadable))
     rsgFontColor(float, float, float, float);
+// Returns the bounding box of the text relative to (0, 0)
+// Any of left, right, top, bottom could be NULL
+extern void __attribute__((overloadable))
+    rsgMeasureText(const char *, int *left, int *right, int *top, int *bottom);
+extern void __attribute__((overloadable))
+    rsgMeasureText(rs_allocation, int *left, int *right, int *top, int *bottom);
 
 extern void __attribute__((overloadable))
     rsgMeshComputeBoundingBox(rs_mesh mesh, float *minX, float *minY, float *minZ,
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index 468ba2a..8da7eaa 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -18,23 +18,29 @@
 

 import java.io.IOException;

 

+import android.util.Log;

+

 /**

  * This class allows to handle an audio track. This audio file is mixed with the

  * audio samples of the MediaItems.

  * {@hide}

  */

 public class AudioTrack {

+    // Logging

+    private static final String TAG = "AudioTrack";

+

     // Instance variables

     private final String mUniqueId;

     private final String mFilename;

-    private final long mDurationMs;

     private long mStartTimeMs;

     private long mTimelineDurationMs;

     private int mVolumePercent;

     private long mBeginBoundaryTimeMs;

     private long mEndBoundaryTimeMs;

     private boolean mLoop;

+    private boolean mMuted;

 

+    private final long mDurationMs;

     private final int mAudioChannels;

     private final int mAudioType;

     private final int mAudioBitrate;

@@ -47,6 +53,129 @@
 

     // The audio waveform filename

     private String mAudioWaveformFilename;

+    private PlaybackThread mPlaybackThread;

+

+    /**

+     * This listener interface is used by the AudioTrack to emit playback

+     * progress notifications.

+     */

+    public interface PlaybackProgressListener {

+        /**

+         * This method notifies the listener of the current time position while

+         * playing an audio track

+         *

+         * @param audioTrack The audio track

+         * @param timeMs The current playback position (expressed in milliseconds

+         *            since the beginning of the audio track).

+         * @param end true if the end of the audio track was reached

+         */

+        public void onProgress(AudioTrack audioTrack, long timeMs, boolean end);

+    }

+

+    /**

+     * The playback thread

+     */

+    private class PlaybackThread extends Thread {

+        // Instance variables

+        private final PlaybackProgressListener mListener;

+        private final long mFromMs, mToMs;

+        private boolean mRun;

+        private final boolean mLoop;

+        private long mPositionMs;

+

+        /**

+         * Constructor

+         *

+         * @param fromMs The time (relative to the beginning of the audio track)

+         *            at which the playback will start

+         * @param toMs The time (relative to the beginning of the audio track) at

+         *            which the playback will stop. Use -1 to play to the end of

+         *            the audio track

+         * @param loop true if the playback should be looped once it reaches the

+         *            end

+         * @param listener The listener which will be notified of the playback

+         *            progress

+         */

+        public PlaybackThread(long fromMs, long toMs, boolean loop,

+                PlaybackProgressListener listener) {

+            mPositionMs = mFromMs = fromMs;

+            if (toMs < 0) {

+                mToMs = mDurationMs;

+            } else {

+                mToMs = toMs;

+            }

+            mLoop = loop;

+            mListener = listener;

+            mRun = true;

+        }

+

+        /*

+         * {@inheritDoc}

+         */

+        @Override

+        public void run() {

+            if (Log.isLoggable(TAG, Log.DEBUG)) {

+                Log.d(TAG, "===> PlaybackThread.run enter");

+            }

+

+            while (mRun) {

+                try {

+                    sleep(100);

+                } catch (InterruptedException ex) {

+                    break;

+                }

+

+                mPositionMs += 100;

+

+                if (mPositionMs >= mToMs) {

+                    if (!mLoop) {

+                        if (mListener != null) {

+                            mListener.onProgress(AudioTrack.this, mPositionMs, true);

+                        }

+                        if (Log.isLoggable(TAG, Log.DEBUG)) {

+                            Log.d(TAG, "PlaybackThread.run playback complete");

+                        }

+                        break;

+                    } else {

+                        // Fire a notification for the end of the clip

+                        if (mListener != null) {

+                            mListener.onProgress(AudioTrack.this, mToMs, false);

+                        }

+

+                        // Rewind

+                        mPositionMs = mFromMs;

+                        if (mListener != null) {

+                            mListener.onProgress(AudioTrack.this, mPositionMs, false);

+                        }

+                        if (Log.isLoggable(TAG, Log.DEBUG)) {

+                            Log.d(TAG, "PlaybackThread.run playback complete");

+                        }

+                    }

+                } else {

+                    if (mListener != null) {

+                        mListener.onProgress(AudioTrack.this, mPositionMs, false);

+                    }

+                }

+            }

+            if (Log.isLoggable(TAG, Log.DEBUG)) {

+                Log.d(TAG, "===> PlaybackThread.run exit");

+            }

+        }

+

+        /**

+         * Stop the playback

+         *

+         * @return The stop position

+         */

+        public long stopPlayback() {

+            mRun = false;

+            try {

+                join();

+            } catch (InterruptedException ex) {

+            }

+            return mPositionMs;

+        }

+    };

 

     /**

      * An object of this type cannot be instantiated by using the default

@@ -59,7 +188,7 @@
 

     /**

      * Constructor

-     * @param audioTrackId The AudioTrack id

+     * @param audioTrackId The audio track id

      * @param filename The absolute file name

      *

      * @throws IOException if file is not found

@@ -89,6 +218,9 @@
         // By default loop is disabled

         mLoop = false;

 

+        // By default the audio track is not muted

+        mMuted = false;

+

         // Ducking is enabled by default

         mDuckingThreshold = 0;

         mDuckingLowVolume = 0;

@@ -99,7 +231,53 @@
     }

 

     /**

-     * @return The id of the media item

+     * Constructor

+     *

+     * @param audioTrackId The audio track id

+     * @param filename The audio filename

+     * @param startTimeMs the start time in milliseconds (relative to the

+     *              timeline)

+     * @param beginMs start time in the audio track in milliseconds (relative to

+     *            the beginning of the audio track)

+     * @param endMs end time in the audio track in milliseconds (relative to the

+     *            beginning of the audio track)

+     * @param loop true to loop the audio track

+     * @param volume The volume in percentage

+     * @param muted true if the audio track is muted

+     * @param audioWaveformFilename The name of the waveform file

+     *

+     * @throws IOException if file is not found

+     */

+    AudioTrack(String audioTrackId, String filename, long startTimeMs, long beginMs, long endMs,

+            boolean loop, int volume, boolean muted, String audioWaveformFilename) throws IOException {

+        mUniqueId = audioTrackId;

+        mFilename = filename;

+        mStartTimeMs = startTimeMs;

+

+        // TODO: This value represents to the duration of the audio file

+        mDurationMs = 300000;

+

+        // TODO: This value needs to be read from the audio track of the source

+        // file

+        mAudioChannels = 2;

+        mAudioType = MediaProperties.ACODEC_AAC_LC;

+        mAudioBitrate = 128000;

+        mAudioSamplingFrequency = 44100;

+

+        mTimelineDurationMs = endMs - beginMs;

+        mVolumePercent = volume;

+

+        mBeginBoundaryTimeMs = beginMs;

+        mEndBoundaryTimeMs = endMs;

+

+        mLoop = loop;

+        mMuted = muted;

+

+        mAudioWaveformFilename = audioWaveformFilename;

+    }

+

+    /**

+     * @return The id of the audio track

      */

     public String getId() {

         return mUniqueId;

@@ -169,6 +347,20 @@
     }

 

     /**

+     * @param muted true to mute the audio track

+     */

+    public void setMute(boolean muted) {

+        mMuted = muted;

+    }

+

+    /**

+     * @return true if the audio track is muted

+     */

+    public boolean isMuted() {

+        return mMuted;

+    }

+

+    /**

      * Set the start time of this audio track relative to the storyboard

      * timeline. Default value is 0.

      *

@@ -312,6 +504,50 @@
     }

 

     /**

+     * Start the playback of this audio track. This method does not block (does

+     * not wait for the playback to complete).

+     *

+     * @param fromMs The time (relative to the beginning of the audio track) at

+     *            which the playback will start

+     * @param toMs The time (relative to the beginning of the audio track) at

+     *            which the playback will stop. Use -1 to play to the end of the

+     *            audio track

+     * @param loop true if the playback should be looped once it reaches the end

+     * @param listener The listener which will be notified of the playback

+     *            progress

+     * @throws IllegalArgumentException if fromMs or toMs is beyond the playback

+     *             duration

+     * @throws IllegalStateException if a playback, preview or an export is

+     *             already in progress

+     */

+    public void startPlayback(long fromMs, long toMs, boolean loop,

+            PlaybackProgressListener listener) {

+        if (fromMs >= mDurationMs) {

+            return;

+        }

+        mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, listener);

+        mPlaybackThread.start();

+    }

+

+    /**

+     * Stop the audio track playback. This method blocks until the ongoing

+     * playback is stopped.

+     *

+     * @return The accurate current time when stop is effective expressed in

+     *         milliseconds

+     */

+    public long stopPlayback() {

+        final long stopTimeMs;

+        if (mPlaybackThread != null) {

+            stopTimeMs = mPlaybackThread.stopPlayback();

+            mPlaybackThread = null;

+        } else {

+            stopTimeMs = 0;

+        }

+        return stopTimeMs;

+    }

+

+    /**

      * This API allows to generate a file containing the sample volume levels of

      * this audio track object. This function may take significant time and is

      * blocking. The filename can be retrieved using getAudioWaveformFilename().

diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index 47d4fa0..cc0a155 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -20,7 +20,6 @@
 import java.util.List;

 

 import android.graphics.Bitmap;

-import android.media.MediaRecorder;

 import android.util.Log;

 import android.view.SurfaceHolder;

 

@@ -50,6 +49,7 @@
     private long mBeginBoundaryTimeMs;

     private long mEndBoundaryTimeMs;

     private int mVolumePercentage;

+    private boolean mMuted;

     private String mAudioWaveformFilename;

     private PlaybackThread mPlaybackThread;

 

@@ -207,7 +207,7 @@
      */

     public MediaVideoItem(String mediaItemId, String filename, int renderingMode)

         throws IOException {

-        this(mediaItemId, filename, renderingMode, null);

+        this(mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);

     }

 

     /**

@@ -216,11 +216,19 @@
      * @param mediaItemId The MediaItem id

      * @param filename The image file name

      * @param renderingMode The rendering mode

+     * @param beginMs Start time in milliseconds. Set to 0 to extract from the

+     *           beginning

+     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to

+     *           extract until the end

+     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%

+     *            means double, 0% means silent.

+     * @param muted true if the audio is muted

      * @param audioWaveformFilename The name of the audio waveform file

      *

      * @throws IOException if the file cannot be opened for reading

      */

     MediaVideoItem(String mediaItemId, String filename, int renderingMode,

+            long beginMs, long endMs, int volumePercent, boolean muted,

             String audioWaveformFilename)  throws IOException {

         super(mediaItemId, filename, renderingMode);

         // TODO: Set these variables correctly

@@ -228,7 +236,7 @@
         mHeight = 720;

         mAspectRatio = MediaProperties.ASPECT_RATIO_3_2;

         mFileType = MediaProperties.FILE_MP4;

-        mVideoType = MediaRecorder.VideoEncoder.H264;

+        mVideoType = MediaProperties.VCODEC_H264BP;

         // Do we have predefined values for this variable?

         mVideoProfile = 0;

         // Can video and audio duration be different?

@@ -240,9 +248,10 @@
         mAudioChannels = 2;

         mAudioSamplingFrequency = 16000;

 

-        mBeginBoundaryTimeMs = 0;

-        mEndBoundaryTimeMs = mDurationMs;

-        mVolumePercentage = 100;

+        mBeginBoundaryTimeMs = beginMs;

+        mEndBoundaryTimeMs = endMs == END_OF_FILE ? mDurationMs : endMs;

+        mVolumePercentage = volumePercent;

+        mMuted = muted;

         mAudioWaveformFilename = audioWaveformFilename;

     }

 

@@ -540,6 +549,20 @@
     }

 

     /**

+     * @param muted true to mute the media item

+     */

+    public void setMute(boolean muted) {

+        mMuted = muted;

+    }

+

+    /**

+     * @return true if the media item is muted

+     */

+    public boolean isMuted() {

+        return mMuted;

+    }

+

+    /**

      * @return The video type

      */

     public int getVideoType() {

diff --git a/media/java/android/media/videoeditor/VideoEditorFactory.java b/media/java/android/media/videoeditor/VideoEditorFactory.java
index 8081d76..0a377e2 100755
--- a/media/java/android/media/videoeditor/VideoEditorFactory.java
+++ b/media/java/android/media/videoeditor/VideoEditorFactory.java
@@ -66,11 +66,11 @@
             }
         }
 
-        Class<?> cls = Class.forName(className);
-        Class<?> partypes[] = new Class[1];
+        final Class<?> cls = Class.forName(className);
+        final Class<?> partypes[] = new Class[1];
         partypes[0] = String.class;
-        Constructor<?> ct = cls.getConstructor(partypes);
-        Object arglist[] = new Object[1];
+        final Constructor<?> ct = cls.getConstructor(partypes);
+        final Object arglist[] = new Object[1];
         arglist[0] = projectPath;
 
         return (VideoEditor)ct.newInstance(arglist);
@@ -84,6 +84,7 @@
      * @param projectPath The path where all VideoEditor internal files
      *            are stored. When a project is deleted the application is
      *            responsible for deleting the path and its contents.
+     * @param className The implementation class name
      * @param generatePreview if set to true the
      *      {@link MediaEditor#generatePreview()} will be called internally to
      *      generate any needed transitions.
@@ -96,8 +97,17 @@
      * @throws IllegalStateException if a previous VideoEditor instance has not
      *             been released
      */
-    public static VideoEditor load(String projectPath, boolean generatePreview) throws IOException {
-        final VideoEditorTestImpl videoEditor = new VideoEditorTestImpl(projectPath);
+    public static VideoEditor load(String projectPath, String className, boolean generatePreview)
+            throws IOException, ClassNotFoundException, NoSuchMethodException,
+            InvocationTargetException, IllegalAccessException, InstantiationException {
+        final Class<?> cls = Class.forName(className);
+        final Class<?> partypes[] = new Class[1];
+        partypes[0] = String.class;
+        final Constructor<?> ct = cls.getConstructor(partypes);
+        final Object arglist[] = new Object[1];
+        arglist[0] = projectPath;
+
+        final VideoEditor videoEditor = (VideoEditor)ct.newInstance(arglist);
         if (generatePreview) {
             videoEditor.generatePreview();
         }
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
index 16f9495..b39d9d8 100644
--- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
@@ -57,6 +57,8 @@
     private static final String TAG_OVERLAY_USER_ATTRIBUTES = "overlay_user_attributes";
     private static final String TAG_EFFECTS = "effects";
     private static final String TAG_EFFECT = "effect";
+    private static final String TAG_AUDIO_TRACKS = "audio_tracks";
+    private static final String TAG_AUDIO_TRACK = "audio_track";
 
     private static final String ATTR_ID = "id";
     private static final String ATTR_FILENAME = "filename";
@@ -65,7 +67,8 @@
     private static final String ATTR_ASPECT_RATIO = "aspect_ratio";
     private static final String ATTR_TYPE = "type";
     private static final String ATTR_DURATION = "duration";
-    private static final String ATTR_BEGIN_TIME = "start_time";
+    private static final String ATTR_START_TIME = "start_time";
+    private static final String ATTR_BEGIN_TIME = "begin_time";
     private static final String ATTR_END_TIME = "end_time";
     private static final String ATTR_VOLUME = "volume";
     private static final String ATTR_BEHAVIOR = "behavior";
@@ -85,6 +88,8 @@
     private static final String ATTR_END_RECT_T = "end_t";
     private static final String ATTR_END_RECT_R = "end_r";
     private static final String ATTR_END_RECT_B = "end_b";
+    private static final String ATTR_LOOP = "loop";
+    private static final String ATTR_MUTED = "muted";
 
     // Instance variables
     private long mDurationMs;
@@ -537,16 +542,13 @@
      * {@inheritDoc}
      */
     public AudioTrack getAudioTrack(String audioTrackId) {
-        if (mPreviewThread != null) {
-            throw new IllegalStateException("Previewing is in progress");
+        for (AudioTrack at : mAudioTracks) {
+            if (at.getId().equals(audioTrackId)) {
+                return at;
+            }
         }
 
-        final AudioTrack audioTrack = getAudioTrack(audioTrackId);
-        if (audioTrack != null) {
-            mAudioTracks.remove(audioTrack);
-        }
-
-        return audioTrack;
+        return null;
     }
 
     /*
@@ -581,6 +583,7 @@
                         .attribute("", ATTR_BEGIN_TIME, Long.toString(mvi.getBoundaryBeginTime()));
                 serializer.attribute("", ATTR_END_TIME, Long.toString(mvi.getBoundaryEndTime()));
                 serializer.attribute("", ATTR_VOLUME, Integer.toString(mvi.getVolume()));
+                serializer.attribute("", ATTR_MUTED, Boolean.toString(mvi.isMuted()));
                 if (mvi.getAudioWaveformFilename() != null) {
                     serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
                             mvi.getAudioWaveformFilename());
@@ -703,6 +706,26 @@
         }
         serializer.endTag("", TAG_TRANSITIONS);
 
+        serializer.startTag("", TAG_AUDIO_TRACKS);
+        for (AudioTrack at : mAudioTracks) {
+            serializer.startTag("", TAG_AUDIO_TRACK);
+            serializer.attribute("", ATTR_ID, at.getId());
+            serializer.attribute("", ATTR_FILENAME, at.getFilename());
+            serializer.attribute("", ATTR_START_TIME, Long.toString(at.getStartTime()));
+            serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(at.getBoundaryBeginTime()));
+            serializer.attribute("", ATTR_END_TIME, Long.toString(at.getBoundaryEndTime()));
+            serializer.attribute("", ATTR_VOLUME, Integer.toString(at.getVolume()));
+            serializer.attribute("", ATTR_MUTED, Boolean.toString(at.isMuted()));
+            serializer.attribute("", ATTR_LOOP, Boolean.toString(at.isLooping()));
+            if (at.getAudioWaveformFilename() != null) {
+                serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
+                at.getAudioWaveformFilename());
+            }
+
+            serializer.endTag("", TAG_AUDIO_TRACK);
+        }
+        serializer.endTag("", TAG_AUDIO_TRACKS);
+
         serializer.endTag("", TAG_PROJECT);
         serializer.endDocument();
 
@@ -745,10 +768,19 @@
                             currentMediaItem = new MediaImageItem(mediaItemId, filename,
                                     durationMs, renderingMode);
                         } else if (MediaVideoItem.class.getSimpleName().equals(type)) {
+                            final long beginMs = Long.parseLong(parser.getAttributeValue("",
+                                    ATTR_BEGIN_TIME));
+                            final long endMs = Long.parseLong(parser.getAttributeValue("",
+                                    ATTR_END_TIME));
+                            final int volume = Integer.parseInt(parser.getAttributeValue("",
+                                    ATTR_VOLUME));
+                            final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("",
+                                    ATTR_MUTED));
                             final String audioWaveformFilename = parser.getAttributeValue("",
                                     ATTR_AUDIO_WAVEFORM_FILENAME);
                             currentMediaItem = new MediaVideoItem(mediaItemId, filename,
-                                    renderingMode, audioWaveformFilename);
+                                    renderingMode, beginMs, endMs, volume, muted,
+                                    audioWaveformFilename);
 
                             final long beginTimeMs = Long.parseLong(parser.getAttributeValue("",
                                     ATTR_BEGIN_TIME));
@@ -795,6 +827,11 @@
                                 currentMediaItem.addEffect(effect);
                             }
                         }
+                    } else if (TAG_AUDIO_TRACK.equals(name)) {
+                        final AudioTrack audioTrack = parseAudioTrack(parser);
+                        if (audioTrack != null) {
+                            addAudioTrack(audioTrack);
+                        }
                     }
                     break;
                 }
@@ -962,6 +999,33 @@
         return effect;
     }
 
+    /**
+     * Parse the audio track
+     *
+     * @param parser The parser
+     *
+     * @return The audio track
+     */
+    private AudioTrack parseAudioTrack(XmlPullParser parser) {
+        final String audioTrackId = parser.getAttributeValue("", ATTR_ID);
+        final String filename = parser.getAttributeValue("", ATTR_FILENAME);
+        final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_START_TIME));
+        final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
+        final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME));
+        final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME));
+        final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED));
+        final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_LOOP));
+        final String waveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME);
+        try {
+            final AudioTrack audioTrack = new AudioTrack(audioTrackId, filename, startTimeMs,
+                    beginMs, endMs, loop, volume, muted, waveformFilename);
+
+            return audioTrack;
+        } catch (IOException ex) {
+            return null;
+        }
+    }
+
     public void cancelExport(String filename) {
     }
 
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
index d894f7b..e74c22f 100644
--- a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
+++ b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
index 744178f..d6c8a21 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
index 3e317dd..b16e436 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
index 2f66b1d..b16e436 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
index 72329f8..1b6ed74 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
index 72329f8..43e35d3 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
index 558c49c..498adbb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
index 558c49c..b7e42a0 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
index 6440bdd..959fc5c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
index 6440bdd..f905979 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
index fe20423..6e8e73c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
index fe20423..b5799c8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
new file mode 100644
index 0000000..a0def6b
--- /dev/null
+++ b/packages/SystemUI/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?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.
+ */
+-->
+<resources>
+    <drawable name="notification_number_text_color">#ffffffff</drawable>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
index 027bed4a..e87d003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
@@ -23,28 +23,34 @@
 import android.view.View;
 import android.widget.LinearLayout;
 
+import com.android.internal.statusbar.StatusBarIcon;
+
 import com.android.systemui.R;
 
 
 public class IconMerger extends LinearLayout {
     private static final String TAG = "IconMerger";
 
+    private int mIconSize;
     private StatusBarIconView mMoreView;
+    private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0);
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        mIconSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_icon_size);
+
+        mMoreView = new StatusBarIconView(context, "more");
+        mMoreView.set(mMoreIcon);
+        addView(mMoreView, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
     }
 
-    public void addMoreView(StatusBarIconView v, LinearLayout.LayoutParams lp) {
-        super.addView(v, lp);
-        mMoreView = v;
-    }
-
-    public void addView(StatusBarIconView v, int index, LinearLayout.LayoutParams lp) {
+    public void addView(StatusBarIconView v, int index) {
         if (index == 0) {
             throw new RuntimeException("Attempt to put view before the more view: " + v);
         }
-        super.addView(v, index, lp);
+        addView(v, index, new LinearLayout.LayoutParams(mIconSize, mIconSize));
     }
 
     @Override
@@ -127,28 +133,8 @@
                 }
             }
         }
-        
-        // BUG: Updating the text during the layout here doesn't seem to cause
-        // the view to be redrawn fully.  The text view gets resized correctly, but the
-        // text contents aren't drawn properly.  To work around this, we post a message
-        // and provide the value later.  We're the only one changing this value show it
-        // should be ordered correctly.
-        if (false) {
-            // TODO this.moreIcon.update(number);
-        } else {
-            mBugWorkaroundNumber = number;
-            mBugWorkaroundHandler.post(mBugWorkaroundRunnable);
-        }
-    }
 
-    private int mBugWorkaroundNumber;
-    private Handler mBugWorkaroundHandler = new Handler();
-    private Runnable mBugWorkaroundRunnable = new Runnable() {
-        public void run() {
-            /* TODO
-            IconMerger.this.moreIcon.update(mBugWorkaroundNumber);
-            IconMerger.this.moreIcon.view.invalidate();
-            */
-        }
-    };
+        mMoreIcon.number = number;
+        mMoreView.set(mMoreIcon);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index e945981..57ebd27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -274,12 +274,6 @@
 
         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
 
-        // the more notifications icon
-        StatusBarIconView moreView = new StatusBarIconView(this, "more");
-        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
-        mNotificationIcons.addMoreView(moreView,
-                new LinearLayout.LayoutParams(mIconSize, mIconSize));
-
         // set the inital view visibility
         setAreThereNotifications();
         mDateView.setVisibility(View.INVISIBLE);
@@ -579,8 +573,7 @@
         parent.addView(row, viewIndex);
         // Add the icon.
         final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
-        mNotificationIcons.addView(iconView, iconIndex,
-                new LinearLayout.LayoutParams(mIconSize, mIconSize));
+        mNotificationIcons.addView(iconView, iconIndex);
         return iconView;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 0ca0572..8419e56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -21,22 +21,37 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.util.Slog;
 import android.util.Log;
+import android.view.View;
 import android.view.ViewDebug;
 import android.widget.FrameLayout;
 
 import com.android.internal.statusbar.StatusBarIcon;
 
+import com.android.systemui.R;
+
 public class StatusBarIconView extends AnimatedImageView {
     private static final String TAG = "StatusBarIconView";
 
     private StatusBarIcon mIcon;
     @ViewDebug.ExportedProperty private String mSlot;
+    private Drawable mNumberBackground;
+    private Paint mNumberPain;
+    private int mNumberX;
+    private int mNumberY;
+    private String mNumberText;
 
     public StatusBarIconView(Context context, String slot) {
         super(context);
+        final Resources res = context.getResources();
         mSlot = slot;
+        mNumberPain = new Paint();
+        mNumberPain.setTextAlign(Paint.Align.CENTER);
+        mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color));
+        mNumberPain.setAntiAlias(true);
     }
 
     private static boolean streq(String a, String b) {
@@ -63,6 +78,9 @@
                 && mIcon.iconLevel == icon.iconLevel;
         final boolean visibilityEquals = mIcon != null
                 && mIcon.visible == icon.visible;
+        final boolean numberEquals = mIcon != null
+                && mIcon.number == icon.number;
+        mIcon = icon.clone();
         if (!iconEquals) {
             Drawable drawable = getIcon(icon);
             if (drawable == null) {
@@ -74,10 +92,22 @@
         if (!levelEquals) {
             setImageLevel(icon.iconLevel);
         }
+        if (!numberEquals) {
+            if (icon.number > 0) {
+                if (mNumberBackground == null) {
+                    mNumberBackground = getContext().getResources().getDrawable(
+                            R.drawable.ic_notification_overlay);
+                }
+                placeNumber();
+            } else {
+                mNumberBackground = null;
+                mNumberText = null;
+            }
+            invalidate();
+        }
         if (!visibilityEquals) {
             setVisibility(icon.visible ? VISIBLE : GONE);
         }
-        mIcon = icon.clone();
         return true;
     }
 
@@ -126,9 +156,47 @@
         return mIcon;
     }
 
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mNumberBackground != null) {
+            placeNumber();
+        }
+    }
+
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (mNumberBackground != null) {
+            mNumberBackground.draw(canvas);
+            canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
+        }
+    }
+
     protected void debug(int depth) {
         super.debug(depth);
         Log.d("View", debugIndent(depth) + "slot=" + mSlot);
         Log.d("View", debugIndent(depth) + "icon=" + mIcon);
     }
+
+    void placeNumber() {
+        final String str = mNumberText = Integer.toString(mIcon.number);
+        final int w = getWidth();
+        final int h = getHeight();
+        final Rect r = new Rect();
+        mNumberPain.getTextBounds(str, 0, str.length(), r);
+        final int tw = r.right - r.left;
+        final int th = r.bottom - r.top;
+        mNumberBackground.getPadding(r);
+        int dw = r.left + tw + r.right;
+        if (dw < mNumberBackground.getMinimumWidth()) {
+            dw = mNumberBackground.getMinimumWidth();
+        }
+        mNumberX = w-r.right-((dw-r.right-r.left)/2);
+        int dh = r.top + th + r.bottom;
+        if (dh < mNumberBackground.getMinimumWidth()) {
+            dh = mNumberBackground.getMinimumWidth();
+        }
+        mNumberY = h-r.bottom-((dh-r.top-th-r.bottom)/2);
+        mNumberBackground.setBounds(w-dw, h-dh, w, h);
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c70f5d4..33685ba 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -296,7 +296,8 @@
 
     int mLandscapeRotation = -1; // default landscape rotation
     int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation
-    int mPortraitRotation = -1;
+    int mPortraitRotation = -1; // default portrait rotation
+    int mUpsideDownRotation = -1; // "other" portrait rotation
 
     // Nothing to see here, move along...
     int mFancyRotationAnimation;
@@ -364,26 +365,25 @@
 
     boolean useSensorForOrientationLp(int appOrientation) {
         // The app says use the sensor.
-        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
+        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
             return true;
         }
         // The user preference says we can rotate, and the app is willing to rotate.
-        // Note we include SCREEN_ORIENTATION_LANDSCAPE since we can use the sensor to choose
-        // between the two possible landscape rotations.
         if (mAccelerometerDefault != 0 &&
                 (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
-                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
+                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
             return true;
         }
-        // We're in a dock that has a rotation affinity, an the app is willing to rotate.
+        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
         if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
                 || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
             // Note we override the nosensor flag here.
             if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
                     || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
-                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
                 return true;
             }
         }
@@ -397,7 +397,10 @@
      * screen is switched off.
      */
     boolean needSensorRunningLp() {
-        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
+        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
             // If the application has explicitly requested to follow the
             // orientation, then we need to turn the sensor or.
             return true;
@@ -2133,21 +2136,42 @@
             if (d.getWidth() > d.getHeight()) {
                 mPortraitRotation = Surface.ROTATION_90;
                 mLandscapeRotation = Surface.ROTATION_0;
+                mUpsideDownRotation = Surface.ROTATION_270;
                 mSeascapeRotation = Surface.ROTATION_180;
             } else {
                 mPortraitRotation = Surface.ROTATION_0;
                 mLandscapeRotation = Surface.ROTATION_90;
+                mUpsideDownRotation = Surface.ROTATION_180;
                 mSeascapeRotation = Surface.ROTATION_270;
             }
         }
 
         synchronized (mLock) {
-            if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
-                //always return portrait if orientation set to portrait
-                return mPortraitRotation;
-            } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
-                return getCurrentLandscapeRotation(lastRotation);
+            switch (orientation) {
+                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+                    //always return portrait if orientation set to portrait
+                    return mPortraitRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+                    //always return landscape if orientation set to landscape
+                    return mLandscapeRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+                    //always return portrait if orientation set to portrait
+                    return mUpsideDownRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+                    //always return seascape if orientation set to reverse landscape
+                    return mSeascapeRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+                    //return either landscape rotation based on the sensor
+                    mOrientationListener.setAllow180Rotation(false);
+                    return getCurrentLandscapeRotation(lastRotation);
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+                    mOrientationListener.setAllow180Rotation(true);
+                    return getCurrentPortraitRotation(lastRotation);
             }
+
+            mOrientationListener.setAllow180Rotation(
+                    orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+
             // case for nosensor meaning ignore sensor and consider only lid
             // or orientation sensor disabled
             //or case.unspecified
@@ -2167,18 +2191,15 @@
     }
 
     private int getCurrentLandscapeRotation(int lastRotation) {
-        // landscape-only apps can take either landscape rotation
-        if (useSensorForOrientationLp(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
-            int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
-            if (isLandscapeOrSeascape(sensorRotation)) {
-                return sensorRotation;
-            }
+        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
+        if (isLandscapeOrSeascape(sensorRotation)) {
+            return sensorRotation;
         }
         // try to preserve the old rotation if it was landscape
         if (isLandscapeOrSeascape(lastRotation)) {
             return lastRotation;
         }
-        // default to one of the two landscape rotations
+        // default to one of the primary landscape rotation
         return mLandscapeRotation;
     }
 
@@ -2186,6 +2207,23 @@
         return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
     }
 
+    private int getCurrentPortraitRotation(int lastRotation) {
+        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
+        if (isAnyPortrait(sensorRotation)) {
+            return sensorRotation;
+        }
+        // try to preserve the old rotation if it was portrait
+        if (isAnyPortrait(lastRotation)) {
+            return lastRotation;
+        }
+        // default to one of the primary portrait rotations
+        return mPortraitRotation;
+    }
+
+    private boolean isAnyPortrait(int sensorRotation) {
+        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
+    }
+
     public boolean detectSafeMode() {
         try {
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index a960097..fe306b3 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -342,7 +342,6 @@
         if (toChannel == null) {
             throw new IllegalArgumentException("toChannel must not be null.");
         }
-        Slog.d(TAG, "transferring touch focus");
         return nativeTransferTouchFocus(fromChannel, toChannel);
     }
     
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index de28375..9a5423c 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -117,6 +117,7 @@
 
     final Context mContext;
     final Handler mHandler;
+    final InputMethodSettings mSettings;
     final SettingsObserver mSettingsObserver;
     final StatusBarManagerService mStatusBar;
     final IWindowManager mIWindowManager;
@@ -126,13 +127,8 @@
 
     // All known input methods.  mMethodMap also serves as the global
     // lock for this class.
-    final ArrayList<InputMethodInfo> mMethodList
-            = new ArrayList<InputMethodInfo>();
-    final HashMap<String, InputMethodInfo> mMethodMap
-            = new HashMap<String, InputMethodInfo>();
-
-    final TextUtils.SimpleStringSplitter mStringColonSplitter
-            = new TextUtils.SimpleStringSplitter(':');
+    final ArrayList<InputMethodInfo> mMethodList = new ArrayList<InputMethodInfo>();
+    final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<String, InputMethodInfo>();
 
     class SessionState {
         final ClientState client;
@@ -483,27 +479,18 @@
         mStatusBar = statusBar;
         statusBar.setIconVisibility("ime", false);
 
+        // mSettings should be created before buildInputMethodListLocked
+        mSettings = new InputMethodSettings(context.getContentResolver(), mMethodMap, mMethodList);
         buildInputMethodListLocked(mMethodList, mMethodMap);
+        mSettings.enableAllIMEsIfThereIsNoEnabledIME();
 
-        final String enabledStr = Settings.Secure.getString(
-                mContext.getContentResolver(),
-                Settings.Secure.ENABLED_INPUT_METHODS);
-        Slog.i(TAG, "Enabled input methods: " + enabledStr);
-        final String defaultIme = Settings.Secure.getString(mContext
-                .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (enabledStr == null || TextUtils.isEmpty(defaultIme)) {
-            Slog.i(TAG, "Enabled input methods or default IME has not been set, enabling all");
+        if (TextUtils.isEmpty(Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD))) {
             InputMethodInfo defIm = null;
-            StringBuilder sb = new StringBuilder(256);
-            final int N = mMethodList.size();
-            for (int i=0; i<N; i++) {
-                InputMethodInfo imi = mMethodList.get(i);
-                Slog.i(TAG, "Adding: " + imi.getId());
-                if (i > 0) sb.append(':');
-                sb.append(imi.getId());
+            for (InputMethodInfo imi: mMethodList) {
                 if (defIm == null && imi.getIsDefaultResourceId() != 0) {
                     try {
-                        Resources res = mContext.createPackageContext(
+                        Resources res = context.createPackageContext(
                                 imi.getPackageName(), 0).getResources();
                         if (res.getBoolean(imi.getIsDefaultResourceId())) {
                             defIm = imi;
@@ -514,12 +501,10 @@
                     }
                 }
             }
-            if (defIm == null && N > 0) {
+            if (defIm == null && mMethodList.size() > 0) {
                 defIm = mMethodList.get(0);
                 Slog.i(TAG, "No default found, using " + defIm.getId());
             }
-            Settings.Secure.putString(mContext.getContentResolver(),
-                    Settings.Secure.ENABLED_INPUT_METHODS, sb.toString());
             if (defIm != null) {
                 Settings.Secure.putString(mContext.getContentResolver(),
                         Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId());
@@ -567,31 +552,10 @@
 
     public List<InputMethodInfo> getEnabledInputMethodList() {
         synchronized (mMethodMap) {
-            return getEnabledInputMethodListLocked();
+            return mSettings.getEnabledInputMethodListLocked();
         }
     }
 
-    List<InputMethodInfo> getEnabledInputMethodListLocked() {
-        final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
-
-        final String enabledStr = Settings.Secure.getString(
-                mContext.getContentResolver(),
-                Settings.Secure.ENABLED_INPUT_METHODS);
-        if (enabledStr != null) {
-            final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
-            splitter.setString(enabledStr);
-
-            while (splitter.hasNext()) {
-                InputMethodInfo info = mMethodMap.get(splitter.next());
-                if (info != null) {
-                    res.add(info);
-                }
-            }
-        }
-
-        return res;
-    }
-
     public void addClient(IInputMethodClient client,
             IInputContext inputContext, int uid, int pid) {
         synchronized (mMethodMap) {
@@ -1471,7 +1435,7 @@
     }
 
     private boolean chooseNewDefaultIMELocked() {
-        List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
+        List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
         if (enabled != null && enabled.size() > 0) {
             // We'd prefer to fall back on a system IME, since that is safer.
             int i=enabled.size();
@@ -1650,7 +1614,7 @@
                     hideInputMethodMenu();
                 }
             };
-    
+
             TypedArray a = context.obtainStyledAttributes(null,
                     com.android.internal.R.styleable.DialogPreference,
                     com.android.internal.R.attr.alertDialogStyle, 0);
@@ -1664,7 +1628,7 @@
                     .setIcon(a.getDrawable(
                             com.android.internal.R.styleable.DialogPreference_dialogTitle));
             a.recycle();
-    
+
             mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
                     new AlertDialog.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
@@ -1738,81 +1702,45 @@
         // Make sure this is a valid input method.
         InputMethodInfo imm = mMethodMap.get(id);
         if (imm == null) {
-            if (imm == null) {
-                throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
-            }
+            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
         }
 
-        StringBuilder builder = new StringBuilder(256);
+        List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
+                .getEnabledInputMethodsAndSubtypeListLocked();
 
-        boolean removed = false;
-        String firstId = null;
-
-        // Look through the currently enabled input methods.
-        String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.ENABLED_INPUT_METHODS);
-        if (enabledStr != null) {
-            final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
-            splitter.setString(enabledStr);
-            while (splitter.hasNext()) {
-                String curId = splitter.next();
-                if (curId.equals(id)) {
-                    if (enabled) {
-                        // We are enabling this input method, but it is
-                        // already enabled.  Nothing to do.  The previous
-                        // state was enabled.
-                        return true;
-                    }
-                    // We are disabling this input method, and it is
-                    // currently enabled.  Skip it to remove from the
-                    // new list.
-                    removed = true;
-                } else if (!enabled) {
-                    // We are building a new list of input methods that
-                    // doesn't contain the given one.
-                    if (firstId == null) firstId = curId;
-                    if (builder.length() > 0) builder.append(':');
-                    builder.append(curId);
+        if (enabled) {
+            for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
+                if (pair.first.equals(id)) {
+                    // We are enabling this input method, but it is already enabled.
+                    // Nothing to do. The previous state was enabled.
+                    return true;
                 }
             }
-        }
-
-        if (!enabled) {
-            if (!removed) {
-                // We are disabling the input method but it is already
-                // disabled.  Nothing to do.  The previous state was
-                // disabled.
+            mSettings.appendAndPutEnabledInputMethodLocked(id, false);
+            // Previous state was disabled.
+            return false;
+        } else {
+            StringBuilder builder = new StringBuilder();
+            if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
+                    builder, enabledInputMethodsList, id)) {
+                // 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)) {
+                    Settings.Secure.putString(
+                            mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
+                            enabledInputMethodsList.size() > 0
+                                    ? enabledInputMethodsList.get(0).first : "");
+                    resetSelectedInputMethodSubtype();
+                }
+                // Previous state was enabled.
+                return true;
+            } else {
+                // We are disabling the input method but it is already disabled.
+                // Nothing to do.  The previous state was disabled.
                 return false;
             }
-            // Update the setting with the new list of input methods.
-            Settings.Secure.putString(mContext.getContentResolver(),
-                    Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
-            // We the 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)) {
-                Settings.Secure.putString(mContext.getContentResolver(),
-                        Settings.Secure.DEFAULT_INPUT_METHOD,
-                        firstId != null ? firstId : "");
-                resetSelectedInputMethodSubtype();
-            }
-            // Previous state was enabled.
-            return true;
         }
-
-        // Add in the newly enabled input method.
-        if (enabledStr == null || enabledStr.length() == 0) {
-            enabledStr = id;
-        } else {
-            enabledStr = enabledStr + ':' + id;
-        }
-
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
-
-        // Previous state was disabled.
-        return false;
     }
 
     private void resetSelectedInputMethodSubtype() {
@@ -1862,6 +1790,161 @@
         return mCurrentSubtype;
     }
 
+    /**
+     * Utility class for putting and getting settings for InputMethod
+     * TODO: Move all putters and getters of settings to this class.
+     */
+    private static class InputMethodSettings {
+        // The string for enabled input method is saved as follows:
+        // example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
+        private static final char INPUT_METHOD_SEPARATER = ':';
+        private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
+        private final TextUtils.SimpleStringSplitter mStringColonSplitter =
+                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
+
+        private final TextUtils.SimpleStringSplitter mStringSemiColonSplitter =
+                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
+
+        private final ContentResolver mResolver;
+        private final HashMap<String, InputMethodInfo> mMethodMap;
+        private final ArrayList<InputMethodInfo> mMethodList;
+
+        private String mEnabledInputMethodsStrCache;
+
+        private static void buildEnabledInputMethodsSettingString(
+                StringBuilder builder, Pair<String, ArrayList<String>> pair) {
+            String id = pair.first;
+            ArrayList<String> subtypes = pair.second;
+            builder.append(id);
+            if (subtypes.size() > 0) {
+                builder.append(subtypes.get(0));
+                for (int i = 1; i < subtypes.size(); ++i) {
+                    builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypes.get(i));
+                }
+            }
+        }
+
+        public InputMethodSettings(
+                ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap,
+                ArrayList<InputMethodInfo> methodList) {
+            mResolver = resolver;
+            mMethodMap = methodMap;
+            mMethodList = methodList;
+        }
+
+        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
+            return createEnabledInputMethodListLocked(
+                    getEnabledInputMethodsAndSubtypeListLocked());
+        }
+
+        // At the initial boot, the settings for input methods are not set,
+        // so we need to enable IME in that case.
+        public void enableAllIMEsIfThereIsNoEnabledIME() {
+            if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
+                StringBuilder sb = new StringBuilder();
+                final int N = mMethodList.size();
+                for (int i = 0; i < N; i++) {
+                    InputMethodInfo imi = mMethodList.get(i);
+                    Slog.i(TAG, "Adding: " + imi.getId());
+                    if (i > 0) sb.append(':');
+                    sb.append(imi.getId());
+                }
+                putEnabledInputMethodsStr(sb.toString());
+            }
+        }
+
+        public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
+            ArrayList<Pair<String, ArrayList<String>>> imsList
+                    = new ArrayList<Pair<String, ArrayList<String>>>();
+            final String enabledInputMethodsStr = getEnabledInputMethodsStr();
+            if (TextUtils.isEmpty(enabledInputMethodsStr)) {
+                return imsList;
+            }
+            mStringColonSplitter.setString(enabledInputMethodsStr);
+            while (mStringColonSplitter.hasNext()) {
+                String nextImsStr = mStringColonSplitter.next();
+                mStringSemiColonSplitter.setString(nextImsStr);
+                if (mStringSemiColonSplitter.hasNext()) {
+                    ArrayList<String> subtypeHashes = new ArrayList<String>();
+                    // The first element is ime id.
+                    String imeId = mStringSemiColonSplitter.next();
+                    while (mStringSemiColonSplitter.hasNext()) {
+                        subtypeHashes.add(mStringSemiColonSplitter.next());
+                    }
+                    imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
+                }
+            }
+            return imsList;
+        }
+
+        public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
+            if (reloadInputMethodStr) {
+                getEnabledInputMethodsStr();
+            }
+            if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
+                // Add in the newly enabled input method.
+                putEnabledInputMethodsStr(id);
+            } else {
+                putEnabledInputMethodsStr(
+                        mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATER + id);
+            }
+        }
+
+        /**
+         * Build and put a string of EnabledInputMethods with removing specified Id.
+         * @return the specified id was removed or not.
+         */
+        public boolean buildAndPutEnabledInputMethodsStrRemovingIdLocked(
+                StringBuilder builder, List<Pair<String, ArrayList<String>>> imsList, String id) {
+            boolean isRemoved = false;
+            boolean needsAppendSeparator = false;
+            for (Pair<String, ArrayList<String>> ims: imsList) {
+                String curId = ims.first;
+                if (curId.equals(id)) {
+                    // We are disabling this input method, and it is
+                    // currently enabled.  Skip it to remove from the
+                    // new list.
+                    isRemoved = true;
+                } else {
+                    if (needsAppendSeparator) {
+                        builder.append(INPUT_METHOD_SEPARATER);
+                    } else {
+                        needsAppendSeparator = true;
+                    }
+                    buildEnabledInputMethodsSettingString(builder, ims);
+                }
+            }
+            if (isRemoved) {
+                // Update the setting with the new list of input methods.
+                putEnabledInputMethodsStr(builder.toString());
+            }
+            return isRemoved;
+        }
+
+        private List<InputMethodInfo> createEnabledInputMethodListLocked(
+                List<Pair<String, ArrayList<String>>> imsList) {
+            final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
+            for (Pair<String, ArrayList<String>> ims: imsList) {
+                InputMethodInfo info = mMethodMap.get(ims.first);
+                if (info != null) {
+                    res.add(info);
+                }
+            }
+            return res;
+        }
+
+        private void putEnabledInputMethodsStr(String str) {
+            Settings.Secure.putString(mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str);
+            mEnabledInputMethodsStrCache = str;
+        }
+
+        private String getEnabledInputMethodsStr() {
+            mEnabledInputMethodsStrCache = Settings.Secure.getString(
+                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS);
+            return mEnabledInputMethodsStrCache;
+        }
+    }
+
     // ----------------------------------------------------------------------
 
     @Override
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 19f56a8..540c7fe 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -881,7 +881,6 @@
                  * the already-set timer.
                  */
                 int pluggedType = intent.getIntExtra("plugged", 0);
-                Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
                 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
                         !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
                     long triggerTime = System.currentTimeMillis() + idleMillis;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 0727a79..30aed69 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -569,8 +569,10 @@
 
             DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0,
                     mDataDescription, null);
-            for (WindowState ws : mWindows) {
-                sendDragStartedLw(ws, evt);
+            final int N = mWindows.size();
+            for (int i = 0; i < N; i++) {
+                // sendDragStartedLw() clones evt for local-process dispatch
+                sendDragStartedLw(mWindows.get(i), evt);
             }
             evt.recycle();
         }
@@ -579,10 +581,17 @@
          * designated window is potentially a drop recipient.  There are race situations
          * around DRAG_ENDED broadcast, so we make sure that once we've declared that
          * the drag has ended, we never send out another DRAG_STARTED for this drag action.
+         *
+         * This method clones the 'event' parameter if it's being delivered to the same
+         * process, so it's safe for the caller to call recycle() on the event afterwards.
          */
-        private void sendDragStartedLw(WindowState newWin, final DragEvent event) {
+        private void sendDragStartedLw(WindowState newWin, DragEvent event) {
             if (!mDragEnded && newWin.isPotentialDragTarget()) {
                 try {
+                    // clone for local callees since dispatch will recycle the event
+                    if (Process.myPid() == newWin.mSession.mPid) {
+                        event = DragEvent.obtain(event);
+                    }
                     newWin.mClient.dispatchDragEvent(event);
                     // track each window that we've notified that the drag is starting
                     mNotifiedWindows.add(newWin);
@@ -608,6 +617,7 @@
             }
             DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0,
                     mDataDescription, null);
+            // sendDragStartedLw() clones 'event' if the window is process-local
             sendDragStartedLw(newWin, event);
             event.recycle();
         }
@@ -632,6 +642,14 @@
         }
 
         void notifyMoveLw(float x, float y) {
+            final int myPid = Process.myPid();
+
+            // Move the surface to the given touch
+            mSurface.openTransaction();
+            mSurface.setPosition((int)(x - mThumbOffsetX), (int)(y - mThumbOffsetY));
+            mSurface.closeTransaction();
+
+            // Tell the affected window
             WindowState touchedWin = getTouchedWinAtPointLw(x, y);
             try {
                 // have we dragged over a new window?
@@ -643,7 +661,9 @@
                     DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
                             0, 0, null, null);
                     mTargetWindow.mClient.dispatchDragEvent(evt);
-                    evt.recycle();
+                    if (myPid != mTargetWindow.mSession.mPid) {
+                        evt.recycle();
+                    }
                 }
                 if (touchedWin != null) {
                     if (DEBUG_DRAG) {
@@ -652,7 +672,9 @@
                     DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
                             x, y, null, null);
                     touchedWin.mClient.dispatchDragEvent(evt);
-                    evt.recycle();
+                    if (myPid != touchedWin.mSession.mPid) {
+                        evt.recycle();
+                    }
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "can't send drag notification to windows");
@@ -667,13 +689,16 @@
                 if (DEBUG_DRAG) {
                     Slog.d(TAG, "sending DROP to " + touchedWin);
                 }
+                final int myPid = Process.myPid();
                 DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP, x, y, null, mData);
                 try {
                     touchedWin.mClient.dispatchDragEvent(evt);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "can't send drop notification to win " + touchedWin);
                 }
-                evt.recycle();
+                if (myPid != touchedWin.mSession.mPid) {
+                    evt.recycle();
+                }
             }
         }
 
@@ -749,13 +774,7 @@
 
                     case MotionEvent.ACTION_MOVE: {
                         synchronized (mWindowMap) {
-                            // move the surface to the latest touch point
-                            mDragState.mSurface.openTransaction();
-                            mDragState.mSurface.setPosition((int)(newX - mDragState.mThumbOffsetX),
-                                    (int)(newY - mDragState.mThumbOffsetY));
-                            mDragState.mSurface.closeTransaction();
-
-                            // tell the involved window(s) where we are
+                            // move the surface and tell the involved window(s) where we are
                             mDragState.notifyMoveLw(newX, newY);
                         }
                     } break;
@@ -3368,11 +3387,8 @@
             }
             // If this application has requested an explicit orientation,
             // then use it.
-            if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_USER) {
+            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
                 return or;
             }
             findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
@@ -5403,7 +5419,6 @@
                         mDragState.reset();
                         mDragState = null;
                     }
-                    
                 }
             }
         } finally {
@@ -5535,7 +5550,7 @@
             inputWindow.frameTop = 0;
             inputWindow.frameRight = mDisplay.getWidth();
             inputWindow.frameBottom = mDisplay.getHeight();
-            
+
             inputWindow.visibleFrameLeft = inputWindow.frameLeft;
             inputWindow.visibleFrameTop = inputWindow.frameTop;
             inputWindow.visibleFrameRight = inputWindow.frameRight;
@@ -6195,9 +6210,8 @@
 
                 mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder());
 
-                // !!! TODO: call into the input monitor to sever the current touch event flow
-                // and redirect to the drag "window"; also extract the current touch (x, y)
-                // in screen coordinates
+                // !!! TODO: extract the current touch (x, y) in screen coordinates.  That
+                // will let us eliminate the (touchX,touchY) parameters from the API.
 
                 mDragState.register();
                 mInputMonitor.updateInputWindowsLw();
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 2d7ee13..e30cf4a 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -727,7 +727,7 @@
             }
         },
 
-        new Test("Persistent with numbers 222") {
+        new Test("Persistent with numbers 22") {
             public void run() {
                 mNM.notify(1, notificationWithNumbers(22));
             }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 90a6256..1d6b18d 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -782,7 +782,6 @@
     const String16 translatable16("translatable");
     const String16 formatted16("formatted");
     const String16 false16("false");
-    const String16 product16("product");
 
     const String16 myPackage(assets->getPackage());
 
@@ -830,7 +829,6 @@
             bool curIsStyled = false;
             bool curIsPseudolocalizable = false;
             bool curIsFormatted = fileIsTranslatable;
-            String16 curProduct;
             bool localHasErrors = false;
 
             if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
@@ -1228,8 +1226,6 @@
                         translatable.setTo(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, formatted16.string()) == 0) {
                         formatted.setTo(block.getAttributeStringValue(i, &length));
-                    } else if (strcmp16(attr, product16.string()) == 0) {
-                        curProduct.setTo(block.getAttributeStringValue(i, &length));
                     }
                 }
                 
@@ -1356,6 +1352,12 @@
                 hasErrors = localHasErrors = true;
             }
 
+            String16 product;
+            identIdx = block.indexOfAttribute(NULL, "product");
+            if (identIdx >= 0) {
+                product = String16(block.getAttributeStringValue(identIdx, &len));
+            }
+
             String16 comment(block.getComment(&len) ? block.getComment(&len) : nulStr);
             
             if (curIsBag) {
@@ -1447,7 +1449,7 @@
 
                         err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
                                 ident, parentIdent, itemIdent, curFormat, curIsFormatted,
-                                curProduct, false, overwrite, outTable);
+                                product, false, overwrite, outTable);
                         if (err == NO_ERROR) {
                             if (curIsPseudolocalizable && localeIsDefined(curParams)
                                     && bundle->getPseudolocalize()) {
@@ -1456,7 +1458,7 @@
                                 block.setPosition(parserPosition);
                                 err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
                                         curType, ident, parentIdent, itemIdent, curFormat,
-                                        curIsFormatted, curProduct, true, overwrite, outTable);
+                                        curIsFormatted, product, true, overwrite, outTable);
 #endif
                             }
                         } 
@@ -1480,7 +1482,7 @@
 
                 err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
                         *curTag, curIsStyled, curFormat, curIsFormatted,
-                        curProduct, false, overwrite, outTable);
+                        product, false, overwrite, outTable);
 
                 if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
                     hasErrors = localHasErrors = true;
@@ -1492,7 +1494,7 @@
                         block.setPosition(parserPosition);
                         err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
                                 ident, *curTag, curIsStyled, curFormat,
-                                curIsFormatted, curProduct,
+                                curIsFormatted, product,
                                 true, overwrite, outTable);
                         if (err != NO_ERROR) {
                             hasErrors = localHasErrors = true;