Merge change 8878

* changes:
  Support for selection of silent ringtone from the ringtone picker. This doesn't actually enable that, but adds the necessary code to make it work when enabled, and cleans up some ringtone related code.
diff --git a/api/current.xml b/api/current.xml
index 187f586..4dabd6f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1024,17 +1024,6 @@
  visibility="public"
 >
 </field>
-<field name="SHUTDOWN"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.SHUTDOWN&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="SIGNAL_PERSISTENT_PROCESSES"
  type="java.lang.String"
  transient="false"
@@ -1057,17 +1046,6 @@
  visibility="public"
 >
 </field>
-<field name="STOP_APP_SWITCHES"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.STOP_APP_SWITCHES&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="SUBSCRIBED_FEEDS_READ"
  type="java.lang.String"
  transient="false"
@@ -31763,17 +31741,6 @@
  visibility="public"
 >
 </field>
-<field name="BACKUP_SERVICE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;backup&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="BIND_AUTO_CREATE"
  type="int"
  transient="false"
@@ -32619,19 +32586,6 @@
 <parameter name="mode" type="int">
 </parameter>
 </method>
-<method name="getSharedPrefsFile"
- return="java.io.File"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
 <method name="getSystemService"
  return="java.lang.Object"
  abstract="false"
@@ -33426,70 +33380,6 @@
 </exception>
 </method>
 </interface>
-<interface name="IIntentReceiver"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="performReceive"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="resultCode" type="int">
-</parameter>
-<parameter name="data" type="java.lang.String">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-<parameter name="ordered" type="boolean">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
-<interface name="IIntentSender"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="send"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="code" type="int">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="resolvedType" type="java.lang.String">
-</parameter>
-<parameter name="finishedReceiver" type="android.content.IIntentReceiver">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
 <class name="Intent"
  extends="java.lang.Object"
  abstract="false"
@@ -37683,26 +37573,6 @@
 >
 <implements name="android.os.Parcelable">
 </implements>
-<constructor name="IntentSender"
- type="android.content.IntentSender"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="target" type="android.content.IIntentSender">
-</parameter>
-</constructor>
-<constructor name="IntentSender"
- type="android.content.IntentSender"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="protected"
->
-<parameter name="target" type="android.os.IBinder">
-</parameter>
-</constructor>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -51230,17 +51100,6 @@
 <parameter name="entryName" type="java.lang.String">
 </parameter>
 </method>
-<method name="getLearner"
- return="android.gesture.Learner"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getOrientationStyle"
  return="int"
  abstract="false"
@@ -52509,15 +52368,6 @@
 >
 </field>
 </class>
-<class name="Learner"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility=""
->
-</class>
 <class name="OrientedBoundingBox"
  extends="java.lang.Object"
  abstract="false"
@@ -123165,19 +123015,6 @@
 <parameter name="mode" type="int">
 </parameter>
 </method>
-<method name="getSharedPrefsFile"
- return="java.io.File"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
 <method name="getSystemService"
  return="java.lang.Object"
  abstract="false"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e2d01de..f101007 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -202,7 +202,6 @@
     // draw and update only what we need
     mFlingerSurface->setSwapRectangle(updateRect);
 
-    glEnable(GL_SCISSOR_TEST);
     glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
             updateRect.height());
 
@@ -218,6 +217,10 @@
         GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
         GLint x = xc - offset;
 
+        glDisable(GL_SCISSOR_TEST);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        glEnable(GL_SCISSOR_TEST);
         glDisable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
         glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 346f156..3c82fe5 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -16,9 +16,12 @@
 
 #define LOG_TAG "BootAnimation"
 
+#include <cutils/properties.h>
+
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+
 #include <utils/Log.h>
 #include <utils/threads.h>
 
@@ -41,12 +44,20 @@
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
 #endif
 
-    sp<ProcessState> proc(ProcessState::self());
-    ProcessState::self()->startThreadPool();
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.nobootanimation", value, "0");
+    int noBootAnimation = atoi(value);
+    LOGI_IF(noBootAnimation,  "boot animation disabled");
+    if (!noBootAnimation) {
 
-    // create the boot animation object
-    sp<BootAnimation> boot = new BootAnimation();
+        sp<ProcessState> proc(ProcessState::self());
+        ProcessState::self()->startThreadPool();
 
-    IPCThreadState::self()->joinThreadPool();
+        // create the boot animation object
+        sp<BootAnimation> boot = new BootAnimation();
+
+        IPCThreadState::self()->joinThreadPool();
+
+    }
     return 0;
 }
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 12bdead..d8db8b3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -119,7 +119,8 @@
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
-    OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);
+    OMXDecoder *encoder =
+        OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
 
     encoder->setSource(decoder);
     // encoder->setSource(meta, new DummySource(width, height));
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 961942a..7e23574 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -102,6 +102,7 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
+    bool audioOnly = false;
     if (argc > 1 && !strcmp(argv[1], "--list")) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -121,6 +122,10 @@
         }
 
         return 0;
+    } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+        audioOnly = true;
+        ++argv;
+        --argc;
     }
 
 #if 0
@@ -149,7 +154,11 @@
         const char *mime;
         meta->findCString(kKeyMIMEType, &mime);
 
-        if (!strncasecmp(mime, "video/", 6)) {
+        if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+            break;
+        }
+
+        if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
             break;
         }
     }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index a3456c7..79bd6e7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -163,6 +163,10 @@
         }
     }
 
+    /**
+     * Implement to return the implementation of the internal accessibility
+     * service interface.  Subclasses should not override.
+     */
     @Override
     public final IBinder onBind(Intent intent) {
         return new IEventListenerWrapper(this);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ba6cc32..3aeac53 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1085,6 +1085,14 @@
             reply.writeInt(result);
             return true;
         }
+        case KILL_APPLICATION_WITH_UID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String pkg = data.readString();
+            int uid = data.readInt();
+            killApplicationWithUid(pkg, uid);
+            reply.writeNoException();
+            return true;
+        }
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2368,6 +2376,17 @@
         data.recycle();
         return result;
     }
+    public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(pkg);
+        data.writeInt(uid);
+        mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
         
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 95b376c..b1b5282 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -266,6 +266,8 @@
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded)
             throws RemoteException;
+
+    public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
         
     /*
      * Private non-Binder interfaces
@@ -421,4 +423,5 @@
     int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
     int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
     int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
+    int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
 }
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f9c38f9..f7479bc 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -273,11 +273,6 @@
         return null;
     }
 
-    private class IntentSenderWrapper extends IntentSender {
-        protected IntentSenderWrapper(IIntentSender target) {
-            super(target);
-        }
-    }
     /**
      * Retrieve a IntentSender object that wraps the existing sender of the PendingIntent
      *
@@ -285,7 +280,7 @@
      *
      */
     public IntentSender getIntentSender() {
-        return new IntentSenderWrapper(mTarget);
+        return new IntentSender(mTarget);
     }
 
     /**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 34429fa..e991bc6 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -51,6 +51,7 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.Menu;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -667,7 +668,40 @@
         }
         mVoiceButton.setVisibility(visibility);
     }
-    
+
+    /*
+     * Menu.
+     */
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Show search settings menu item if anyone handles the intent for it
+        Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
+        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        PackageManager pm = getContext().getPackageManager();
+        ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0);
+        if (activityInfo != null) {
+            settingsIntent.setClassName(activityInfo.applicationInfo.packageName,
+                    activityInfo.name);
+            CharSequence label = activityInfo.loadLabel(getContext().getPackageManager());
+            menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label)
+                    .setIcon(android.R.drawable.ic_menu_preferences)
+                    .setAlphabeticShortcut('P')
+                    .setIntent(settingsIntent);
+            return true;
+        }
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        // The menu shows up above the IME, regardless of whether it is in front
+        // of the drop-down or not. This looks weird when there is no IME, so
+        // we make sure it is visible.
+        mSearchAutoComplete.ensureImeVisible();
+        return super.onMenuOpened(featureId, menu);
+    }
+
     /**
      * Listeners of various types
      */
@@ -1709,6 +1743,12 @@
                 if (mSearchDialog.backToPreviousComponent()) {
                     return true;
                 }
+                // If the drop-down obscures the keyboard, the user wouldn't see anything
+                // happening when pressing back, so we dismiss the entire dialog instead.
+                if (isInputMethodNotNeeded()) {
+                    mSearchDialog.cancel();
+                    return true;
+                }
                 return false; // will dismiss soft keyboard if necessary
             }
             return false;
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index d6044145..5782644 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -16,8 +16,6 @@
 
 package android.bluetooth;
 
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -75,11 +73,11 @@
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
-    /** No headset currently connected */
+    /** No Pce currently connected */
     public static final int STATE_DISCONNECTED = 0;
     /** Connection attempt in progress */
     public static final int STATE_CONNECTING   = 1;
-    /** A headset is currently connected */
+    /** A Pce is currently connected */
     public static final int STATE_CONNECTED    = 2;
 
     public static final int RESULT_FAILURE = 0;
@@ -87,11 +85,9 @@
     /** Connection canceled before completion. */
     public static final int RESULT_CANCELED = 2;
 
-    public static final int PRIORITY_AUTO = 100;
-    public static final int PRIORITY_OFF = 0;
     /**
      * An interface for notifying Bluetooth PCE IPC clients when they have
-     * been connected to the BluetoothHeadset service.
+     * been connected to the BluetoothPbap service.
      */
     public interface ServiceListener {
         /**
@@ -113,7 +109,7 @@
     }
 
     /**
-     * Create a BluetoothHeadset proxy object.
+     * Create a BluetoothPbap proxy object.
      */
     public BluetoothPbap(Context context, ServiceListener l) {
         mContext = context;
@@ -133,7 +129,7 @@
 
     /**
      * Close the connection to the backing service.
-     * Other public functions of BluetoothHeadset will return default error
+     * Other public functions of BluetoothPbap will return default error
      * results once close() has been called. Multiple invocations of close()
      * are ok.
      */
@@ -145,9 +141,9 @@
     }
 
     /**
-     * Get the current state of the Bluetooth Headset service.
+     * Get the current state of the BluetoothPbap service.
      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
-     *         object is currently not connected to the Headset service.
+     *         object is currently not connected to the Pbap service.
      */
     public int getState() {
         if (DBG) log("getState()");
@@ -159,13 +155,13 @@
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
         }
-        return BluetoothHeadset.STATE_ERROR;
+        return BluetoothPbap.STATE_ERROR;
     }
 
     /**
-     * Get the Bluetooth address of the current headset.
+     * Get the Bluetooth address of the current Pce.
      * @return The Bluetooth address, or null if not in connected or connecting
-     *         state, or if this proxy object is not connected to the Headset
+     *         state, or if this proxy object is not connected to the Pbap
      *         service.
      */
     public String getPceAddress() {
@@ -182,9 +178,9 @@
     }
 
     /**
-     * Returns true if the specified headset is connected (does not include
+     * Returns true if the specified Pcs is connected (does not include
      * connecting). Returns false if not connected, or if this proxy object
-     * if not currently connected to the headset service.
+     * if not currently connected to the Pbap service.
      */
     public boolean isConnected(String address) {
         if (DBG) log("isConnected(" + address + ")");
@@ -200,9 +196,9 @@
     }
 
     /**
-     * Disconnects the current headset. Currently this call blocks, it may soon
+     * Disconnects the current Pce. Currently this call blocks, it may soon
      * be made asynchornous. Returns false if this proxy object is
-     * not currently connected to the Headset service.
+     * not currently connected to the Pbap service.
      */
     public boolean disconnectPce() {
         if (DBG) log("disconnectPce()");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c6c9835..84449ef 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1293,7 +1293,8 @@
      * Use with {@link #getSystemService} to retrieve an
      * {@blink android.backup.IBackupManager IBackupManager} for communicating
      * with the backup mechanism.
-     *
+     * @hide
+     * 
      * @see #getSystemService
      */
     public static final String BACKUP_SERVICE = "backup";
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 45a082a..15612ce 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -135,6 +135,7 @@
         return mBase.getPackageCodePath();
     }
 
+    /** @hide */
     @Override
     public File getSharedPrefsFile(String name) {
         return mBase.getSharedPrefsFile(name);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 66b507d..64ee60e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2412,7 +2412,7 @@
     /**
      * Create an intent from a URI.  This URI may encode the action,
      * category, and other intent fields, if it was returned by
-     * {@link #toUri}..  If the Intent was not generate by toUri(), its data
+     * {@link #toUri}.  If the Intent was not generate by toUri(), its data
      * will be the entire URI and its action will be ACTION_VIEW.
      *
      * <p>The URI given here must not be relative -- that is, it must include
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 4da49d9..0e4d984 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -52,6 +52,9 @@
  * categories, and components, and same flags), it will receive a IntentSender
  * representing the same token if that is still valid.
  *
+ * <p>Instances of this class can not be made directly, but rather must be
+ * created from an existing {@link android.app.PendingIntent} with
+ * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}.
  */
 public class IntentSender implements Parcelable {
     private final IIntentSender mTarget;
@@ -245,11 +248,13 @@
         return b != null ? new IntentSender(b) : null;
     }
 
-    protected IntentSender(IIntentSender target) {
+    /** @hide */
+    public IntentSender(IIntentSender target) {
         mTarget = target;
     }
 
-    protected IntentSender(IBinder target) {
+    /** @hide */
+    public IntentSender(IBinder target) {
         mTarget = IIntentSender.Stub.asInterface(target);
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9ca11cd..0a42a6f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -131,8 +131,9 @@
     public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
     
     /**
-     * Value for {@link #flags}: this is set of the application has set
-     * its android:targetSdkVersion to something >= the current SDK version.
+     * Value for {@link #flags}: this is set of the application has specified
+     * {@link android.R.styleable#AndroidManifestApplication_testOnly
+     * android:testOnly} to be true.
      */
     public static final int FLAG_TEST_ONLY = 1<<8;
 
diff --git a/core/java/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java
index a29c2c8..ec2e78c 100644
--- a/core/java/android/gesture/GestureLibrary.java
+++ b/core/java/android/gesture/GestureLibrary.java
@@ -35,6 +35,7 @@
         return false;
     }
 
+    /** @hide */
     public Learner getLearner() {
         return mStore.getLearner();
     }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 5486920..188e7ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@
     void userActivity(long when, boolean noChangeLights);
     void userActivityWithForce(long when, boolean noChangeLights, boolean force);
     void setPokeLock(int pokey, IBinder lock, String tag);
+    int getSupportedWakeLockFlags();
     void setStayOnSetting(int val);
     long getScreenOnTime();
     void preventScreenOn(boolean prevent);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index bfcf2fc..d5934102 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -114,12 +114,14 @@
     private static final int WAKE_BIT_SCREEN_DIM = 4;
     private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
     private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+    private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
     
     private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
                                         | WAKE_BIT_CPU_WEAK
                                         | WAKE_BIT_SCREEN_DIM
                                         | WAKE_BIT_SCREEN_BRIGHT
-                                        | WAKE_BIT_KEYBOARD_BRIGHT;
+                                        | WAKE_BIT_KEYBOARD_BRIGHT
+                                        | WAKE_BIT_PROXIMITY_SCREEN_OFF;
 
     /**
      * Wake lock that ensures that the CPU is running.  The screen might
@@ -147,6 +149,16 @@
     public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
 
     /**
+     * Wake lock that turns the screen off when the proximity sensor activates.
+     * Since not all devices have proximity sensors, use
+     * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
+     * this wake lock mode is supported.
+     *
+     * {@hide}
+     */
+    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
+
+    /**
      * Normally wake locks don't actually wake the device, they just cause
      * it to remain on once it's already on.  Think of the video player
      * app as the normal behavior.  Notifications that pop up and want
@@ -196,6 +208,7 @@
             case SCREEN_DIM_WAKE_LOCK:
             case SCREEN_BRIGHT_WAKE_LOCK:
             case FULL_WAKE_LOCK:
+            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException();
@@ -365,7 +378,33 @@
         } catch (RemoteException e) {
         }
     }
-    
+
+   /**
+     * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
+     * that are supported on the device.
+     * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
+     * is supported:
+     *
+     * {@samplecode
+     * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+     * int supportedFlags = pm.getSupportedWakeLockFlags();
+     *  boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+     *                                  == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
+     * }
+     *
+     * @return the set of supported WakeLock flags.
+     *
+     * {@hide}
+     */
+    public int getSupportedWakeLockFlags()
+    {
+        try {
+            return mService.getSupportedWakeLockFlags();
+        } catch (RemoteException e) {
+            return 0;
+        }
+    }
+
     private PowerManager()
     {
     }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 19df87f..358fc9e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -351,6 +351,9 @@
     VelocityTracker mVelocityTracker;
     private int mMaximumFling;
 
+    // use this flag to control whether enabling the new double tap zoom
+    static final boolean ENABLE_DOUBLETAP_ZOOM = true;
+
     /**
      * Touch mode
      */
@@ -370,6 +373,7 @@
     private static final int SCROLL_ZOOM_OUT = 11;
     private static final int LAST_SCROLL_ZOOM = 11;
     // end of touch mode values specific to scale+scroll
+    private static final int TOUCH_DOUBLE_TAP_MODE = 12;
 
     // Whether to forward the touch events to WebCore
     private boolean mForwardTouchEvents = false;
@@ -394,6 +398,8 @@
      */
     // pre-computed square of ViewConfiguration.getScaledTouchSlop()
     private int mTouchSlopSquare;
+    // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
+    private int mDoubleTapSlopSquare;
     // pre-computed density adjusted navigation slop
     private int mNavSlop;
     // This should be ViewConfiguration.getTapTimeout()
@@ -450,6 +456,7 @@
     private static final int NEVER_REMEMBER_PASSWORD    = 2;
     private static final int SWITCH_TO_SHORTPRESS       = 3;
     private static final int SWITCH_TO_LONGPRESS        = 4;
+    private static final int RELEASE_SINGLE_TAP         = 5;
     private static final int REQUEST_FORM_DATA          = 6;
     private static final int SWITCH_TO_CLICK            = 7;
     private static final int RESUME_WEBCORE_UPDATE      = 8;
@@ -482,7 +489,7 @@
         "NEVER_REMEMBER_PASSWORD", //        = 2;
         "SWITCH_TO_SHORTPRESS", //           = 3;
         "SWITCH_TO_LONGPRESS", //            = 4;
-        "5",
+        "RELEASE_SINGLE_TAP", //             = 5;
         "REQUEST_FORM_DATA", //              = 6;
         "SWITCH_TO_CLICK", //                = 7;
         "RESUME_WEBCORE_UPDATE", //          = 8;
@@ -521,6 +528,16 @@
     // initial scale in percent. 0 means using default.
     private int mInitialScale = 0;
 
+    // while in the zoom overview mode, the page's width is fully fit to the
+    // current window. The page is alive, in another words, you can click to
+    // follow the links. Double tap will toggle between zoom overview mode and
+    // the last zoom scale.
+    boolean mInZoomOverview = false;
+    // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+    // engadget always have wider mContentWidth no matter what viewport size is.
+    int mZoomOverviewWidth = 0;
+    float mLastScale;
+
     // default scale. Depending on the display density.
     static int DEFAULT_SCALE_PERCENT;
     private float mDefaultScale;
@@ -762,9 +779,11 @@
         setLongClickable(true);
 
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
-        final int slop = configuration.getScaledTouchSlop();
+        int slop = configuration.getScaledTouchSlop();
         mTouchSlopSquare = slop * slop;
         mMinLockSnapReverseDistance = slop;
+        slop = configuration.getScaledDoubleTapSlop();
+        mDoubleTapSlopSquare = slop * slop;
         final float density = getContext().getResources().getDisplayMetrics().density;
         // use one line height, 16 based on our current default font, for how
         // far we allow a touch be away from the edge of a link
@@ -1124,6 +1143,9 @@
             b.putInt("scrollX", mScrollX);
             b.putInt("scrollY", mScrollY);
             b.putFloat("scale", mActualScale);
+            if (mInZoomOverview) {
+                b.putFloat("lastScale", mLastScale);
+            }
             return true;
         }
         return false;
@@ -1168,6 +1190,13 @@
                 // onSizeChanged() is called, the rest will be set
                 // correctly
                 mActualScale = scale;
+                float lastScale = b.getFloat("lastScale", -1.0f);
+                if (lastScale > 0) {
+                    mInZoomOverview = true;
+                    mLastScale = lastScale;
+                } else {
+                    mInZoomOverview = false;
+                }
                 invalidate();
                 return true;
             }
@@ -3060,6 +3089,11 @@
                 float y = mLastTouchY + (float) (mScrollY - lp.y);
                 mWebTextView.fakeTouchEvent(x, y);
             }
+            if (mInZoomOverview) {
+                // if in zoom overview mode, call doDoubleTap() to bring it back
+                // to normal mode so that user can enter text.
+                doDoubleTap();
+            }
         }
         else { // used by plugins
             imm.showSoftInput(this, 0);
@@ -3634,7 +3668,9 @@
         // update mMinZoomScale if the minimum zoom scale is not fixed
         if (!mMinZoomScaleFixed) {
             mMinZoomScale = (float) getViewWidth()
-                    / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+                    / Math.max(ZOOM_OUT_WIDTH, mDrawHistory ? mHistoryPicture
+                            .getWidth() : (mZoomOverviewWidth > 0 ?
+                                    mZoomOverviewWidth : mContentWidth));
         }
 
         // we always force, in case our height changed, in which case we still
@@ -3755,6 +3791,15 @@
                     nativeMoveSelection(viewToContent(mSelectX)
                             , viewToContent(mSelectY), false);
                     mTouchSelection = mExtendSelection = true;
+                } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
+                    mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+                    if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
+                        mTouchMode = TOUCH_DOUBLE_TAP_MODE;
+                    } else {
+                        // commit the short press action for the previous tap
+                        doShortPress();
+                        // continue, mTouchMode should be still TOUCH_INIT_MODE
+                    }
                 } else {
                     mTouchMode = TOUCH_INIT_MODE;
                     mPreventDrag = mForwardTouchEvents;
@@ -3764,7 +3809,8 @@
                     }
                 }
                 // Trigger the link
-                if (mTouchMode == TOUCH_INIT_MODE) {
+                if (mTouchMode == TOUCH_INIT_MODE
+                        || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                     mPrivateHandler.sendMessageDelayed(mPrivateHandler
                             .obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
                 }
@@ -3810,7 +3856,8 @@
                     if (mTouchMode == TOUCH_SHORTPRESS_MODE
                             || mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
                         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-                    } else if (mTouchMode == TOUCH_INIT_MODE) {
+                    } else if (mTouchMode == TOUCH_INIT_MODE
+                            || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                     }
 
@@ -3836,7 +3883,7 @@
                                 .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
                     }
                     WebSettings settings = getSettings();
-                    if (settings.supportZoom()
+                    if (settings.supportZoom() && !mInZoomOverview
                             && settings.getBuiltInZoomControls()
                             && !mZoomButtonsController.isVisible()
                             && (canZoomScrollOut() ||
@@ -3905,7 +3952,7 @@
                     mUserScroll = true;
                 }
 
-                if (!getSettings().getBuiltInZoomControls()) {
+                if (!getSettings().getBuiltInZoomControls() && !mInZoomOverview) {
                     boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
                     boolean showMagnify = canZoomScrollOut();
                     if (mZoomControls != null && (showPlusMinus || showMagnify)) {
@@ -3929,7 +3976,22 @@
             case MotionEvent.ACTION_UP: {
                 mLastTouchUpTime = eventTime;
                 switch (mTouchMode) {
+                    case TOUCH_DOUBLE_TAP_MODE: // double tap
+                        mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+                        doDoubleTap();
+                        break;
                     case TOUCH_INIT_MODE: // tap
+                        if (ENABLE_DOUBLETAP_ZOOM) {
+                            mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+                            if (!mPreventDrag) {
+                                mPrivateHandler.sendMessageDelayed(
+                                        mPrivateHandler.obtainMessage(
+                                        RELEASE_SINGLE_TAP),
+                                        ViewConfiguration.getDoubleTapTimeout());
+                            }
+                            break;
+                        }
+                        // fall through
                     case TOUCH_SHORTPRESS_START_MODE:
                     case TOUCH_SHORTPRESS_MODE:
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -4365,6 +4427,9 @@
             mInvInitialZoomScale = 1.0f / oldScale;
             mInvFinalZoomScale = 1.0f / mActualScale;
             mZoomScale = mActualScale;
+            if (!mInZoomOverview) {
+                mLastScale = scale;
+            }
             invalidate();
             return true;
         } else {
@@ -4470,6 +4535,9 @@
     public boolean zoomIn() {
         // TODO: alternatively we can disallow this during draw history mode
         switchOutDrawHistory();
+        // Center zooming to the center of the screen.
+        mZoomCenterX = getViewWidth() * .5f;
+        mZoomCenterY = getViewHeight() * .5f;
         return zoomWithPreview(mActualScale * 1.25f);
     }
 
@@ -4480,6 +4548,9 @@
     public boolean zoomOut() {
         // TODO: alternatively we can disallow this during draw history mode
         switchOutDrawHistory();
+        // Center zooming to the center of the screen.
+        mZoomCenterX = getViewWidth() * .5f;
+        mZoomCenterY = getViewHeight() * .5f;
         return zoomWithPreview(mActualScale * 0.8f);
     }
 
@@ -4571,6 +4642,50 @@
         }
     }
 
+    private void doDoubleTap() {
+        if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
+            return;
+        }
+        mZoomCenterX = mLastTouchX;
+        mZoomCenterY = mLastTouchY;
+        mInZoomOverview = !mInZoomOverview;
+        if (mInZoomOverview) {
+            float newScale = (float) getViewWidth()
+                    / (mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+                            : mContentWidth);
+            if (Math.abs(newScale - mActualScale) < 0.01) {
+                mInZoomOverview = !mInZoomOverview;
+                // as it is already full screen, do nothing.
+                return;
+            }
+            if (getSettings().getBuiltInZoomControls()) {
+                if (mZoomButtonsController.isVisible()) {
+                    mZoomButtonsController.setVisible(false);
+                }
+            } else {
+                if (mZoomControlRunnable != null) {
+                    mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+                }
+                if (mZoomControls != null) {
+                    mZoomControls.hide();
+                }
+            }
+            zoomWithPreview(newScale);
+        } else {
+            // mLastTouchX and mLastTouchY are the point in the current viewport
+            int contentX = viewToContent((int) mLastTouchX + mScrollX);
+            int contentY = viewToContent((int) mLastTouchY + mScrollY);
+            int left = nativeGetBlockLeftEdge(contentX, contentY);
+            if (left != NO_LEFTEDGE) {
+                // add a 5pt padding to the left edge. Re-calculate the zoom
+                // center so that the new scroll x will be on the left edge.
+                mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale
+                        * mActualScale / (mLastScale - mActualScale);
+            }
+            zoomWithPreview(mLastScale);
+        }
+    }
+
     // Called by JNI to handle a touch on a node representing an email address,
     // address, or phone number
     private void overrideLoading(String url) {
@@ -4791,6 +4906,8 @@
                     if (mTouchMode == TOUCH_INIT_MODE) {
                         mTouchMode = TOUCH_SHORTPRESS_START_MODE;
                         updateSelection();
+                    } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
+                        mTouchMode = TOUCH_DONE_MODE;
                     }
                     break;
                 }
@@ -4802,6 +4919,13 @@
                     }
                     break;
                 }
+                case RELEASE_SINGLE_TAP: {
+                    if (!mPreventDrag) {
+                        mTouchMode = TOUCH_DONE_MODE;
+                        doShortPress();
+                    }
+                    break;
+                }
                 case SWITCH_TO_CLICK:
                     // The user clicked with the trackball, and did not click a
                     // second time, so perform the action of a trackball single
@@ -4854,6 +4978,7 @@
                     break;
                 case NEW_PICTURE_MSG_ID:
                     // called for new content
+                    final int viewWidth = getViewWidth();
                     final WebViewCore.DrawData draw =
                             (WebViewCore.DrawData) msg.obj;
                     final Point viewSize = draw.mViewPoint;
@@ -4861,16 +4986,12 @@
                         // use the same logic in sendViewSizeZoom() to make sure
                         // the mZoomScale has matched the viewSize so that we
                         // can clear mZoomScale
-                        if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
+                        if (Math.round(viewWidth / mZoomScale) == viewSize.x) {
                             mZoomScale = 0;
                             mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
                                     0, 0);
                         }
                     }
-                    if (!mMinZoomScaleFixed) {
-                        mMinZoomScale = (float) getViewWidth()
-                                / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
-                    }
                     // We update the layout (i.e. request a layout from the
                     // view system) if the last view size that we sent to
                     // WebCore matches the view size of the picture we just
@@ -4888,6 +5009,25 @@
                     if (mPictureListener != null) {
                         mPictureListener.onNewPicture(WebView.this, capturePicture());
                     }
+                    if (mWebViewCore.getSettings().getUseWideViewPort()) {
+                        mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
+                                draw.mViewPoint.x);
+                    }
+                    if (!mMinZoomScaleFixed) {
+                        mMinZoomScale = (float) viewWidth
+                                / Math.max(ZOOM_OUT_WIDTH,
+                                mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+                                        : mContentWidth);
+                    }
+                    if (!mDrawHistory && mInZoomOverview) {
+                        // fit the content width to the current view. Ignore
+                        // the rounding error case.
+                        if (Math.abs((viewWidth * mInvActualScale)
+                                - mZoomOverviewWidth) > 1) {
+                            zoomWithPreview((float) viewWidth
+                                    / mZoomOverviewWidth);
+                        }
+                    }
                     break;
                 case WEBCORE_INITIALIZED_MSG_ID:
                     // nativeCreate sets mNativeClass to a non-zero value
@@ -4916,7 +5056,7 @@
                         }
                     }
                     break;
-                case DID_FIRST_LAYOUT_MSG_ID:
+                case DID_FIRST_LAYOUT_MSG_ID: {
                     if (mNativeClass == 0) {
                         break;
                     }
@@ -4943,15 +5083,17 @@
                     if (width == 0) {
                         break;
                     }
+                    final WebSettings settings = mWebViewCore.getSettings();
                     int initialScale = msg.arg1;
                     int viewportWidth = msg.arg2;
                     // start a new page with DEFAULT_SCALE zoom scale.
                     float scale = mDefaultScale;
+                    mInZoomOverview = false;
                     if (mInitialScale > 0) {
                         scale = mInitialScale / 100.0f;
                     } else  {
-                        if (initialScale < 0) break;
-                        if (mWebViewCore.getSettings().getUseWideViewPort()) {
+                        if (initialScale == -1) break;
+                        if (settings.getUseWideViewPort()) {
                             // force viewSizeChanged by setting mLastWidthSent
                             // to 0
                             mLastWidthSent = 0;
@@ -4961,11 +5103,21 @@
                             // than the view width, zoom in to fill the view
                             if (viewportWidth > 0 && viewportWidth < width) {
                                 scale = (float) width / viewportWidth;
+                            } else {
+                                if (settings.getUseWideViewPort()) {
+                                    mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
+                                }
                             }
+                        } else if (initialScale < 0) {
+                            // this should only happen when
+                            // ENABLE_DOUBLETAP_ZOOM is true
+                            mInZoomOverview = true;
+                            scale = -initialScale / 100.0f;
                         } else {
                             scale = initialScale / 100.0f;
                         }
                     }
+                    mLastScale = scale;
                     setNewZoomScale(scale, false);
                     // As we are on a new page, remove the WebTextView.  This
                     // is necessary for page loads driven by webkit, and in
@@ -4973,6 +5125,7 @@
                     // the WebTextView was visible.
                     clearTextEntry();
                     break;
+                }
                 case MOVE_OUT_OF_PLUGIN:
                     if (nativePluginEatsNavKey()) {
                         navHandledKey(msg.arg1, 1, false, 0, true);
@@ -5542,4 +5695,7 @@
     private native void     nativeUpdateCachedTextfield(String updatedText,
             int generation);
     private native void     nativeUpdatePluginReceivesEvents();
+    // return NO_LEFTEDGE means failure.
+    private static final int NO_LEFTEDGE = -1;
+    private native int      nativeGetBlockLeftEdge(int x, int y);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4993fcf..36c5f0c8 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -96,7 +96,8 @@
 
     private boolean mViewportUserScalable = true;
 
-    private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
+    private int mRestoredScale = 0;
+    private int mRestoredScreenWidthScale = 0;
     private int mRestoredX = 0;
     private int mRestoredY = 0;
 
@@ -1340,9 +1341,8 @@
             Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
             return;
         }
-        if (mSettings.getUseWideViewPort()
-                && (w < mViewportWidth || mViewportWidth == -1)) {
-            int width = mViewportWidth;
+        if (mSettings.getUseWideViewPort()) {
+            int width;
             if (mViewportWidth == -1) {
                 if (mSettings.getLayoutAlgorithm() ==
                         WebSettings.LayoutAlgorithm.NORMAL) {
@@ -1362,9 +1362,15 @@
                      */
                     width = Math.max(w, nativeGetContentMinPrefWidth());
                 }
+            } else {
+                width = Math.max(w, mViewportWidth);
             }
-            nativeSetSize(width, Math.round((float) width * h / w), w, scale,
-                    w, h);
+            // while in zoom overview mode, the text are wrapped to the screen
+            // width matching mWebView.mLastScale. So that we don't trigger
+            // re-flow while toggling between overview mode and normal mode.
+            nativeSetSize(width, Math.round((float) width * h / w),
+                    Math.round(mWebView.mInZoomOverview ? w * scale
+                            / mWebView.mLastScale : w), scale, w, h);
         } else {
             nativeSetSize(w, h, w, scale, w, h);
         }
@@ -1409,6 +1415,7 @@
         public Region mInvalRegion;
         public Point mViewPoint;
         public Point mWidthHeight;
+        public int mMinPrefWidth;
     }
 
     private void webkitDraw() {
@@ -1424,6 +1431,9 @@
             // Send the native view size that was used during the most recent
             // layout.
             draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
+            if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+                draw.mMinPrefWidth = nativeGetContentMinPrefWidth();
+            }
             if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
             Message.obtain(mWebView.mPrivateHandler,
                     WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
@@ -1734,9 +1744,10 @@
 
             if (mRestoredScale > 0) {
                 Message.obtain(mWebView.mPrivateHandler,
-                        WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
+                        WebView.DID_FIRST_LAYOUT_MSG_ID,
+                        mRestoredScreenWidthScale > 0 ?
+                        -mRestoredScreenWidthScale : mRestoredScale, 0,
                         scaleLimit).sendToTarget();
-                mRestoredScale = 0;
             } else {
                 // if standardLoad is true, use mViewportInitialScale, otherwise
                 // pass -1 to the WebView to indicate no change of the scale.
@@ -1764,8 +1775,8 @@
                 }
             }
 
-            // reset restored offset
-            mRestoredX = mRestoredY = 0;
+            // reset restored offset, scale
+            mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
         }
     }
 
@@ -1777,6 +1788,17 @@
     }
 
     // called by JNI
+    private void restoreScreenWidthScale(int scale) {
+        if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+            return;
+        }
+
+        if (mBrowserFrame.firstLayoutDone() == false) {
+            mRestoredScreenWidthScale = scale;
+        }
+    }
+
+    // called by JNI
     private void needTouchEvents(boolean need) {
         if (mWebView != null) {
             Message.obtain(mWebView.mPrivateHandler,
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e613ec4..ea88b5b 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -104,6 +104,7 @@
     private View mDropDownAnchorView;  // view is retrieved lazily from id once needed
     private int mDropDownWidth;
     private int mDropDownHeight;
+    private final Rect mTempRect = new Rect();
 
     private Drawable mDropDownListHighlight;
 
@@ -209,8 +210,7 @@
     private void onClickImpl() {
         // If the dropdown is showing, bring it back in front of the soft
         // keyboard when the user touches the text field.
-        if (mPopup.isShowing() &&
-                mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED) {
+        if (mPopup.isShowing() && isInputMethodNotNeeded()) {
             ensureImeVisible();
         }
     }
@@ -1089,6 +1089,13 @@
     }
 
     /**
+     * @hide internal used only here and SearchDialog
+     */
+    public boolean isInputMethodNotNeeded() {
+        return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+    }
+
+    /**
      * <p>Displays the drop down on screen.</p>
      */
     public void showDropDown() {
@@ -1097,7 +1104,7 @@
         int widthSpec = 0;
         int heightSpec = 0;
 
-        boolean noInputMethod = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+        boolean noInputMethod = isInputMethodNotNeeded();
 
         if (mPopup.isShowing()) {
             if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
@@ -1303,7 +1310,15 @@
                 getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
 
         if (mDropDownAlwaysVisible) {
-            return maxHeight;
+            // getMaxAvailableHeight() subtracts the padding, so we put it back,
+            // to get the available height for the whole window
+            int padding = 0;
+            Drawable background = mPopup.getBackground();
+            if (background != null) {
+                background.getPadding(mTempRect);
+                padding = mTempRect.top + mTempRect.bottom;
+            }
+            return maxHeight + padding;
         }
 
         return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 24c0e2a..e19a93d 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -432,7 +432,7 @@
             width = resolveSize(width, widthMeasureSpec);
 
             if (offsetHorizontalAxis) {
-                    for (int i = 0; i < count; i++) {
+                for (int i = 0; i < count; i++) {
                     View child = getChildAt(i);
                     if (child.getVisibility() != GONE) {
                         LayoutParams params = (LayoutParams) child.getLayoutParams();
@@ -486,10 +486,14 @@
                     View child = getChildAt(i);
                     if (child.getVisibility() != GONE && child != ignore) {
                         LayoutParams params = (LayoutParams) child.getLayoutParams();
-                        params.mLeft += horizontalOffset;
-                        params.mRight += horizontalOffset;
-                        params.mTop += verticalOffset;
-                        params.mBottom += verticalOffset;
+                        if (horizontalGravity) {
+                            params.mLeft += horizontalOffset;
+                            params.mRight += horizontalOffset;
+                        }
+                        if (verticalGravity) {
+                            params.mTop += verticalOffset;
+                            params.mBottom += verticalOffset;
+                        }
                     }
                 }
             }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 17704ae..6ad2441 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -863,7 +863,8 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to call the activity manager shutdown() API
-         to put the higher-level system there into a shutdown state. -->
+         to put the higher-level system there into a shutdown state.
+         @hide -->
     <permission android:name="android.permission.SHUTDOWN"
         android:label="@string/permlab_shutdown"
         android:description="@string/permdesc_shutdown"
@@ -872,7 +873,8 @@
     <!-- Allows an application to tell the activity manager to temporarily
          stop application switches, putting it into a special mode that
          prevents applications from immediately switching away from some
-         critical UI such as the home screen. -->
+         critical UI such as the home screen.
+         @hide -->
     <permission android:name="android.permission.STOP_APP_SWITCHES"
         android:label="@string/permlab_stopAppSwitches"
         android:description="@string/permdesc_stopAppSwitches"
diff --git a/core/res/res/drawable/expander_ic_maximized.9.png b/core/res/res/drawable/expander_ic_maximized.9.png
index 778255a..465cabd 100644
--- a/core/res/res/drawable/expander_ic_maximized.9.png
+++ b/core/res/res/drawable/expander_ic_maximized.9.png
Binary files differ
diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable/expander_ic_minimized.9.png
index 5235c18..9967ecb 100644
--- a/core/res/res/drawable/expander_ic_minimized.9.png
+++ b/core/res/res/drawable/expander_ic_minimized.9.png
Binary files differ
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index f829b08..2b9e448 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -96,6 +96,7 @@
     native private int  nAllocationCreatePredefSized(int predef, int count);
     native private int  nAllocationCreateSized(int elem, int count);
     native private int  nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+    native private int  nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
 
     native private void nAllocationUploadToTexture(int alloc, int baseMioLevel);
     native private void nAllocationDestroy(int alloc);
@@ -529,7 +530,12 @@
     }
 
     public Allocation allocationCreateFromBitmap(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
-        int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b); 
+        int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+        return new Allocation(id);
+    }
+
+    public Allocation allocationCreateFromBitmapBoxed(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
+        int id = nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
         return new Allocation(id);
     }
 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 573610c..6f781a0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -291,6 +291,29 @@
     return 0;
 }
 
+static int
+nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    SkBitmap const * nativeBitmap =
+            (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+    const SkBitmap& bitmap(*nativeBitmap);
+    SkBitmap::Config config = bitmap.getConfig();
+
+    RsElementPredefined e = SkBitmapToPredefined(config);
+
+    if (e != RS_ELEMENT_USER_U8) {
+        bitmap.lockPixels();
+        const int w = bitmap.width();
+        const int h = bitmap.height();
+        const void* ptr = bitmap.getPixels();
+        jint id = (jint)rsAllocationCreateFromBitmapBoxed(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+        bitmap.unlockPixels();
+        return id;
+    }
+    return 0;
+}
+
 
 static void
 nAllocationDestroy(JNIEnv *_env, jobject _this, jint a)
@@ -994,6 +1017,7 @@
 {"nAllocationCreatePredefSized",   "(II)I",                                (void*)nAllocationCreatePredefSized },
 {"nAllocationCreateSized",         "(II)I",                                (void*)nAllocationCreateSized },
 {"nAllocationCreateFromBitmap",    "(IZLandroid/graphics/Bitmap;)I",       (void*)nAllocationCreateFromBitmap },
+{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I",       (void*)nAllocationCreateFromBitmapBoxed },
 {"nAllocationUploadToTexture",     "(II)V",                                (void*)nAllocationUploadToTexture },
 {"nAllocationDestroy",             "(I)V",                                 (void*)nAllocationDestroy },
 {"nAllocationData",                "(I[I)V",                               (void*)nAllocationData_i },
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index 0859457..e76fd4c 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -26,6 +26,8 @@
 #include <utils/List.h>
 #include <utils/threads.h>
 
+#include <OMX_Video.h>
+
 namespace android {
 
 class OMXMediaBuffer;
@@ -35,10 +37,8 @@
                    public MediaBufferObserver {
 public:
     static OMXDecoder *Create(
-            OMXClient *client, const sp<MetaData> &data);
-
-    static OMXDecoder *CreateEncoder(
-            OMXClient *client, const sp<MetaData> &data);
+            OMXClient *client, const sp<MetaData> &data,
+            bool createEncoder = false);
 
     virtual ~OMXDecoder();
 
@@ -68,10 +68,23 @@
     };
 
     enum PortStatus {
-        kPortStatusActive   = 0,
-        kPortStatusDisabled = 1,
-        kPortStatusShutdown = 2,
-        kPortStatusFlushing = 3
+        kPortStatusActive             = 0,
+        kPortStatusDisabled           = 1,
+        kPortStatusShutdown           = 2,
+        kPortStatusFlushing           = 3,
+        kPortStatusFlushingToDisabled = 4,
+        kPortStatusFlushingToShutdown = 5,
+    };
+
+    enum Quirks {
+        kWantsRawNALFrames                   = 1,
+        kDoesntReturnBuffersOnDisable        = 2,
+        kDoesntFlushOnExecutingToIdle        = 4,
+        kDoesntProperlyFlushAllPortsAtOnce   = 8,
+        kRequiresAllocateBufferOnInputPorts  = 16,
+        kRequiresAllocateBufferOnOutputPorts = 32,
+        kRequiresLoadedToIdleAfterAllocation = 64,
+        kMeasuresTimeInMilliseconds          = 128,
     };
 
     OMXClient *mClient;
@@ -79,6 +92,8 @@
     IOMX::node_id mNode;
     char *mComponentName;
     bool mIsMP3;
+    bool mIsAVC;
+    uint32_t mQuirks;
 
     MediaSource *mSource;
     sp<MetaData> mOutputFormat;
@@ -116,7 +131,8 @@
     bool mReachedEndOfInput;
 
     OMXDecoder(OMXClient *client, IOMX::node_id node,
-               const char *mime, const char *codec);
+               const char *mime, const char *codec,
+               uint32_t quirks);
 
     void setPortStatus(OMX_U32 port_index, PortStatus status);
     PortStatus getPortStatus(OMX_U32 port_index) const;
@@ -125,7 +141,13 @@
 
     void setAMRFormat();
     void setAACFormat();
-    void setVideoOutputFormat(OMX_U32 width, OMX_U32 height);
+
+    status_t setVideoPortFormatType(
+            OMX_U32 portIndex,
+            OMX_VIDEO_CODINGTYPE compressionFormat,
+            OMX_COLOR_FORMATTYPE colorFormat);
+
+    void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
     void setup();
     void dumpPortDefinition(OMX_U32 port_index);
 
@@ -144,6 +166,7 @@
 
     void freeInputBuffer(IOMX::buffer_id buffer);
     void freeOutputBuffer(IOMX::buffer_id buffer);
+    void freePortBuffers(OMX_U32 port_index);
 
     void postStart();
     void postEmptyBufferDone(IOMX::buffer_id buffer);
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+    TIHardwareRenderer(
+            const sp<ISurface> &surface,
+            size_t displayWidth, size_t displayHeight,
+            size_t decodedWidth, size_t decodedHeight);
+
+    virtual ~TIHardwareRenderer();
+
+    virtual void render(
+            const void *data, size_t size, void *platformPrivate);
+
+private:
+    sp<ISurface> mISurface;
+    size_t mDisplayWidth, mDisplayHeight;
+    size_t mDecodedWidth, mDecodedHeight;
+    size_t mFrameSize;
+    sp<Overlay> mOverlay;
+    Vector<void *> mOverlayAddresses;
+    size_t mIndex;
+
+    TIHardwareRenderer(const TIHardwareRenderer &);
+    TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+}  // namespace android
+
+#endif  // TI_HARDWARE_RENDERER_H_
+
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 1336131..232ffb0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -3443,8 +3443,8 @@
             srcThread->getTracks(tracks, activeTracks, stream);
             if (tracks.size()) {
                 dstThread->putTracks(tracks, activeTracks);
-                dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
             }
+            dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
         }
     }
 
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 855ea63..1d14f70 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -146,26 +146,26 @@
 };
 
 enum RsBlendSrcFunc {
-    RS_BLEND_SRC_ZERO, 
-    RS_BLEND_SRC_ONE, 
-    RS_BLEND_SRC_DST_COLOR, 
-    RS_BLEND_SRC_ONE_MINUS_DST_COLOR, 
-    RS_BLEND_SRC_SRC_ALPHA, 
-    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, 
-    RS_BLEND_SRC_DST_ALPHA, 
-    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, 
-    RS_BLEND_SRC_SRC_ALPHA_SATURATE
+    RS_BLEND_SRC_ZERO,                  // 0
+    RS_BLEND_SRC_ONE,                   // 1
+    RS_BLEND_SRC_DST_COLOR,             // 2
+    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
+    RS_BLEND_SRC_SRC_ALPHA,             // 4
+    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_SRC_DST_ALPHA,             // 6
+    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
 };
 
 enum RsBlendDstFunc {
-    RS_BLEND_DST_ZERO, 
-    RS_BLEND_DST_ONE, 
-    RS_BLEND_DST_SRC_COLOR, 
-    RS_BLEND_DST_ONE_MINUS_SRC_COLOR, 
-    RS_BLEND_DST_SRC_ALPHA, 
-    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, 
-    RS_BLEND_DST_DST_ALPHA, 
-    RS_BLEND_DST_ONE_MINUS_DST_ALPHA
+    RS_BLEND_DST_ZERO,                  // 0
+    RS_BLEND_DST_ONE,                   // 1
+    RS_BLEND_DST_SRC_COLOR,             // 2
+    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
+    RS_BLEND_DST_SRC_ALPHA,             // 4
+    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_DST_DST_ALPHA,             // 6
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
 };
 
 enum RsTexEnvMode {
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 0789301..7a5556e 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -30,11 +30,3 @@
 #define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
 #define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
 
-//typedef int (*rsc_RunScript)(uint32_t launchIndex, const rsc_FunctionTable *);
-
-
-/* EnableCap */
-#define GL_LIGHTING                       0x0B50
-
-/* LightName */
-#define GL_LIGHT0                         0x4000
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
index 6885251..495fe55 100644
--- a/libs/rs/java/Film/res/raw/filmstrip.c
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -11,29 +11,29 @@
     int32_t triangleOffsets[64];
     float triangleOffsetsTex[64];
     int32_t triangleOffsetsCount;
-} FilmScriptUserEnv; 
-*/ 
+} FilmScriptUserEnv;
+*/
+
+#define POS_TRANSLATE 0
+#define POS_ROTATE 1
+#define POS_FOCUS 2
+
+#define STATE_TRIANGLE_OFFSET_COUNT 0
+#define STATE_LAST_FOCUS 1
+
 
 // The script enviroment has 3 env allocations.
 // bank0: (r) The enviroment structure
 // bank1: (r) The position information
 // bank2: (rw) The temporary texture state
 
-int main(int index) 
+int main(int index)
 {
     int f1,f2,f3,f4, f5,f6,f7,f8, f9,f10,f11,f12, f13,f14,f15,f16;
     int g1,g2,g3,g4, g5,g6,g7,g8, g9,g10,g11,g12, g13,g14,g15,g16;
-    float trans;
-    float rot;
-    int x;
-    float focusPos;  // float
-    int focusID;
-    int lastFocusID;
-    int imgCount;
 
-    trans = loadF(1, 0);
-    rot = loadF(1, 1);
-
+    float trans = loadF(1, POS_TRANSLATE);
+    float rot = loadF(1, POS_ROTATE);
     matrixLoadScale(&f16, 2.f, 2.f, 2.f);
     matrixTranslate(&f16, 0.f, 0.f, trans);
     matrixRotate(&f16, 90.f, 0.f, 0.f, 1.f);
@@ -46,24 +46,18 @@
     drawTriangleMesh(NAMED_mesh);
 
 
-
-    //int imgId = 0;
-
+    // Start of images.
     bindProgramFragmentStore(NAMED_PFImages);
     bindProgramFragment(NAMED_PFSImages);
     bindProgramVertex(NAMED_PVImages);
 
-    //focusPos = loadF(1, 2);
-    //focusID = 0;
-    //lastFocusID = loadI32(2, 0);
-    //imgCount = 13;
+    float focusPos = loadF(1, POS_FOCUS);
+    int focusID = 0;
+    int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
+    int imgCount = 13;
 
-    /*
-    disable(GL_LIGHTING);
-
-
-    if (trans > (-.3)) {
-        focusID = -1.0 - focusPos;
+    if (trans > (-.3f)) {
+        focusID = -1.0f - focusPos;
         if (focusID >= imgCount) {
             focusID = -1;
         }
@@ -71,6 +65,7 @@
         focusID = -1;
     }
 
+    /*
     if (focusID != lastFocusID) {
         if (lastFocusID >= 0) {
             uploadToTexture(con, env->tex[lastFocusID], 1);
@@ -79,36 +74,38 @@
             uploadToTexture(con, env->tex[focusID], 0);
         }
     }
-    storeEnvI32(con, 2, 0, focusID);
+    */
+    storeI32(2, STATE_LAST_FOCUS, focusID);
 
+    int triangleOffsetsCount = loadI32(2, STATE_TRIANGLE_OFFSET_COUNT);
 
+    int imgId = 0;
     for (imgId=1; imgId <= imgCount; imgId++) {
-        float pos = focusPos + imgId + .4f;
-        int offset = (int)floor(pos*2);
-        pos -= 0.75;
-    
-        offset += env->triangleOffsetsCount / 2;
-    
-        if ((offset < 0) || (offset >= env->triangleOffsetsCount)) {
-            continue;
+        float pos = focusPos + imgId + 0.4f;
+        int offset = (int)floorf(pos * 2.f);
+        pos = pos - 0.75f;
+
+        offset = offset + triangleOffsetsCount / 2;
+
+        if (!((offset < 0) || (offset >= triangleOffsetsCount))) {
+            int start = offset -2;
+            int end = offset + 2;
+
+            if (start < 0) {
+                start = 0;
+            }
+            if (end > triangleOffsetsCount) {
+                end = triangleOffsetsCount;
+            }
+
+            bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1));
+    /*
+            matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
+            storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
+            renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
+    */
         }
-    
-        int start = offset -2;
-        int end = offset + 2;
-    
-        if (start < 0) {
-            start = 0;
-        }
-        if (end > env->triangleOffsetsCount) {
-            end = env->triangleOffsetsCount;
-        }
-    
-        programFragmentBindTexture(con, env->fpImages, 0, env->tex[imgId - 1]);
-        matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0); 
-        storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
-        renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
-    } 
-*/
+    }
     return 0;
 }
 
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index fca0818..395bd35 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -38,6 +39,12 @@
 import android.view.MotionEvent;
 
 public class FilmRS {
+    private final int POS_TRANSLATE = 0;
+    private final int POS_ROTATE = 1;
+    private final int POS_FOCUS = 2;
+
+    private final int STATE_TRIANGLE_OFFSET_COUNT = 0;
+    private final int STATE_LAST_FOCUS = 1;
 
     public FilmRS() {
     }
@@ -56,11 +63,11 @@
         if (x > 270) {
             x = 270;
         }
-    
+
         float anim = ((float)x-50) / 270.f;
-        mBufferPos[0] = 2f * anim + 0.5f;   // translation
-        mBufferPos[1] = (anim * 40);  // rotation
-        mBufferPos[2] = ((float)y) / 16.f - 8;  // focusPos
+        mBufferPos[POS_TRANSLATE] = 2f * anim + 0.5f;   // translation
+        mBufferPos[POS_ROTATE] = (anim * 40);  // rotation
+        mBufferPos[POS_FOCUS] = ((float)y) / 16.f - 8;  // focusPos
         mAllocPos.data(mBufferPos);
     }
 
@@ -80,15 +87,19 @@
     private RenderScript.ProgramVertex mPVImages;
     private ProgramVertexAlloc mPVA;
 
-    private RenderScript.Allocation mAllocEnv;
+    private RenderScript.Allocation mImages[];
+    private RenderScript.Allocation mAllocIDs;
     private RenderScript.Allocation mAllocPos;
     private RenderScript.Allocation mAllocState;
     private RenderScript.Allocation mAllocPV;
     private RenderScript.TriangleMesh mMesh;
     private RenderScript.Light mLight;
 
-    private float[] mBufferPos;
-    private float[] mBufferPV;
+    private FilmStripMesh mFSM;
+
+    private int[] mBufferIDs;
+    private float[] mBufferPos = new float[3];
+    private int[] mBufferState;
 
     private void initSamplers() {
         mRS.samplerBegin();
@@ -112,7 +123,7 @@
         mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.EQUAL);
         mRS.programFragmentStoreDitherEnable(false);
         mRS.programFragmentStoreDepthMask(false);
-        mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE, 
+        mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
                                           RenderScript.BlendDstFunc.ONE);
         mPFSImages = mRS.programFragmentStoreCreate();
         mPFSImages.setName("PFSImages");
@@ -148,7 +159,75 @@
     }
 
 
-    int mParams[] = new int[10];
+    private void loadImages() {
+        mBufferIDs = new int[13];
+        mImages = new RenderScript.Allocation[13];
+        mAllocIDs = mRS.allocationCreatePredefSized(
+            RenderScript.ElementPredefined.USER_FLOAT,
+            mBufferIDs.length);
+
+        Bitmap b;
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inScaled = false;
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p01, opts);
+        mImages[0] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p02, opts);
+        mImages[1] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p03, opts);
+        mImages[2] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p04, opts);
+        mImages[3] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p05, opts);
+        mImages[4] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p06, opts);
+        mImages[5] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p07, opts);
+        mImages[6] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p08, opts);
+        mImages[7] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p09, opts);
+        mImages[8] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p10, opts);
+        mImages[9] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p11, opts);
+        mImages[10] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p12, opts);
+        mImages[11] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        b = BitmapFactory.decodeResource(mRes, R.drawable.p13, opts);
+        mImages[12] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+        for(int ct=0; ct < mImages.length; ct++) {
+            mImages[ct].uploadToTexture(1);
+            mBufferIDs[ct] = mImages[ct].getID();
+        }
+        mAllocIDs.data(mBufferIDs);
+    }
+
+    private void initState()
+    {
+        mBufferState = new int[10];
+        mAllocState = mRS.allocationCreatePredefSized(
+            RenderScript.ElementPredefined.USER_FLOAT,
+            mBufferState.length);
+
+        mBufferState[STATE_TRIANGLE_OFFSET_COUNT] = mFSM.mTriangleOffsetsCount;
+        mBufferState[STATE_LAST_FOCUS] = -1;
+
+        mAllocState.data(mBufferState);
+    }
 
     private void initRS() {
         mElementVertex = mRS.elementGetPredefined(
@@ -157,8 +236,8 @@
             RenderScript.ElementPredefined.INDEX_16);
 
         mRS.triangleMeshBegin(mElementVertex, mElementIndex);
-        FilmStripMesh fsm = new FilmStripMesh();
-        fsm.init(mRS);
+        mFSM = new FilmStripMesh();
+        mFSM.init(mRS);
         mMesh = mRS.triangleMeshCreate();
         mMesh.setName("mesh");
 
@@ -176,19 +255,22 @@
         mRS.scriptCSetRoot(true);
         mScriptStrip = mRS.scriptCCreate();
 
-        mBufferPos = new float[3];
         mAllocPos = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT, 
+            RenderScript.ElementPredefined.USER_FLOAT,
             mBufferPos.length);
 
+        loadImages();
+        initState();
+
         mPVA = new ProgramVertexAlloc(mRS);
         mPVBackground.bindAllocation(0, mPVA.mAlloc);
         mPVImages.bindAllocation(0, mPVA.mAlloc);
         mPVA.setupProjectionNormalized(320, 480);
 
 
+        mScriptStrip.bindAllocation(mAllocIDs, 0);
         mScriptStrip.bindAllocation(mAllocPos, 1);
-       //mScriptStrip.bindAllocation(gStateAlloc, 2);
+        mScriptStrip.bindAllocation(mAllocState, 2);
         mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
 
 
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
index d338d0d..960fdf0 100644
--- a/libs/rs/java/Rollo/res/raw/rollo.c
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -51,7 +51,7 @@
 
     float touchCut = 1.f;
     if (loadI32(0, STATE_TOUCH)) {
-        touchCut = 5.f;
+        touchCut = 4.f;
     }
 
 
@@ -60,14 +60,17 @@
     storeF(2, SCRATCH_ZOOM, zoom);
 
     float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
-    float rot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
-    storeF(2, SCRATCH_ROT, rot);
+    float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+    storeF(2, SCRATCH_ROT, drawRot);
 
-    float diam = 8.f;// + curve * 2.f;
+    float diam = 10.f;
     float scale = 1.0f / zoom;
 
-    rot = rot * scale;
-    float rotStep = 20.0f / 180.0f * 3.14f * scale;
+    // Bug makes 1.0f alpha fail.
+    color(1.0f, 1.0f, 1.0f, 0.99f);
+
+    float rot = drawRot * scale;
+    float rotStep = 16.0f / 180.0f * 3.14f * scale;
     rowCount = 4;
     int index = 0;
     int iconCount = loadI32(0, STATE_COUNT);
@@ -82,24 +85,55 @@
 
         int y;
         for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-            float ty1 = ((y * 3.0f) - 4.5f) * scale;
+            float ty1 = ((y * 3.5f) - 6.f) * scale;
             float ty2 = ty1 + scale * 2.f;
-            bindTexture(NAMED_PF, 0, loadI32(1, y));
-            color(1.0f, 1.0f, 1.0f, 1.0f);
-            if (done && (index != selectedID)) {
-                color(0.4f, 0.4f, 0.4f, 1.0f);
-            }
+            bindTexture(NAMED_PF, 0, loadI32(1, index));
+            //if (done && (index != selectedID)) {
+                //color(0.4f, 0.4f, 0.4f, 1.0f);
+            //}
             drawQuad(tx1, ty1, tz1,
                      tx2, ty1, tz2,
                      tx2, ty2, tz2,
                      tx1, ty2, tz1);
+
             iconCount--;
             index++;
         }
         rot = rot + rotStep;
     }
 
-    return 0;
+    // Draw the selected icon
+    color(1.0f, 1.0f, 1.0f, 0.9f);
+    rot = drawRot * scale;
+    index = 0;
+    iconCount = loadI32(0, STATE_COUNT);
+    while (iconCount) {
+        int y;
+        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+            if (index == selectedID) {
+
+                float tmpSin = sinf(rot) * scale;
+                float tmpCos = cosf(rot) * scale;
+                float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+                float tx2 = tx1 + (tmpCos * 4.f);
+                float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+                float tz2 = tz1 - (tmpSin * 4.f);
+
+                float ty1 = ((y * 3.5f) - 5.f) * scale;
+                float ty2 = ty1 + scale * 4.f;
+                bindTexture(NAMED_PF, 0, loadI32(1, index));
+                drawQuad(tx1, ty1, tz1,
+                         tx2, ty1, tz2,
+                         tx2, ty2, tz2,
+                         tx1, ty2, tz1);
+            }
+            iconCount--;
+            index++;
+        }
+        rot = rot + rotStep;
+    }
+
+    return 1;
 }
 
 
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
index b04ea73..256fa3c 100644
--- a/libs/rs/java/Rollo/res/raw/rollo2.c
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -3,65 +3,153 @@
 #pragma stateFragment(PF)
 #pragma stateFragmentStore(PFS)
 
-void drawLoop(int x, int y, int z, int rot)
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X             0
+#define STATE_DONE              1
+//#define STATE_PRESSURE          2
+#define STATE_ZOOM              3
+//#define STATE_WARP              4
+#define STATE_ORIENTATION       5
+#define STATE_SELECTION         6
+#define STATE_FIRST_VISIBLE     7
+#define STATE_COUNT             8
+#define STATE_TOUCH             9
+
+float filter(float val, float target, float str)
 {
-    int ct;
-    int tx;
-    int ty;
-    int tmpSin;
-    int tmpCos;
-    int sz;
-
-    for (ct = 0; ct < 10; ct ++) {
-        tmpSin = sinx((ct * 36 + rot) * 0x10000);
-        tmpCos = cosx((ct * 36 + rot) * 0x10000);
-
-        ty = y + tmpCos * 4;
-        tx = x + tmpSin * 4;
-        pfBindTexture(NAMED_PF, 0, loadI32(1, ct & 3));
-
-        sz = 0xc000;
-        drawQuad(tx - sz, ty - sz, z,
-                 tx + sz, ty - sz, z,
-                 tx + sz, ty + sz, z,
-                 tx - sz, ty + sz, z);
-    }
+    float delta = (target - val);
+    return val + delta * str;
 }
 
+
 int main(void* con, int ft, int launchID)
 {
     int rowCount;
-    int x;
-    int y;
-    int row;
-    int col;
     int imageID;
-    int tx1;
-    int ty1;
-    int tz1;
-    int tx2;
-    int ty2;
-    int tz2;
-    int tmpSin;
-    int tmpCos;
-    int iconCount;
-    int pressure;
+    int done = loadI32(0, STATE_DONE);
+    int selectedID = loadI32(0, STATE_SELECTION);
+    int iconCount = loadI32(0, STATE_COUNT);
 
-    int ringCount;
+    float f = loadF(2, 0);
 
+    float iconSize = 1.f;
+    float iconSpacing = 0.2f;
+    float z = 4.f;
 
-
-    rotStep = 16 * 0x10000;
-    pressure = loadI32(0, 2);
-    rowCount = 4;
-
-    iconCount = loadI32(0, 1);
-    rot = (-20 + loadI32(0, 0)) * 0x10000;
-
-    for (ringCount = 0; ringCount < 5; ringCount++) {
-        drawLoop(0, 0, 0x90000 + (ringCount * 0x80000));
+    pfClearColor(0.0f, 0.0f, 0.0f, f);
+    if (done) {
+    } else {
+        if (f < 0.8f) {
+            f = f + 0.02f;
+            storeF(2, 0, f);
+        }
     }
 
-    return 0;
+    float touchCut = 1.f;
+    if (loadI32(0, STATE_TOUCH)) {
+        touchCut = 5.f;
+    }
+
+
+    float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+    float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+    storeF(2, SCRATCH_ZOOM, zoom);
+
+    float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
+    float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
+    storeF(2, SCRATCH_ROT, pos);
+    pos = pos - 1.f;
+
+    color(1.0f, 1.0f, 1.0f, 1.0f);
+
+
+    // Draw flat icons first
+    int index = ((int)pos) * 4;
+    int row;
+    int col;
+    float xoffset = -0.3f;
+    float gridSize = iconSize * 4.f + iconSpacing * 3.f;
+    float yoffset = (pos - ((int)pos));
+    for (row = 0; row < 4; row ++) {
+        float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
+        float ty2 = ty1 + iconSize;
+
+        for (col = 0; (col < 4) && (index < iconCount); col ++) {
+            if (index >= 0) {
+                bindTexture(NAMED_PF, 0, loadI32(1, index));
+                float fcol = col;
+                float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
+                float tx2 = tx1 + iconSize;
+
+                drawQuad(tx1, ty1, z,
+                         tx2, ty1, z,
+                         tx2, ty2, z,
+                         tx1, ty2, z);
+            }
+            index++;
+        }
+    }
+
+    // bottom roller
+    {
+        float roll = (1.f - yoffset) * 0.5f * 3.14f;
+        float tmpSin = sinf(roll);
+        float tmpCos = cosf(roll);
+
+        for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+            float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
+            float ty1 = ty2 - tmpCos * iconSize;
+
+            float tz1 = z + tmpSin * iconSize;
+            float tz2 = z;
+
+            float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+            float tx2 = tx1 + iconSize;
+
+            bindTexture(NAMED_PF, 0, loadI32(1, index));
+            drawQuad(tx1, ty1, tz1,
+                     tx2, ty1, tz1,
+                     tx2, ty2, tz2,
+                     tx1, ty2, tz2);
+            index++;
+        }
+    }
+
+    // Top roller
+    {
+        index = (((int)pos) * 4) - 4;
+        float roll = yoffset * 0.5f * 3.14f;
+        float tmpSin = sinf(roll);
+        float tmpCos = cosf(roll);
+
+        for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+            float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
+            float ty2 = ty1 + tmpCos * iconSize;
+
+            float tz1 = z;
+            float tz2 = z + tmpSin * iconSize;
+
+            float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+            float tx2 = tx1 + iconSize;
+
+            bindTexture(NAMED_PF, 0, loadI32(1, index));
+            drawQuad(tx1, ty1, tz1,
+                     tx2, ty1, tz1,
+                     tx2, ty2, tz2,
+                     tx1, ty2, tz2);
+            index++;
+        }
+    }
+
+
+
+
+    return 1;
 }
 
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
index 8f48335..14afaf8 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -18,6 +18,7 @@
 
 import java.io.Writer;
 
+import android.renderscript.RSSurfaceView;
 import android.renderscript.RenderScript;
 import android.renderscript.ProgramVertexAlloc;
 
@@ -95,8 +96,11 @@
     private RenderScript.ProgramFragment mPFImages;
     private RenderScript.ProgramVertex mPV;
     private ProgramVertexAlloc mPVAlloc;
+    private RenderScript.ProgramVertex mPVOrtho;
+    private ProgramVertexAlloc mPVOrthoAlloc;
     private RenderScript.Allocation[] mIcons;
     private RenderScript.Allocation mIconPlate;
+    private RenderScript.Allocation mBackground;
 
     private int[] mAllocStateBuf;
     private RenderScript.Allocation mAllocState;
@@ -130,23 +134,28 @@
         mRS.programFragmentStoreBegin(null, null);
         mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
         mRS.programFragmentStoreDitherEnable(false);
-        mRS.programFragmentStoreDepthMask(false);
-        mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE, 
-                                          RenderScript.BlendDstFunc.ONE);
+        mRS.programFragmentStoreDepthMask(true);
+        mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA,
+                                          RenderScript.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
         mPFSBackground = mRS.programFragmentStoreCreate();
         mPFSBackground.setName("PFS");
 
         mPVAlloc = new ProgramVertexAlloc(mRS);
         mRS.programVertexBegin(null, null);
-        mRS.programVertexSetTextureMatrixEnable(true);
+        mRS.programVertexSetTextureMatrixEnable(false);
         mPV = mRS.programVertexCreate();
         mPV.setName("PV");
         mPV.bindAllocation(0, mPVAlloc.mAlloc);
-
-
-
         mPVAlloc.setupProjectionNormalized(320, 480);
-        //mPVAlloc.setupOrthoNormalized(320, 480);
+
+        mPVOrthoAlloc = new ProgramVertexAlloc(mRS);
+        mRS.programVertexBegin(null, null);
+        mRS.programVertexSetTextureMatrixEnable(true);
+        mPVOrtho = mRS.programVertexCreate();
+        mPVOrtho.setName("PVOrtho");
+        mPVOrtho.bindAllocation(0, mPVOrthoAlloc.mAlloc);
+        mPVOrthoAlloc.setupOrthoWindow(320, 480);
+
         mRS.contextBindProgramVertex(mPV);
 
         mAllocScratchBuf = new int[32];
@@ -162,16 +171,21 @@
 
 
         {
-            mIcons = new RenderScript.Allocation[4];
+            mIcons = new RenderScript.Allocation[29];
             mAllocIconIDBuf = new int[mIcons.length];
             mAllocIconID = mRS.allocationCreatePredefSized(
                 RenderScript.ElementPredefined.USER_I32, mAllocIconIDBuf.length);
 
-            
+
             Bitmap b;
             BitmapFactory.Options opts = new BitmapFactory.Options();
             opts.inScaled = false;
 
+            b = BitmapFactory.decodeResource(mRes, R.raw.cf_background, opts);
+            mBackground = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+            mBackground.setName("TexBk");
+
+
             b = BitmapFactory.decodeResource(mRes, R.raw.browser, opts);
             mIcons[0] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
 
@@ -184,6 +198,112 @@
             b = BitmapFactory.decodeResource(mRes, R.raw.settings, opts);
             mIcons[3] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
 
+/*
+            b = BitmapFactory.decodeResource(mRes, R.raw.assasins_creed, opts);
+            mIcons[4] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.bankofamerica, opts);
+            mIcons[5] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.chess, opts);
+            mIcons[6] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.dictionary, opts);
+            mIcons[7] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.facebook, opts);
+            mIcons[8] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.flashlight, opts);
+            mIcons[9] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.flight_control, opts);
+            mIcons[10] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.google_earth, opts);
+            mIcons[11] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.harry_potter, opts);
+            mIcons[12] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.movies, opts);
+            mIcons[13] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.nytimes, opts);
+            mIcons[14] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.pandora, opts);
+            mIcons[15] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.public_radio, opts);
+            mIcons[16] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.shazam, opts);
+            mIcons[17] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.skype, opts);
+            mIcons[18] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.solitaire, opts);
+            mIcons[19] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.sudoku, opts);
+            mIcons[20] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.taptaprevenge, opts);
+            mIcons[21] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.tetris, opts);
+            mIcons[22] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.tictactoe, opts);
+            mIcons[23] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.tweetie, opts);
+            mIcons[24] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.urbanspoon, opts);
+            mIcons[25] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.waterslide_extreme, opts);
+            mIcons[26] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.weather_channel, opts);
+            mIcons[27] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+            b = BitmapFactory.decodeResource(mRes, R.raw.zippo, opts);
+            mIcons[28] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+*/
+            mIcons[4] =  mIcons[3];
+            mIcons[5] =  mIcons[2];
+            mIcons[6] =  mIcons[1];
+            mIcons[7] =  mIcons[0];
+            mIcons[8] =  mIcons[1];
+            mIcons[9] =  mIcons[2];
+            mIcons[10] = mIcons[3];
+            mIcons[11] = mIcons[2];
+            mIcons[12] = mIcons[1];
+            mIcons[13] = mIcons[0];
+            mIcons[14] = mIcons[1];
+            mIcons[15] = mIcons[2];
+            mIcons[16] = mIcons[3];
+            mIcons[17] = mIcons[2];
+            mIcons[18] = mIcons[1];
+            mIcons[19] = mIcons[0];
+            mIcons[20] = mIcons[1];
+            mIcons[21] = mIcons[2];
+            mIcons[22] = mIcons[3];
+            mIcons[23] = mIcons[2];
+            mIcons[24] = mIcons[1];
+            mIcons[25] = mIcons[0];
+            mIcons[26] = mIcons[1];
+            mIcons[27] = mIcons[2];
+            mIcons[28] = mIcons[3];
+
+
+
             for(int ct=0; ct < mIcons.length; ct++) {
                 mIcons[ct].uploadToTexture(0);
                 mAllocIconIDBuf[ct] = mIcons[ct].getID();
@@ -221,6 +341,11 @@
 
     }
 
+    private void makeTextBitmap() {
+        //Bitmap.createBitmap(width, height, Bitmap.Config);
+        //new Canvas(theBitmap);
+        //canvas.drawText();
+    }
 
 
     private void initRS() {
@@ -232,7 +357,7 @@
         //mRS.scriptCSetClearDepth(0);
         mScript = mRS.scriptCCreate();
 
-        mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, 0, 0, 38, 0, 0};
+        mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
         mAllocState = mRS.allocationCreatePredefSized(
             RenderScript.ElementPredefined.USER_I32, mAllocStateBuf.length);
         mScript.bindAllocation(mAllocState, 0);
@@ -248,4 +373,3 @@
 }
 
 
-
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
index b5e02af..27f1584 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -76,7 +76,7 @@
     float mOldColumn;
     float mZoom = 1;
 
-    int mIconCount = 38;
+    int mIconCount = 29;
     int mRows = 4;
     int mColumns = (mIconCount + mRows - 1) / mRows;
 
@@ -101,7 +101,7 @@
 
     void computeSelection(float x, float y)
     {
-        float col = mColumn + (x - 0.5f) * 3;
+        float col = mColumn + (x - 0.5f) * 4 + 1;
         int iCol = (int)(col + 0.25f);
 
         float row = (y / 0.8f) * mRows;
@@ -158,13 +158,14 @@
                     mZoom = zoom;
                     mFlingX = nx;
                     mRender.setZoom(zoom);
-                } else {
-                    if(mControlMode && (mZoom < 1.01f)) {
+                    if(mZoom < 1.01f) {
                         computeSelection(nx, ny);
                     }
+                } else {
                     mControlMode = false;
                     mColumn = mOldColumn;
                     mRender.setZoom(1.f);
+                    mRender.setSelected(-1);
                 }
             } else {
                 // Do something with corners here....
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 2f99808..45e6d1b 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -99,6 +99,16 @@
 	ret RsAllocation
 	}
 
+AllocationCreateFromBitmapBoxed {
+	param uint32_t width
+	param uint32_t height
+	param RsElementPredefined dstFmt
+	param RsElementPredefined srcFmt
+	param bool genMips
+	param const void * data
+	ret RsAllocation
+	}
+
 
 AllocationUploadToTexture {
 	param RsAllocation alloc
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index c143307..a2e3bab 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -301,14 +301,18 @@
         return elementConverter_cpy_32;
     }
 
-    LOGE("pickConverter, unsuported combo");
+    LOGE("pickConverter, unsuported combo, src %i,  dst %i", srcFmt, dstFmt);
     return 0;
 }
 
 
 RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt,  bool genMips, const void *data)
 {
-    rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+    rsAssert(!(w & (w-1)));
+    rsAssert(!(h & (h-1)));
+
+    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
+    rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt));
     rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
     rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
     if (genMips) {
@@ -340,6 +344,42 @@
     return texAlloc;
 }
 
+static uint32_t fmtToBits(RsElementPredefined fmt)
+{
+    return 16;
+}
+
+RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+    uint32_t w2 = rsHigherPow2(w);
+    uint32_t h2 = rsHigherPow2(h);
+
+    if ((w2 == w) && (h2 == h)) {
+        return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data);
+    }
+
+    uint32_t bpp = fmtToBits(srcFmt) >> 3;
+    size_t size = w2 * h2 * bpp;
+    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
+    memset(tmp, 0, size);
+
+    const uint8_t * src = static_cast<const uint8_t *>(data);
+    for (uint32_t y = 0; y < h; y++) {
+        uint8_t * ydst = &tmp[y + ((h2 - h) >> 1)];
+        memcpy(&ydst[(w2 - w) >> 1], src, w * bpp);
+        src += h * bpp;
+    }
+
+    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp);
+    free(tmp);
+    return ret;
+
+
+
+
+}
+
+
 RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
 {
     bool use32bpp = false;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 78b8bf8..e52b0e0 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -79,8 +79,7 @@
     mFragment.set(frag);
     mVertex.set(vtx);
     mFragmentStore.set(store);
-    return true;
-
+    return ret;
 }
 
 
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 497dbcf..a00b8e8 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -83,6 +83,7 @@
 
     const ProgramFragment * getFragment() {return mFragment.get();}
     const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+    const ProgramVertex * getVertex() {return mVertex.get();}
 
     void setupCheck();
 
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 417ba6a..792135d 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -55,8 +55,6 @@
         glLoadIdentity();
     }
 
-
-    LOGE("lights %i ", mLightCount);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     if (mLightCount) {
@@ -103,6 +101,25 @@
     }
 }
 
+void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
+{
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
+{
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
+{
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
+    memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+
 
 ProgramVertexState::ProgramVertexState()
 {
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index ac15b70..da5ed81 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -41,6 +41,10 @@
     void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
     void addLight(const Light *);
 
+    void setProjectionMatrix(const rsc_Matrix *) const;
+    void setModelviewMatrix(const rsc_Matrix *) const;
+    void setTextureMatrix(const rsc_Matrix *) const;
+
 protected:
     bool mDirty;
     uint32_t mLightCount;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 129b19f..10d1120 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -135,7 +135,6 @@
 
 
 
-
 //////////////////////////////////////////////////////////////////////////////
 // Matrix routines
 //////////////////////////////////////////////////////////////////////////////
@@ -257,6 +256,24 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+    GET_TLS();
+    rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+    GET_TLS();
+    rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
 // Drawing
 //////////////////////////////////////////////////////////////////////////////
 
@@ -343,20 +360,12 @@
 //
 //////////////////////////////////////////////////////////////////////////////
 
-extern "C" const void * loadVp(uint32_t bank, uint32_t offset)
-{
-    GET_TLS();
-    return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset];
-}
-
-
-
 static void SC_color(float r, float g, float b, float a)
 {
     glColor4f(r, g, b, a);
 }
 
-
+/*
 extern "C" void materialDiffuse(float r, float g, float b, float a)
 {
     float v[] = {r, g, b, a};
@@ -369,35 +378,18 @@
     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
 }
 
-extern "C" void lightPosition(float x, float y, float z, float w)
-{
-    float v[] = {x, y, z, w};
-    glLightfv(GL_LIGHT0, GL_POSITION, v);
-}
-
 extern "C" void materialShininess(float s)
 {
     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
 }
+*/
 
-extern "C" void uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
 {
     GET_TLS();
     rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
 }
 
-extern "C" void enable(uint32_t p)
-{
-    glEnable(p);
-}
-
-extern "C" void disable(uint32_t p)
-{
-    glDisable(p);
-}
-
-
-
 static void SC_ClearColor(float r, float g, float b, float a)
 {
     //LOGE("c %f %f %f %f", r, g, b, a);
@@ -408,6 +400,16 @@
     sc->mEnviroment.mClearColor[3] = a;
 }
 
+static void SC_debugF(const char *s, float f)
+{
+    LOGE("%s %f", s, f);
+}
+
+static void SC_debugI32(const char *s, int32_t i)
+{
+    LOGE("%s %i", s, i);
+}
+
 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -444,6 +446,10 @@
         "float", "(float)" },
     { "randf", (void *)&SC_randf,
         "float", "(float)" },
+    { "floorf", (void *)&floorf,
+        "float", "(float)" },
+    { "ceilf", (void *)&ceilf,
+        "float", "(float)" },
 
     // matrix
     { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
@@ -481,6 +487,14 @@
     { "bindTexture", (void *)&SC_bindTexture,
         "void", "(int, int, int)" },
 
+    // vp
+    { "vpLoadModelMatrix", (void *)&SC_bindProgramFragment,
+        "void", "(void *)" },
+    { "vpLoadTextureMatrix", (void *)&SC_bindProgramFragmentStore,
+        "void", "(void *)" },
+
+
+
     // drawing
     { "drawQuad", (void *)&SC_drawQuad,
         "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
@@ -495,10 +509,19 @@
     // misc
     { "pfClearColor", (void *)&SC_ClearColor,
         "void", "(float, float, float, float)" },
-
     { "color", (void *)&SC_color,
         "void", "(float, float, float, float)" },
 
+    { "uploadToTexture", (void *)&SC_uploadToTexture,
+        "void", "(int, int)" },
+
+
+    { "debugF", (void *)&SC_debugF,
+        "void", "(void *, float)" },
+    { "debugI32", (void *)&SC_debugI32,
+        "void", "(void *, int)" },
+
+
     { NULL, NULL, NULL, NULL }
 };
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 7a7574f..102899c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -650,6 +650,7 @@
                 if (currentLayers.indexOf( layer ) < 0) {
                     // this layer is not visible anymore
                     ditchedLayers.add(layer);
+                    mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
                 }
             }
         }
@@ -685,17 +686,15 @@
         layer->validateVisibility(planeTransform);
 
         // start with the whole surface at its current location
-        const Layer::State& s = layer->drawingState();
-        const Rect bounds(layer->visibleBounds());
+        const Layer::State& s(layer->drawingState());
 
         // handle hidden surfaces by setting the visible region to empty
         Region opaqueRegion;
         Region visibleRegion;
         Region coveredRegion;
-        if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
-            visibleRegion.clear();
-        } else {
+        if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
             const bool translucent = layer->needsBlending();
+            const Rect bounds(layer->visibleBounds());
             visibleRegion.set(bounds);
             coveredRegion = visibleRegion;
 
@@ -742,12 +741,16 @@
         layer->setVisibleRegion(visibleRegion);
         layer->setCoveredRegion(coveredRegion);
 
-        // If a secure layer is partially visible, lock down the screen!
+        // If a secure layer is partially visible, lock-down the screen!
         if (layer->isSecure() && !visibleRegion.isEmpty()) {
             secureFrameBuffer = true;
         }
     }
 
+    // invalidate the areas where a layer was removed
+    dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
+    mDirtyRegionRemovedLayer.clear();
+
     mSecureFrameBuffer = secureFrameBuffer;
     opaqueRegion = aboveOpaqueLayers;
 }
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index e8687a7..2569a0f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -334,6 +334,7 @@
                 // Can only accessed from the main thread, these members
                 // don't need synchronization
                 Region                      mDirtyRegion;
+                Region                      mDirtyRegionRemovedLayer;
                 Region                      mInvalidRegion;
                 Region                      mWormholeRegion;
                 wp<Client>                  mLastScheduledBroadcast;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1d960c5..95d61cd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,8 @@
 #include <media/PVPlayer.h>
 #include "TestPlayerStub.h"
 
+//#undef USE_STAGEFRIGHT
+
 #if USE_STAGEFRIGHT
 #include "StagefrightPlayer.h"
 #endif
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5944d9c..5be9224 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -26,6 +26,7 @@
         SurfaceRenderer.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
+        TIHardwareRenderer.cpp    \
         Utils.cpp                 \
         AudioPlayer.cpp           \
         ESDS.cpp                  \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 17c72b9..d547556 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -87,7 +87,10 @@
     } else {
         mAudioTrack = new AudioTrack(
                 AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
-                numChannels, 8192, 0, &AudioCallback, this, 0);
+                (numChannels == 2)
+                    ? AudioSystem::CHANNEL_OUT_STEREO
+                    : AudioSystem::CHANNEL_OUT_MONO,
+                8192, 0, &AudioCallback, this, 0);
 
         assert(mAudioTrack->initCheck() == OK);
 
@@ -217,8 +220,10 @@
 
             Mutex::Autolock autoLock(mLock);
             mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
             mPositionTimeRealUs =
-                ((mNumFramesPlayed + size_done / 4) * 1000000) / mSampleRate; // XXX
+                ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+                    / mSampleRate;
         }
 
         if (mInputBuffer->range_length() == 0) {
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 6b47a38..01cb2d9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -73,8 +73,6 @@
 
     if (bitrate_index == 0 || bitrate_index == 0x0f) {
         // Disallow "free" bitrate.
-
-        LOGE("We disallow 'free' bitrate for now.");
         return false;
     }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index caaec06..4c883c6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -73,6 +73,8 @@
 
     bool mNeedsNALFraming;
 
+    uint8_t *mSrcBuffer;
+
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
 };
@@ -743,7 +745,8 @@
       mBuffer(NULL),
       mBufferOffset(0),
       mBufferSizeRemaining(0),
-      mNeedsNALFraming(false) {
+      mNeedsNALFraming(false),
+      mSrcBuffer(NULL) {
     const char *mime;
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
     assert(success);
@@ -777,8 +780,13 @@
     status_t err = mSampleTable->getMaxSampleSize(&max_size);
     assert(err == OK);
 
-    // Add padding for de-framing of AVC content just in case.
-    mGroup->add_buffer(new MediaBuffer(max_size + 2));
+    // Assume that a given buffer only contains at most 10 fragments,
+    // each fragment originally prefixed with a 2 byte length will
+    // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+    // and thus will grow by 2 bytes per fragment.
+    mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+    mSrcBuffer = new uint8_t[max_size];
 
     mStarted = true;
 
@@ -793,6 +801,9 @@
         mBuffer = NULL;
     }
 
+    delete[] mSrcBuffer;
+    mSrcBuffer = NULL;
+
     delete mGroup;
     mGroup = NULL;
 
@@ -832,33 +843,31 @@
         // fall through
     }
 
-    if (mBuffer == NULL) {
-        off_t offset;
-        size_t size;
-        status_t err = mSampleTable->getSampleOffsetAndSize(
-                mCurrentSampleIndex, &offset, &size);
+    off_t offset;
+    size_t size;
+    status_t err = mSampleTable->getSampleOffsetAndSize(
+            mCurrentSampleIndex, &offset, &size);
 
-        if (err != OK) {
-            return err;
-        }
+    if (err != OK) {
+        return err;
+    }
 
-        uint32_t dts;
-        err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+    uint32_t dts;
+    err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
 
-        if (err != OK) {
-            return err;
-        }
+    if (err != OK) {
+        return err;
+    }
 
-        err = mGroup->acquire_buffer(&mBuffer);
-        if (err != OK) {
-            assert(mBuffer == NULL);
-            return err;
-        }
+    err = mGroup->acquire_buffer(&mBuffer);
+    if (err != OK) {
+        assert(mBuffer == NULL);
+        return err;
+    }
 
-        assert(mBuffer->size() + 2 >= size);
-
+    if (!mIsAVC || !mNeedsNALFraming) {
         ssize_t num_bytes_read =
-            mDataSource->read_at(offset, (uint8_t *)mBuffer->data() + 2, size);
+            mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
@@ -867,50 +876,62 @@
             return err;
         }
 
-        mBuffer->set_range(2, size);
+        mBuffer->set_range(0, size);
         mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
         mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
-
         ++mCurrentSampleIndex;
 
-        mBufferOffset = 2;
-        mBufferSizeRemaining = size;
-    }
-
-    if (!mIsAVC) {
         *out = mBuffer;
         mBuffer = NULL;
 
         return OK;
     }
 
-    uint8_t *data = (uint8_t *)mBuffer->data() + mBufferOffset;
-    assert(mBufferSizeRemaining >= 2);
+    ssize_t num_bytes_read =
+        mDataSource->read_at(offset, mSrcBuffer, size);
 
-    size_t nal_length = (data[0] << 8) | data[1];
-    assert(mBufferSizeRemaining >= 2 + nal_length);
-
-    if (mNeedsNALFraming) {
-        // Insert marker.
-        data[-2] = data[-1] = data[0] = 0;
-        data[1] = 1;
-
-        mBuffer->set_range(mBufferOffset - 2, nal_length + 4);
-    } else {
-        mBuffer->set_range(mBufferOffset + 2, nal_length);
-    }
-
-    mBufferOffset += nal_length + 2;
-    mBufferSizeRemaining -= nal_length + 2;
-
-    if (mBufferSizeRemaining > 0) {
-        *out = mBuffer->clone();
-    } else {
-        *out = mBuffer;
+    if (num_bytes_read < (ssize_t)size) {
+        mBuffer->release();
         mBuffer = NULL;
+
+        return err;
     }
 
+    uint8_t *dstData = (uint8_t *)mBuffer->data();
+    size_t srcOffset = 0;
+    size_t dstOffset = 0;
+    while (srcOffset < size) {
+        assert(srcOffset + 1 < size);
+        size_t nalLength =
+            (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+        assert(srcOffset + 1 + nalLength < size);
+        srcOffset += 2;
+
+        if (nalLength == 0) {
+            continue;
+        }
+
+        assert(dstOffset + 4 <= mBuffer->size());
+
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 0;
+        dstData[dstOffset++] = 1;
+        memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+        srcOffset += nalLength;
+        dstOffset += nalLength;
+    }
+
+    mBuffer->set_range(0, dstOffset);
+    mBuffer->meta_data()->clear();
+    mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+    mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+    ++mCurrentSampleIndex;
+
+    *out = mBuffer;
+    mBuffer = NULL;
+
     return OK;
 }
 
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 78fcdee..04c9a11 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -40,6 +40,7 @@
 #include <media/stagefright/SoftwareRenderer.h>
 #include <media/stagefright/SurfaceRenderer.h>
 #include <media/stagefright/TimeSource.h>
+#include <media/stagefright/TIHardwareRenderer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Surface.h>
 
@@ -311,6 +312,9 @@
         {
             Mutex::Autolock autoLock(mLock);
             mVideoPosition = pts_us;
+
+            LOGV("now_video = %.2f secs (%lld ms)",
+                 pts_us / 1E6, (pts_us + 500) / 1000);
         }
 
         if (seeking && mAudioPlayer != NULL) {
@@ -344,6 +348,7 @@
         if (mAudioPlayer != NULL
             && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
             mTimeSourceDeltaUs = realtime_us - mediatime_us;
+            LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
         }
 
         int64_t now_us = mTimeSource->getRealTimeUs();
@@ -436,6 +441,7 @@
 }
 
 void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+    LOGI("setAudioSource");
     mAudioSource = source;
 
     sp<MetaData> meta = source->getFormat();
@@ -646,17 +652,28 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     assert(success);
 
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
     if (mSurface.get() != NULL) {
+        LOGW("Using SurfaceRenderer.");
         mRenderer =
             new SurfaceRenderer(
                     mSurface, mVideoWidth, mVideoHeight,
                     decodedWidth, decodedHeight);
-    } else if (format == OMX_COLOR_FormatYUV420Planar
-        && !strncasecmp(component, "OMX.qcom.video.decoder.", 23)) {
+    } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+        && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
+        LOGW("Using QComHardwareRenderer.");
         mRenderer =
             new QComHardwareRenderer(
                     mISurface, mVideoWidth, mVideoHeight,
                     decodedWidth, decodedHeight);
+    } else if (format == OMX_COLOR_FormatCbYCrY
+            && !strcmp(component, "OMX.TI.Video.Decoder")) {
+        LOGW("Using TIHardwareRenderer.");
+        mRenderer =
+            new TIHardwareRenderer(
+                    mISurface, mVideoWidth, mVideoHeight,
+                    decodedWidth, decodedHeight);
     } else {
         LOGW("Using software renderer.");
         mRenderer = new SoftwareRenderer(
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index c059a9d..5e44999 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -20,6 +20,7 @@
 
 #undef NDEBUG
 #include <assert.h>
+#include <ctype.h>
 
 #include <OMX_Component.h>
 
@@ -54,14 +55,20 @@
 };
 
 static const CodecInfo kDecoderInfo[] = {
+    { "audio/mpeg", "OMX.TI.MP3.decode" },
     { "audio/mpeg", "OMX.PV.mp3dec" },
+    { "audio/3gpp", "OMX.TI.AMR.decode" },
     { "audio/3gpp", "OMX.PV.amrdec" },
+    { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
     { "audio/mp4a-latm", "OMX.PV.aacdec" },
     { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+    { "video/mp4v-es", "OMX.TI.Video.Decoder" },
     { "video/mp4v-es", "OMX.PV.mpeg4dec" },
     { "video/3gpp", "OMX.qcom.video.decoder.h263" },
+    { "video/3gpp", "OMX.TI.Video.Decoder" },
     { "video/3gpp", "OMX.PV.h263dec" },
     { "video/avc", "OMX.qcom.video.decoder.avc" },
+    { "video/avc", "OMX.TI.Video.Decoder" },
     { "video/avc", "OMX.PV.avcdec" },
 };
 
@@ -92,7 +99,9 @@
 }
 
 // static
-OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
+OMXDecoder *OMXDecoder::Create(
+        OMXClient *client, const sp<MetaData> &meta,
+        bool createEncoder) {
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     assert(success);
@@ -102,9 +111,15 @@
     const char *codec = NULL;
     IOMX::node_id node = 0;
     for (int index = 0;; ++index) {
-        codec = GetCodec(
-                kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
-                mime, index);
+        if (createEncoder) {
+            codec = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            codec = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
 
         if (!codec) {
             return NULL;
@@ -118,7 +133,33 @@
         }
     }
 
-    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec);
+    uint32_t quirks = 0;
+    if (!strcmp(codec, "OMX.PV.avcdec")) {
+        quirks |= kWantsRawNALFrames;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")
+        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+        quirks |= kDoesntReturnBuffersOnDisable;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+        quirks |= kDoesntFlushOnExecutingToIdle;
+        quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
+    }
+    if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+        quirks |= kRequiresLoadedToIdleAfterAllocation;
+    }
+    if (!strcmp(codec, "OMX.TI.AAC.decode")
+        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+        quirks |= kMeasuresTimeInMilliseconds;
+    }
+
+    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
 
     uint32_t type;
     const void *data;
@@ -169,52 +210,22 @@
     return decoder;
 }
 
-// static
-OMXDecoder *OMXDecoder::CreateEncoder(
-        OMXClient *client, const sp<MetaData> &meta) {
-    const char *mime;
-    bool success = meta->findCString(kKeyMIMEType, &mime);
-    assert(success);
-
-    sp<IOMX> omx = client->interface();
-
-    const char *codec = NULL;
-    IOMX::node_id node = 0;
-    for (int index = 0;; ++index) {
-        codec = GetCodec(
-                kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
-                mime, index);
-
-        if (!codec) {
-            return NULL;
-        }
-
-        LOGI("Attempting to allocate OMX node '%s'", codec);
-
-        status_t err = omx->allocate_node(codec, &node);
-        if (err == OK) {
-            break;
-        }
-    }
-
-    OMXDecoder *encoder = new OMXDecoder(client, node, mime, codec);
-
-    return encoder;
-}
-
 OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
-                       const char *mime, const char *codec)
+                       const char *mime, const char *codec,
+                       uint32_t quirks)
     : mClient(client),
       mOMX(mClient->interface()),
       mNode(node),
       mComponentName(strdup(codec)),
       mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+      mIsAVC(!strcasecmp(mime, "video/avc")),
+      mQuirks(quirks),
       mSource(NULL),
       mCodecSpecificDataIterator(mCodecSpecificData.begin()),
       mState(OMX_StateLoaded),
       mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
       mShutdownInitiated(false),
-      mDealer(new MemoryDealer(3 * 1024 * 1024)),
+      mDealer(new MemoryDealer(5 * 1024 * 1024)),
       mSeeking(false),
       mStarted(false),
       mErrorCondition(OK),
@@ -261,7 +272,7 @@
     // mDealer->dump("Decoder Dealer");
 
     sp<MetaData> params = new MetaData;
-    if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+    if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
         params->setInt32(kKeyNeedsNALFraming, true);
     }
 
@@ -297,7 +308,7 @@
     }
 
     int attempt = 1;
-    while (mState != OMX_StateLoaded && attempt < 10) {
+    while (mState != OMX_StateLoaded && attempt < 20) {
         usleep(100000);
 
         ++attempt;
@@ -366,7 +377,11 @@
             mOutputBuffers.erase(mOutputBuffers.begin());
         }
 
-        status_t err = mOMX->send_command(mNode, OMX_CommandFlush, -1);
+        // XXX One of TI's decoders appears to ignore a flush if it doesn't
+        // currently hold on to any buffers on the port in question and
+        // never sends the completion event... FIXME
+
+        status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
         assert(err == OK);
 
         // Once flushing is completed buffers will again be scheduled to be
@@ -472,9 +487,121 @@
     assert(err == NO_ERROR);
 }
 
-void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
+status_t OMXDecoder::setVideoPortFormatType(
+        OMX_U32 portIndex,
+        OMX_VIDEO_CODINGTYPE compressionFormat,
+        OMX_COLOR_FORMATTYPE colorFormat) {
+    OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+    format.nSize = sizeof(format);
+    format.nVersion.s.nVersionMajor = 1;
+    format.nVersion.s.nVersionMinor = 1;
+    format.nPortIndex = portIndex;
+    format.nIndex = 0;
+    bool found = false;
+
+    OMX_U32 index = 0;
+    for (;;) {
+        format.nIndex = index;
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+
+        if (err != OK) {
+            return err;
+        }
+
+        // The following assertion is violated by TI's video decoder.
+        // assert(format.nIndex == index);
+
+        if (format.eCompressionFormat == compressionFormat
+            && format.eColorFormat == colorFormat) {
+            found = true;
+            break;
+        }
+
+        ++index;
+    }
+
+    if (!found) {
+        return UNKNOWN_ERROR;
+    }
+
+    status_t err = mOMX->set_parameter(
+            mNode, OMX_IndexParamVideoPortFormat,
+            &format, sizeof(format));
+
+    return err;
+}
+
+#if 1
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
     LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
+#if 1
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the TI decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    if (!strcasecmp("video/avc", mime)) {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+    if (!strcasecmp("video/avc", mime)) {
+        compressionFormat = OMX_VIDEO_CodingAVC;
+    } else if (!strcasecmp("video/mp4v-es", mime)) {
+        compressionFormat = OMX_VIDEO_CodingMPEG4;
+    } else if (!strcasecmp("video/3gpp", mime)) {
+        compressionFormat = OMX_VIDEO_CodingH263;
+    } else {
+        assert(!"Should not be here. Not a supported video mime type.");
+    }
+
+    setVideoPortFormatType(
+            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
     OMX_PARAM_PORTDEFINITIONTYPE def;
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
@@ -502,7 +629,7 @@
     
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
-    // video_def.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
     video_def->eColorFormat = OMX_COLOR_FormatUnused;
 
     err = mOMX->set_parameter(
@@ -522,21 +649,189 @@
 
     assert(def.eDomain == OMX_PortDomainVideo);
     
+#if 0
     def.nBufferSize =
         (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2;  // YUV420
+#endif
 
     video_def->nFrameWidth = width;
     video_def->nFrameHeight = height;
-    video_def->nStride = width;
-    // video_def->nSliceHeight = height;
-    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
-//    video_def->eColorFormat = OMX_COLOR_FormatYUV420Planar;
 
     err = mOMX->set_parameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     assert(err == NO_ERROR);
 }
 
+#else
+static void hexdump(const void *_data, size_t size) {
+    char line[256];
+    char tmp[16];
+
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        sprintf(line, "0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                strcat(line, " ");
+            }
+
+            if (offset + i < size) {
+                sprintf(tmp, "%02x ", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, "   ");
+            }
+        }
+
+        strcat(line, " ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                sprintf(tmp, "%c", data[offset + i]);
+                strcat(line, tmp);
+            } else {
+                strcat(line, ".");
+            }
+        }
+
+        LOGI(line);
+
+        offset += 16;
+    }
+}
+
+static void DumpPortDefinitionType(const void *_param) {
+    OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
+
+    LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
+        param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
+
+    if (param->eDomain == OMX_PortDomainVideo) {
+        OMX_VIDEO_PORTDEFINITIONTYPE *video = &param->format.video;
+        LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
+            video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
+    } else {
+        hexdump(param, param->nSize);
+    }
+}
+
+void OMXDecoder::setVideoOutputFormat(
+        const char *mime, OMX_U32 width, OMX_U32 height) {
+    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 0
+    // Enabling this code appears to be the right thing(tm), but,...
+    // the decoder then loses the ability to output YUV420 and only outputs
+    // YCbYCr (16bit)
+    {
+        OMX_PARAM_COMPONENTROLETYPE role;
+        role.nSize = sizeof(role);
+        role.nVersion.s.nVersionMajor = 1;
+        role.nVersion.s.nVersionMinor = 1;
+        strncpy((char *)role.cRole, "video_decoder.avc",
+                OMX_MAX_STRINGNAME_SIZE - 1);
+        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &role, sizeof(role));
+        assert(err == OK);
+    }
+#endif
+
+    setVideoPortFormatType(
+            kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
+
+#if 1
+    {
+        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+        format.nSize = sizeof(format);
+        format.nVersion.s.nVersionMajor = 1;
+        format.nVersion.s.nVersionMinor = 1;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+
+        LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
+        hexdump(&format, format.nSize);
+
+        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+               || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
+
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &format, sizeof(format));
+        assert(err == OK);
+    }
+#endif
+
+    OMX_PORT_PARAM_TYPE ptype;
+    ptype.nSize = sizeof(ptype);
+    ptype.nVersion.s.nVersionMajor = 1;
+    ptype.nVersion.s.nVersionMinor = 1;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
+    hexdump(&ptype, ptype.nSize);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    def.nSize = sizeof(def);
+    def.nVersion.s.nVersionMajor = 1;
+    def.nVersion.s.nVersionMinor = 1;
+    def.nPortIndex = kPortIndexInput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    def.nPortIndex = kPortIndexOutput;
+
+    err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+
+    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+    DumpPortDefinitionType(&def);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    assert(err == OK);
+}
+
+#endif
+
 void OMXDecoder::setup() {
     const sp<MetaData> &meta = mSource->getFormat();
 
@@ -554,7 +849,7 @@
         success = success && meta->findInt32(kKeyHeight, &height);
         assert(success);
 
-        setVideoOutputFormat(width, height);
+        setVideoOutputFormat(mime, width, height);
     }
 
     // dumpPortDefinition(0);
@@ -644,10 +939,7 @@
 }
 
 void OMXDecoder::onStart() {
-    bool needs_qcom_hack =
-        !strncmp(mComponentName, "OMX.qcom.video.", 15);
-
-    if (!needs_qcom_hack) {
+    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
         status_t err =
             mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
         assert(err == NO_ERROR);
@@ -656,7 +948,7 @@
     allocateBuffers(kPortIndexInput);
     allocateBuffers(kPortIndexOutput);
 
-    if (needs_qcom_hack) {
+    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
         // XXX this should happen before AllocateBuffers, but qcom's
         // h264 vdec disagrees.
         status_t err =
@@ -691,13 +983,17 @@
 
     for (OMX_U32 i = 0; i < num_buffers; ++i) {
         sp<IMemory> mem = mDealer->allocate(buffer_size);
+        if (mem.get() == NULL) {
+            LOGE("[%s] allocating IMemory of size %ld FAILED.",
+                 mComponentName, buffer_size);
+        }
         assert(mem.get() != NULL);
 
         IOMX::buffer_id buffer;
         status_t err;
 
         if (port_index == kPortIndexInput
-            && !strncmp(mComponentName, "OMX.qcom.video.encoder.", 23)) {
+                && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
             // qcom's H.263 encoder appears to want to allocate its own input
             // buffers.
             err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
@@ -706,7 +1002,7 @@
                      mComponentName, err);
             }
         } else if (port_index == kPortIndexOutput
-            && !strncmp(mComponentName, "OMX.qcom.video.decoder.", 23)) {
+                && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
 #if 1
             err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
 #else
@@ -817,18 +1113,59 @@
         case OMX_CommandFlush: {
             OMX_U32 port_index = data;
             LOGV("Port %ld flush complete.", port_index);
-            assert(getPortStatus(port_index) == kPortStatusFlushing);
 
-            setPortStatus(port_index, kPortStatusActive);
-            BufferList *buffers = &mBuffers.editItemAt(port_index);
-            while (!buffers->empty()) {
-                IOMX::buffer_id buffer = *buffers->begin();
-                buffers->erase(buffers->begin());
+            PortStatus status = getPortStatus(port_index);
 
-                if (port_index == kPortIndexInput) {
-                    postEmptyBufferDone(buffer);
-                } else {
-                    postInitialFillBuffer(buffer);
+            assert(status == kPortStatusFlushing
+                    || status == kPortStatusFlushingToDisabled
+                    || status == kPortStatusFlushingToShutdown);
+
+            switch (status) {
+                case kPortStatusFlushing:
+                {
+                    // This happens when we're flushing before a seek.
+                    setPortStatus(port_index, kPortStatusActive);
+                    BufferList *buffers = &mBuffers.editItemAt(port_index);
+                    while (!buffers->empty()) {
+                        IOMX::buffer_id buffer = *buffers->begin();
+                        buffers->erase(buffers->begin());
+
+                        if (port_index == kPortIndexInput) {
+                            postEmptyBufferDone(buffer);
+                        } else {
+                            postInitialFillBuffer(buffer);
+                        }
+                    }
+                    break;
+                }
+
+                case kPortStatusFlushingToDisabled:
+                {
+                    // Port settings have changed and the (buggy) OMX component
+                    // does not properly return buffers on disabling, we need to
+                    // do a flush first and _then_ disable the port in question.
+
+                    setPortStatus(port_index, kPortStatusDisabled);
+                    status_t err = mOMX->send_command(
+                            mNode, OMX_CommandPortDisable, port_index);
+                    assert(err == OK);
+
+                    freePortBuffers(port_index);
+                    break;
+                }
+
+                default:
+                {
+                    assert(status == kPortStatusFlushingToShutdown);
+
+                    setPortStatus(port_index, kPortStatusShutdown);
+                    if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
+                        && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
+                        status_t err = mOMX->send_command(
+                                mNode, OMX_CommandStateSet, OMX_StateIdle);
+                        assert(err == OK);
+                    }
+                    break;
                 }
             }
             break;
@@ -841,10 +1178,22 @@
 
 void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
     assert(getPortStatus(port_index) == kPortStatusActive);
-    setPortStatus(port_index, kPortStatusDisabled);
 
-    status_t err =
-        mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+    status_t err;
+
+    if (mQuirks & kDoesntReturnBuffersOnDisable) {
+        // Decoder does not properly return our buffers when disabled...
+        // Need to flush port instead and _then_ disable.
+
+        setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+    } else {
+        setPortStatus(port_index, kPortStatusDisabled);
+
+        err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+    }
+
     assert(err == NO_ERROR);
 }
 
@@ -894,19 +1243,8 @@
             mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
         assert(err == NO_ERROR);
 
-        BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
-        for (BufferList::iterator it = ibuffers->begin();
-             it != ibuffers->end(); ++it) {
-            freeInputBuffer(*it);
-        }
-        ibuffers->clear();
-
-        BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
-        for (BufferList::iterator it = obuffers->begin();
-             it != obuffers->end(); ++it) {
-            freeOutputBuffer(*it);
-        }
-        obuffers->clear();
+        freePortBuffers(kPortIndexInput);
+        freePortBuffers(kPortIndexOutput);
     }
 }
 
@@ -925,26 +1263,41 @@
 
     mShutdownInitiated = true;
 
-    status_t err =
-        mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
-    assert(err == NO_ERROR);
+    status_t err;
+    if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+        if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+            assert(err == OK);
 
-    setPortStatus(kPortIndexInput, kPortStatusShutdown);
-    setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+            err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+        } else {
+            err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+        }
+
+        setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+    } else {
+        err = mClient->send_command(
+                mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+        setPortStatus(kPortIndexInput, kPortStatusShutdown);
+        setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+    }
+    assert(err == OK);
 }
 
 void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
-    int shift = 2 * port_index;
+    int shift = 3 * port_index;
 
-    mPortStatusMask &= ~(3 << shift);
+    mPortStatusMask &= ~(7 << shift);
     mPortStatusMask |= status << shift;
 }
 
 OMXDecoder::PortStatus OMXDecoder::getPortStatus(
         OMX_U32 port_index) const {
-    int shift = 2 * port_index;
+    int shift = 3 * port_index;
 
-    return static_cast<PortStatus>((mPortStatusMask >> shift) & 3);
+    return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
 }
 
 void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -964,6 +1317,8 @@
             break;
 
         case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
             LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
             mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
             err = NO_ERROR;
@@ -980,7 +1335,9 @@
 void OMXDecoder::onFillBufferDone(const omx_message &msg) {
     IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
 
-    LOGV("[%s] onFillBufferDone (%p)", mComponentName, buffer);
+    LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+         msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+         buffer, msg.u.extended_buffer_data.range_length);
 
     status_t err;
     switch (getPortStatus(kPortIndexOutput)) {
@@ -995,6 +1352,8 @@
             break;
 
         case kPortStatusFlushing:
+        case kPortStatusFlushingToDisabled:
+        case kPortStatusFlushingToShutdown:
             LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
             mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
             err = NO_ERROR;
@@ -1035,7 +1394,7 @@
 
         size_t range_length = 0;
 
-        if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+        if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
             assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
 
             memcpy(mem->pointer(), kNALStartCode, 4);
@@ -1142,15 +1501,18 @@
     OMX_TICKS timestamp = 0;
 
     if (success) {
-        // XXX units should be microseconds but PV treats them as milliseconds.
-        timestamp = ((OMX_S64)units * 1000) / scale;
+        if (mQuirks & kMeasuresTimeInMilliseconds) {
+            timestamp = ((OMX_S64)units * 1000) / scale;
+        } else {
+            timestamp = ((OMX_S64)units * 1000000) / scale;
+        }
     }
 
     input_buffer->release();
     input_buffer = NULL;
 
-    LOGV("[%s] Calling EmptyBuffer on buffer %p",
-         mComponentName, buffer);
+    LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+         mComponentName, buffer, src_length, flags);
 
     status_t err2 = mClient->emptyBuffer(
             mNode, buffer, 0, src_length, flags, timestamp);
@@ -1169,8 +1531,16 @@
 
     media_buffer->meta_data()->clear();
 
-    media_buffer->meta_data()->setInt32(
-            kKeyTimeUnits, msg.u.extended_buffer_data.timestamp);
+    if (mQuirks & kMeasuresTimeInMilliseconds) {
+        media_buffer->meta_data()->setInt32(
+                kKeyTimeUnits,
+                msg.u.extended_buffer_data.timestamp);
+    } else {
+        media_buffer->meta_data()->setInt32(
+                kKeyTimeUnits,
+                (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+    }
+
     media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
 
     if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
@@ -1198,7 +1568,9 @@
 
     PortStatus outputStatus = getPortStatus(kPortIndexOutput);
     if (outputStatus == kPortStatusShutdown
-            || outputStatus == kPortStatusFlushing) {
+            || outputStatus == kPortStatusFlushing
+            || outputStatus == kPortStatusFlushingToDisabled
+            || outputStatus == kPortStatusFlushingToShutdown) {
         mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
     } else {
         LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
@@ -1326,4 +1698,18 @@
     postMessage(msg);
 }
 
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+    BufferList *buffers = &mBuffers.editItemAt(port_index);
+    while (!buffers->empty()) {
+        IOMX::buffer_id buffer = *buffers->begin();
+        buffers->erase(buffers->begin());
+
+        if (port_index == kPortIndexInput) {
+            freeInputBuffer(buffer);
+        } else {
+            freeOutputBuffer(buffer);
+        }
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+        const sp<ISurface> &surface,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight)
+    : mISurface(surface),
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mDecodedWidth(decodedWidth),
+      mDecodedHeight(decodedHeight),
+      mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+    assert(mISurface.get() != NULL);
+    assert(mDecodedWidth > 0);
+    assert(mDecodedHeight > 0);
+
+    sp<OverlayRef> ref = mISurface->createOverlay(
+            mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+    if (ref.get() == NULL) {
+        LOGE("Unable to create the overlay!");
+        return;
+    }
+
+    mOverlay = new Overlay(ref);
+
+    for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+        mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+    }
+    mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+    if (mOverlay.get() != NULL) {
+        mOverlay->destroy();
+        mOverlay.clear();
+
+        // XXX apparently destroying an overlay is an asynchronous process...
+        sleep(1);
+    }
+}
+
+void TIHardwareRenderer::render(
+        const void *data, size_t size, void *platformPrivate) {
+    // assert(size == mFrameSize);
+
+    if (mOverlay.get() == NULL) {
+        return;
+    }
+
+#if 0
+    overlay_buffer_t buffer;
+    if (mOverlay->dequeueBuffer(&buffer) == OK) {
+        void *addr = mOverlay->getBufferAddress(buffer);
+
+        memcpy(addr, data, size);
+
+        mOverlay->queueBuffer(buffer);
+    }
+#else
+    memcpy(mOverlayAddresses[mIndex], data, size);
+    mOverlay->queueBuffer((void *)mIndex);
+
+    if (mIndex-- == 0) {
+        mIndex = mOverlayAddresses.size() - 1;
+    }
+#endif
+}
+
+}  // namespace android
+
diff --git a/packages/SettingsProvider/res/values-cs/defaults.xml b/packages/SettingsProvider/res/values-cs/defaults.xml
deleted file mode 100644
index a7c01b3..0000000
--- a/packages/SettingsProvider/res/values-cs/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"mobil,bluetooth,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-cs/strings.xml b/packages/SettingsProvider/res/values-cs/strings.xml
index dc75a92..2b089d9 100644
--- a/packages/SettingsProvider/res/values-cs/strings.xml
+++ b/packages/SettingsProvider/res/values-cs/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Paměť pro nastavení"</string>
+    <string name="app_label" msgid="4567566098528588863">"Paměť pro nastavení"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-de/defaults.xml b/packages/SettingsProvider/res/values-de/defaults.xml
deleted file mode 100644
index f85d3f0..0000000
--- a/packages/SettingsProvider/res/values-de/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"Mobilfunk, Bluetooth, WLAN"</string>
-    <string name="def_location_providers_allowed">"GPS"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml
index 50c8a14..a293522 100644
--- a/packages/SettingsProvider/res/values-de/strings.xml
+++ b/packages/SettingsProvider/res/values-de/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Einstellungsspeicher"</string>
+    <string name="app_label" msgid="4567566098528588863">"Einstellungsspeicher"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-es/defaults.xml b/packages/SettingsProvider/res/values-es/defaults.xml
deleted file mode 100644
index a64805a..0000000
--- a/packages/SettingsProvider/res/values-es/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"móvil,bluetooth,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml
index d30d195..de3958b 100644
--- a/packages/SettingsProvider/res/values-es/strings.xml
+++ b/packages/SettingsProvider/res/values-es/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Almacenamiento de configuración"</string>
+    <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-fr/defaults.xml b/packages/SettingsProvider/res/values-fr/defaults.xml
deleted file mode 100644
index 56334cc..0000000
--- a/packages/SettingsProvider/res/values-fr/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"cellulaire, Bluetooth, Wi-Fi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-fr/strings.xml b/packages/SettingsProvider/res/values-fr/strings.xml
index 686ec8b..7a1386a 100644
--- a/packages/SettingsProvider/res/values-fr/strings.xml
+++ b/packages/SettingsProvider/res/values-fr/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Stockage des paramètres"</string>
+    <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-it/defaults.xml b/packages/SettingsProvider/res/values-it/defaults.xml
deleted file mode 100644
index 19c0896..0000000
--- a/packages/SettingsProvider/res/values-it/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"cellulare,bluetooth,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-it/strings.xml b/packages/SettingsProvider/res/values-it/strings.xml
index 29e462f..f88a654 100644
--- a/packages/SettingsProvider/res/values-it/strings.xml
+++ b/packages/SettingsProvider/res/values-it/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Archiviazione impostazioni"</string>
+    <string name="app_label" msgid="4567566098528588863">"Archiviazione impostazioni"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-nl/defaults.xml b/packages/SettingsProvider/res/values-nl/defaults.xml
deleted file mode 100644
index 625235a..0000000
--- a/packages/SettingsProvider/res/values-nl/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"mobiel,bluetooth,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-nl/strings.xml b/packages/SettingsProvider/res/values-nl/strings.xml
index b37b535..7a0e416 100644
--- a/packages/SettingsProvider/res/values-nl/strings.xml
+++ b/packages/SettingsProvider/res/values-nl/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Opslagruimte voor instellingen"</string>
+    <string name="app_label" msgid="4567566098528588863">"Opslagruimte voor instellingen"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pl/defaults.xml b/packages/SettingsProvider/res/values-pl/defaults.xml
deleted file mode 100644
index b60832e..0000000
--- a/packages/SettingsProvider/res/values-pl/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"komórka,bluetooth,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-pl/strings.xml b/packages/SettingsProvider/res/values-pl/strings.xml
index 4ab1e91..ccff82e3 100644
--- a/packages/SettingsProvider/res/values-pl/strings.xml
+++ b/packages/SettingsProvider/res/values-pl/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"Pamięć ustawień"</string>
+    <string name="app_label" msgid="4567566098528588863">"Pamięć ustawień"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml b/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
deleted file mode 100644
index fdbba88..0000000
--- a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="def_airplane_mode_radios">"手機,藍牙,wifi"</string>
-    <string name="def_location_providers_allowed">"gps"</string>
-    <!-- no translation found for def_backup_transport (6764822064303377157) -->
-    <skip />
-</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/strings.xml b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
index b24144a..0700a76 100644
--- a/packages/SettingsProvider/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label">"設定儲存空間"</string>
+    <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index af02741..c33bdd7 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -21,7 +21,7 @@
     <integer name="def_screen_off_timeout">60000</integer>
     <bool name="def_airplane_mode_on">false</bool>
     <!-- Comma-separated list of bluetooth, wifi, and cell. -->
-    <string name="def_airplane_mode_radios">cell,bluetooth,wifi</string>
+    <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
     <bool name="def_auto_time">true</bool>
     <bool name="def_accelerometer_rotation">true</bool>
     <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
@@ -35,7 +35,7 @@
          Network location is off by default because it requires
          user opt-in via Setup Wizard or Settings.  
     -->
-    <string name="def_location_providers_allowed">gps</string>
+    <string name="def_location_providers_allowed" translatable="false">gps</string>
     <bool name="assisted_gps_enabled">true</bool>
     <!--  0 == mobile, 1 == wifi. -->
     <integer name="def_network_preference">1</integer>
@@ -44,5 +44,5 @@
     <bool name="def_networks_available_notification_on">true</bool>
     
     <bool name="def_backup_enabled">false</bool>
-    <string name="def_backup_transport"></string>
+    <string name="def_backup_transport" translatable="false"></string>
 </resources>
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index d6cd4ef..134fb6f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -60,7 +60,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Debug;
 import android.os.HandlerThread;
 import android.os.Parcel;
 import android.os.RemoteException;
@@ -1829,6 +1828,11 @@
             ps = mSettings.peekPackageLP(pkg.packageName);
             updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
         }
+        // Verify certificates first
+        if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
+            Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
+            return null;
+        }
         if (updatedPkg != null) {
             // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
             parseFlags |= PackageParser.PARSE_IS_SYSTEM;
@@ -1846,16 +1850,19 @@
                         return null;
                     } else {
                         // Delete the older apk pointed to by ps
+                        // At this point, its safely assumed that package installation for
+                        // apps in system partition will go through. If not there won't be a working
+                        // version of the app
+                        synchronized (mPackages) {
+                            // Just remove the loaded entries from package lists.
+                            mPackages.remove(ps.name);
+                        }
                         deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
                         mSettings.enableSystemPackageLP(ps.name);
                     }
                 }
             }
         }
-        if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
-            Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
-            return null;
-        }
         // The apk is forward locked (not public) if its code and resources
         // are kept in different files.
         if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
@@ -2135,7 +2142,7 @@
                 pkg.applicationInfo.packageName,
                 pkg.applicationInfo.processName,
                 pkg.applicationInfo.uid);
-        pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString;
+        pkg.applicationInfo.publicSourceDir = destResourceFile.toString();
 
         File dataPath;
         if (mPlatformPackage == pkg) {
@@ -2262,15 +2269,26 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
         }
 
+        // We don't expect installation to fail beyond this point,
         if ((scanMode&SCAN_MONITOR) != 0) {
             pkg.mPath = destCodeFile.getAbsolutePath();
             mAppDirs.put(pkg.mPath, pkg);
         }
 
+        // Request the ActivityManager to kill the process(only for existing packages)
+        // so that we do not end up in a confused state while the user is still using the older
+        // version of the application while the new one gets installed.
+        IActivityManager am = ActivityManagerNative.getDefault();
+        if ((am != null) && ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0)) {
+            try {
+                am.killApplicationWithUid(pkg.applicationInfo.packageName,
+                        pkg.applicationInfo.uid);
+            } catch (RemoteException e) {
+            }
+        }
         synchronized (mPackages) {
-            // We don't expect installation to fail beyond this point
             // Add the new setting to mSettings
-            mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
+            mSettings.insertPackageSettingLP(pkgSetting, pkg, destCodeFile, destResourceFile);
             // Add the new setting to mPackages
             mPackages.put(pkg.applicationInfo.packageName, pkg);
             int N = pkg.providers.size();
@@ -2958,7 +2976,8 @@
         }
         
         if ((addedPermission || replace) && !ps.permissionsFixed &&
-                (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) ||
+                ((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)){
             // This is the first that we have heard about this package, so the
             // permissions we have now selected are fixed until explicitly
             // changed.
@@ -4159,7 +4178,9 @@
     private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo, 
             int flags) {
         String packageName = p.packageName;
-        outInfo.removedPackage = packageName;
+        if (outInfo != null) {
+            outInfo.removedPackage = packageName;
+        }
         removePackageLI(p, true);
         // Retrieve object to delete permissions for shared user later on
         PackageSetting deletedPs;
@@ -4181,7 +4202,9 @@
                 dataDir.delete();
             }
             synchronized (mPackages) {
-                outInfo.removedUid = mSettings.removePackageLP(packageName);                
+                if (outInfo != null) {
+                    outInfo.removedUid = mSettings.removePackageLP(packageName);
+                }
             }
         }
         synchronized (mPackages) {
@@ -4256,7 +4279,7 @@
         }
         return true;
     }
-    
+
     private void deletePackageResourcesLI(String packageName,
             String sourceDir, String publicSourceDir) {
         File sourceFile = new File(sourceDir);
@@ -4286,7 +4309,9 @@
             Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
             return false;
         }
-        outInfo.uid = applicationInfo.uid;
+        if (outInfo != null) {
+            outInfo.uid = applicationInfo.uid;
+        }
 
         // Delete package data from internal structures and also remove data if flag is set
         removePackageDataLI(p, outInfo, flags);
@@ -5463,7 +5488,7 @@
         String resourcePathString;
         private long timeStamp;
         private String timeStampString = "0";
-        final int versionCode;
+        int versionCode;
 
         PackageSignatures signatures = new PackageSignatures();
 
@@ -5701,10 +5726,6 @@
             final String name = pkg.packageName;
             PackageSetting p = getPackageLP(name, sharedUser, codePath,
                     resourcePath, pkg.mVersionCode, pkgFlags, create, add);
-
-            if (p != null) {
-                p.pkg = pkg;
-            }
             return p;
         }
         
@@ -5852,22 +5873,18 @@
             if (p != null) {
                 if (!p.codePath.equals(codePath)) {
                     // Check to see if its a disabled system app
-                    PackageSetting ps = mDisabledSysPackages.get(name);
-                    if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+                    if((p != null) && ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                         // This is an updated system app with versions in both system
                         // and data partition. Just let the most recent version
                         // take precedence.
-                        return p;
+                        Log.w(TAG, "Trying to update system app code path from " +
+                                p.codePathString + " to " + codePath.toString());
                     } else {
                         // Let the app continue with previous uid if code path changes.
                         reportSettingsProblem(Log.WARN,
                                 "Package " + name + " codePath changed from " + p.codePath
                                 + " to " + codePath + "; Retaining data and using new code from " +
                                 codePath);
-                        p.codePath = codePath;
-                        p.resourcePath = resourcePath;
-                        p.codePathString = codePath.toString();
-                        p.resourcePathString = resourcePath.toString();
                     }
                 } else if (p.sharedUser != sharedUser) {
                     reportSettingsProblem(Log.WARN,
@@ -5891,8 +5908,29 @@
                 if (sharedUser != null) {
                     p.userId = sharedUser.userId;
                 } else if (MULTIPLE_APPLICATION_UIDS) {
-                    // Assign new user id
-                    p.userId = newUserIdLP(p);
+                    // Clone the setting here for disabled system packages
+                    PackageSetting dis = mDisabledSysPackages.get(name);
+                    if (dis != null) {
+                        // For disabled packages a new setting is created
+                        // from the existing user id. This still has to be
+                        // added to list of user id's
+                        // Copy signatures from previous setting
+                        if (dis.signatures.mSignatures != null) {
+                            p.signatures.mSignatures = dis.signatures.mSignatures.clone();
+                        }
+                        p.userId = dis.userId;
+                        // Clone permissions
+                        p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
+                        p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
+                        // Clone component info
+                        p.disabledComponents = new HashSet<String>(dis.disabledComponents);
+                        p.enabledComponents = new HashSet<String>(dis.enabledComponents);
+                        // Add new setting to list of user ids
+                        addUserIdLP(p.userId, p, name);
+                    } else {
+                        // Assign new user id
+                        p.userId = newUserIdLP(p);
+                    }
                 } else {
                     p.userId = FIRST_APPLICATION_UID;
                 }
@@ -5904,15 +5942,39 @@
                 if (add) {
                     // Finish adding new package by adding it and updating shared 
                     // user preferences
-                    insertPackageSettingLP(p, name, sharedUser);
+                    addPackageSettingLP(p, name, sharedUser);
                 }
             }
             return p;
         }
-        
+
+        private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg,
+                File codePath, File resourcePath) {
+            p.pkg = pkg;
+            // Update code path if needed
+            if (!codePath.toString().equalsIgnoreCase(p.codePathString)) {
+                Log.w(TAG, "Code path for pkg : " + p.pkg.packageName +
+                        " changing form " + p.codePathString + " to " + codePath);
+                p.codePath = codePath;
+                p.codePathString = codePath.toString();
+            }
+            //Update resource path if needed
+            if (!resourcePath.toString().equalsIgnoreCase(p.resourcePathString)) {
+                Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
+                        " changing form " + p.resourcePathString + " to " + resourcePath);
+                p.resourcePath = resourcePath;
+                p.resourcePathString = resourcePath.toString();
+            }
+            // Update version code if needed
+             if (pkg.mVersionCode != p.versionCode) {
+                p.versionCode = pkg.mVersionCode;
+            }
+            addPackageSettingLP(p, pkg.packageName, p.sharedUser);
+        }
+
         // Utility method that adds a PackageSetting to mPackages and
         // completes updating the shared user attributes
-        private void insertPackageSettingLP(PackageSetting p, String name,
+        private void addPackageSettingLP(PackageSetting p, String name,
                 SharedUserSetting sharedUser) {
             mPackages.put(name, p);
             if (sharedUser != null) {
@@ -6005,7 +6067,7 @@
                 }
                 if (mUserIds.get(index) != null) {
                     reportSettingsProblem(Log.ERROR,
-                            "Adding duplicate shared id: " + uid
+                            "Adding duplicate user id: " + uid
                             + " name=" + name);
                     return false;
                 }
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 79d78ad1..a3c3436 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -29,6 +29,10 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
@@ -58,7 +62,8 @@
 import java.util.Observable;
 import java.util.Observer;
 
-class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
+class PowerManagerService extends IPowerManager.Stub
+        implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
 
     private static final String TAG = "PowerManagerService";
     static final String PARTIAL_NAME = "PowerManagerService";
@@ -72,7 +77,8 @@
     private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
                                         | PowerManager.SCREEN_DIM_WAKE_LOCK
                                         | PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                                        | PowerManager.FULL_WAKE_LOCK;
+                                        | PowerManager.FULL_WAKE_LOCK
+                                        | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
 
     //                       time since last state:               time since last event:
     // The short keylight delay comes from Gservices; this is the default.
@@ -138,6 +144,7 @@
     private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
     private int[] mBroadcastWhy = new int[3];
     private int mPartialCount = 0;
+    private int mProximityCount = 0;
     private int mPowerState;
     private boolean mOffBecauseOfUser;
     private int mUserState;
@@ -175,6 +182,8 @@
     private IActivityManager mActivityService;
     private IBatteryStats mBatteryStats;
     private BatteryService mBatteryService;
+    private SensorManager mSensorManager;
+    private Sensor mProximitySensor;
     private boolean mDimScreen = true;
     private long mNextTimeout;
     private volatile int mPokey = 0;
@@ -536,6 +545,7 @@
                     wl.minState = SCREEN_DIM;
                     break;
                 case PowerManager.PARTIAL_WAKE_LOCK:
+                case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                     break;
                 default:
                     // just log and bail.  we're in the server, so don't
@@ -583,6 +593,11 @@
                 }
             }
             Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
+        } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+            mProximityCount++;
+            if (mProximityCount == 1) {
+                enableProximityLockLocked();
+            }
         }
         if (newlock) {
             acquireUid = wl.uid;
@@ -639,6 +654,11 @@
                 if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
                 Power.releaseWakeLock(PARTIAL_NAME);
             }
+        } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+            mProximityCount--;
+            if (mProximityCount == 0) {
+                disableProximityLockLocked();
+            }
         }
         // Unlink the lock from the binder.
         wl.binder.unlinkToDeath(wl, 0);
@@ -1996,4 +2016,47 @@
     public void monitor() {
         synchronized (mLocks) { }
     }
+
+    public int getSupportedWakeLockFlags() {
+        int result = PowerManager.PARTIAL_WAKE_LOCK
+                   | PowerManager.FULL_WAKE_LOCK
+                   | PowerManager.SCREEN_DIM_WAKE_LOCK;
+
+        // call getSensorManager() to make sure mProximitySensor is initialized
+        getSensorManager();
+        if (mProximitySensor != null) {
+            result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+        }
+
+        return result;
+    }
+
+    private SensorManager getSensorManager() {
+        if (mSensorManager == null) {
+            mSensorManager = new SensorManager(mHandlerThread.getLooper());
+            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+        }
+        return mSensorManager;
+    }
+
+    private void enableProximityLockLocked() {
+        mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+    }
+
+    private void disableProximityLockLocked() {
+        mSensorManager.unregisterListener(this);
+    }
+
+    public void onSensorChanged(SensorEvent event) {
+        long milliseconds = event.timestamp / 1000000;
+        if (event.values[0] == 0.0) {
+            goToSleep(milliseconds);
+        } else {
+            userActivity(milliseconds, false);
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        // ignore
+    }
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8a4b8f9..7bd2532 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4742,7 +4742,30 @@
             Binder.restoreCallingIdentity(callingId);
         }
     }
-    
+
+    /*
+     * The pkg name and uid have to be specified.
+     * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
+     */
+    public void killApplicationWithUid(String pkg, int uid) {
+        if (pkg == null) {
+            return;
+        }
+        // Make sure the uid is valid.
+        if (uid < 0) {
+            Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
+            return;
+        }
+        int callerUid = Binder.getCallingUid();
+        // Only the system server can kill an application
+        if (callerUid == Process.SYSTEM_UID) {
+            uninstallPackageLocked(pkg, uid, false);
+        } else {
+            throw new SecurityException(callerUid + " cannot kill pkg: " +
+                    pkg);
+        }
+    }
+
     private void restartPackageLocked(final String packageName, int uid) {
         uninstallPackageLocked(packageName, uid, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index b83a44d6..9fb1e61 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -110,6 +110,7 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
     public File getSharedPrefsFile(String name) {
         throw new UnsupportedOperationException();
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
 
 package com.android.dumprendertree;
 
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.os.Bundle;
@@ -42,7 +45,7 @@
     private BufferedOutputStream mBufferedOutputFailedStream;
     private BufferedOutputStream mBufferedOutputNoresultStream;
     private BufferedOutputStream mBufferedOutputTimedoutStream;
-    
+
     public void passed(String layout_file) {
         try {
             mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@
             e.printStackTrace();
         }
     }
-    
+
     public void failed(String layout_file) {
         try {
             mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@
             e.printStackTrace();
         }
     }
-    
+
     public void noresult(String layout_file) {
         try {
             mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@
             e.printStackTrace();
         }
     }
-    
+
     public void timedout(String url) {
         try {
             mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@
             e.printStackTrace();
         }
     }
-    
+
     public MyTestRecorder(boolean resume) {
         try {
             File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
             File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
             File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
             File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-          
+
             mBufferedOutputPassedStream =
                 new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
             mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@
             e.printStackTrace();
         }
     }
-    
+
     public void close() {
         try {
             mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@
 
     private static final String LOGTAG = "LayoutTests";
     static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-    
+
     static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
     static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
     static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@
     static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
     static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
 
+    static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+    static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+    static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+    static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+    static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+    private ForwardServer fs8000, fs8080, fs8443;
+
     private MyTestRecorder mResultRecorder;
     private Vector<String> mTestList;
     private boolean mRebaselineResults;
     private String mTestPathPrefix;
     private boolean mFinished;
-    
+
     public LayoutTestsAutoTest() {
       super("com.android.dumprendertree", TestShellActivity.class);
+
+      int addr = -1;
+      try {
+          addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+      } catch (IOException ioe) {
+          Log.e(LOGTAG, "failed to resolve server address.", ioe);
+      }
+      if(addr != -1) {
+          fs8000 = new ForwardServer(8000, addr, 8000);
+          fs8080 = new ForwardServer(8080, addr, 8080);
+          fs8443 = new ForwardServer(8443, addr, 8443);
+      }
     }
 
     // This function writes the result of the layout test to
@@ -157,7 +181,7 @@
       bundle.putBoolean(file, result);
       inst.sendStatus(0, bundle);
     }
-    
+
     private void getTestList() {
         // Read test list.
         try {
@@ -174,7 +198,7 @@
             Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
         }
     }
-  
+
     private void resumeTestList() {
         // read out the test name it stoped last time.
         try {
@@ -189,7 +213,7 @@
             Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
         }
     }
-  
+
     private void clearTestStatus() {
         // Delete TEST_STATUS_FILE
         try {
@@ -208,13 +232,13 @@
         // Write actual results to result directory.
         return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
     }
-    
+
     private String getExpectedResultFile(String test) {
         int pos = test.lastIndexOf('.');
         if(pos == -1)
             return null;
         String shortName = test.substring(0, pos);
-        return shortName + "-expected.txt";          
+        return shortName + "-expected.txt";
     }
 
     private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@
     // Wrap up
     private void failedCase(String file) {
         Log.w("Layout test: ", file + " failed");
-        mResultRecorder.failed(file);    
+        mResultRecorder.failed(file);
     }
 
     private void passedCase(String file) {
@@ -236,7 +260,7 @@
         Log.v("Layout test:", file + " no expected result");
         mResultRecorder.noresult(file);
     }
-     
+
     private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
         Log.v(LOGTAG, "  Processing result: " + testFile);
 
@@ -257,13 +281,13 @@
                         break;
                     }
                 }
-                
+
                 if (passing) {
                     passedCase(testFile);
                 } else {
                     failedCase(testFile);
                 }
-                
+
                 fe.close();
                 fr.close();
             } catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@
             noresultCase(testFile);
         }
     }
-    
+
     private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
         activity.setCallback(new TestShellCallback() {
             public void finished() {
@@ -287,7 +311,7 @@
                     LayoutTestsAutoTest.this.notifyAll();
                 }
             }
-            
+
             public void timedOut(String url) {
             }
         });
@@ -306,16 +330,16 @@
 
             resultFile = getAndroidExpectedResultFile(expectedResultFile);
         }
-        
+
         mFinished = false;
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(activity, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+        intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
         intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
         intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
         activity.startActivity(intent);
-      
+
         // Wait until done.
         synchronized (this) {
             while(!mFinished){
@@ -324,18 +348,18 @@
                 } catch (InterruptedException e) { }
             }
         }
-        
+
         if (!mRebaselineResults) {
             String expectedResultFile = getExpectedResultFile(test);
             File f = new File(expectedResultFile);
             if (!f.exists()) {
                 expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
             }
-            
+
             processResult(test, resultFile, expectedResultFile);
         }
-    } 
-    
+    }
+
     // Invokes running of layout tests
     // and waits till it has finished running.
     public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@
         }
 
         this.mTestList = new Vector<String>();
-      
+
         // Read settings
         try {
             this.mTestPathPrefix =
                 (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
-        } catch (IOException e) {  
+        } catch (IOException e) {
             Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
             return;
         }
-        
+
         this.mRebaselineResults = runner.mRebaseline;
-        
+
         int timeout = runner.mTimeoutInMillis;
         if (timeout <= 0) {
             timeout = DEFAULT_TIMEOUT_IN_MILLIS;
         }
-          
+
         this.mResultRecorder = new MyTestRecorder(resume);
-          
+
         if (!resume)
             clearTestStatus();
-          
+
         getTestList();
         if (resume)
             resumeTestList();
@@ -377,6 +401,15 @@
         TestShellActivity activity = (TestShellActivity) getActivity();
 
         // Run tests.
+        int addr = -1;
+        try{
+            addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+        } catch (IOException ioe) {
+            Log.w(LOGTAG, "error while resolving test host name", ioe);
+        }
+        if(addr == -1) {
+            Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+        }
         for (int i = 0; i < mTestList.size(); i++) {
             String s = mTestList.elementAt(i);
             FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@
         }
 
         FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-        
+        if(fs8000 != null)
+            fs8000.stop();
+        if(fs8080 != null)
+            fs8080.stop();
+        if(fs8443 != null)
+            fs8443.stop();
+
         activity.finish();
     }
 
+    private void startForwardServerIfNeeded() {
+        try {
+            if(fs8000 != null)
+                fs8000.start();
+            if(fs8080 != null)
+                fs8080.start();
+            if(fs8443 != null)
+                fs8443.start();
+        } catch (IOException ioe) {
+            Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+        }
+    }
+
+    private String getTestUrl(String path) {
+        String url = null;
+        if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+            url = "file://" + path;
+        } else {
+            startForwardServerIfNeeded();
+            if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+                // still cut the URL after "http/tests/"
+                url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+            } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+                    && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+                    && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+                url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+            } else {
+                url = "file://" + path;
+            }
+        }
+        return url;
+    }
 
     private String getTestPath() {
         LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@
             Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
         }
         Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-        
+
         return test_path;
     }
-    
+
     public void generateTestList() {
         try {
             File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@
         } catch (Exception e) {
             e.printStackTrace();
         }
-        
+
         executeLayoutTests(false);
     }
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 48c1e5d..4483a8e 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -531,6 +531,12 @@
         }
 
         @Override
+        public boolean onJsTimeout() {
+            Log.v(LOGTAG, "JavaScript timeout");
+            return false;
+        }
+
+        @Override
         public void onExceededDatabaseQuota(String url_str,
                 String databaseIdentifier, long currentQuota,
                 WebStorage.QuotaUpdater callback) {
@@ -614,6 +620,9 @@
         }
 
         WebSettings settings = webview.getSettings();
+        settings.setAppCacheEnabled(true);
+        settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+        settings.setAppCacheMaxSize(Long.MAX_VALUE);
         settings.setJavaScriptEnabled(true);
         settings.setJavaScriptCanOpenWindowsAutomatically(true);
         settings.setSupportMultipleWindows(true);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+    private static final String ADB_OK = "OKAY";
+    private static final int ADB_PORT = 5037;
+    private static final String ADB_HOST = "127.0.0.1";
+    private static final int ADB_RESPONSE_SIZE = 4;
+
+    private static final String LOGTAG = "AdbUtils";
+
+    /**
+     *
+     * Convert integer format IP into xxx.xxx.xxx.xxx format
+     *
+     * @param host IP address in integer format
+     * @return human readable format
+     */
+    public static String convert(int host) {
+        return ((host >> 24) & 0xFF) + "."
+        + ((host >> 16) & 0xFF) + "."
+        + ((host >> 8) & 0xFF) + "."
+        + (host & 0xFF);
+    }
+
+    /**
+     *
+     * Resolve DNS name into IP address
+     *
+     * @param host DNS name
+     * @return IP address in integer format
+     * @throws IOException
+     */
+    public static int resolve(String host)  throws IOException {
+        Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+        DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+        OutputStream os = localSocket.getOutputStream();
+        int count_read = 0;
+        byte[] buf = new byte[128];
+
+        if (localSocket == null || dis == null || os == null)
+            return -1;
+        String cmd = "dns:" + host;
+
+        if(!sendAdbCmd(dis, os, cmd))
+            return -1;
+
+        count_read = dis.readInt();
+        localSocket.close();
+        return count_read;
+    }
+
+    /**
+     *
+     * Send an ADB command using existing socket connection
+     *
+     * the streams provided must be from a socket connected to adbd already
+     *
+     * @param is input stream of the socket connection
+     * @param os output stream of the socket
+     * @param cmd the adb command to send
+     * @return if adb gave a success response
+     * @throws IOException
+     */
+    public static boolean sendAdbCmd(InputStream is, OutputStream os,
+            String cmd) throws IOException {
+        byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+        cmd = String.format("%04X", cmd.length()) + cmd;
+        os.write(cmd.getBytes());
+        int read = is.read(buf);
+        if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+            Log.w(LOGTAG, "adb cmd faild.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     *
+     * Get a tcp socket connection to specified IP address and port proxied by adb
+     *
+     * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+     * read from as if it is directly connected to the target
+     *
+     * @param remoteAddress IP address of the host to connect to
+     * @param remotePort port of the host to connect to
+     * @return a valid Socket instance if successful, null otherwise
+     */
+    public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+        try {
+            Socket socket = new Socket(ADB_HOST, ADB_PORT);
+            String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+            if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+                socket.close();
+                return null;
+            }
+            return socket;
+        } catch (IOException ioe) {
+            Log.w(LOGTAG, "error creating adb socket", ioe);
+            return null;
+        }
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+    private static final String LOGTAG = "ForwardServer";
+
+    private int remotePort;
+    private int remoteAddress;
+    private int localPort;
+    private ServerSocket serverSocket;
+    private boolean started;
+
+    private Set<Forwarder> forwarders;
+
+    public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+        this.localPort = localPort;
+        this.remoteAddress = remoteAddress;
+        this.remotePort = remotePort;
+        started = false;
+        forwarders = new HashSet<Forwarder>();
+    }
+
+    public synchronized void start() throws IOException {
+        if(!started) {
+            serverSocket = new ServerSocket(localPort);
+            Thread serverThread = new Thread(new ServerRunner(serverSocket));
+            serverThread.setName(LOGTAG);
+            serverThread.start();
+            started = true;
+        }
+    }
+
+    public synchronized void stop() {
+        if(started) {
+            synchronized (forwarders) {
+                for(Forwarder forwarder : forwarders)
+                    forwarder.stop();
+                forwarders.clear();
+            }
+            try {
+                serverSocket.close();
+            } catch (IOException ioe) {
+                Log.v(LOGTAG, "exception while closing", ioe);
+            } finally {
+                started = false;
+            }
+        }
+    }
+
+    public synchronized boolean isRunning() {
+        return started;
+    }
+
+    private class ServerRunner implements Runnable {
+
+        private ServerSocket socket;
+
+        public ServerRunner(ServerSocket socket) {
+            this.socket = socket;
+        }
+
+        public void run() {
+            try {
+                while (true) {
+                    Socket localSocket = socket.accept();
+                    Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+                    if(remoteSocket == null) {
+                        try {
+                            localSocket.close();
+                        } catch (IOException ioe) {
+                            Log.w(LOGTAG, "error while closing socket", ioe);
+                        } finally {
+                            Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+                        }
+                    } else {
+                        Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+                                ForwardServer.this);
+                        forwarder.start();
+                    }
+                }
+            } catch (IOException ioe) {
+                return;
+            }
+        }
+    }
+
+    public void register(Forwarder forwarder) {
+        synchronized (forwarders) {
+            if(!forwarders.contains(forwarder)) {
+                forwarders.add(forwarder);
+            }
+        }
+    }
+
+    public void unregister(Forwarder recyclable) {
+        synchronized (forwarders) {
+            if(forwarders.contains(recyclable)) {
+                recyclable.stop();
+                forwarders.remove(recyclable);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+    private ForwardServer server;
+    private Socket from, to;
+
+    private static final String LOGTAG = "Forwarder";
+
+    public Forwarder (Socket from, Socket to, ForwardServer server) {
+        this.server = server;
+        this.from = from;
+        this.to = to;
+        server.register(this);
+    }
+
+    public void start() {
+        Thread outgoing = new Thread(new SocketPipe(from, to));
+        Thread incoming = new Thread(new SocketPipe(to, from));
+        outgoing.setName(LOGTAG);
+        incoming.setName(LOGTAG);
+        outgoing.start();
+        incoming.start();
+    }
+
+    public void stop() {
+        shutdown(from);
+        shutdown(to);
+    }
+
+    private void shutdown(Socket socket) {
+        try {
+            socket.shutdownInput();
+        } catch (IOException e) {
+            Log.v(LOGTAG, "Socket#shutdownInput", e);
+        }
+        try {
+            socket.shutdownOutput();
+        } catch (IOException e) {
+            Log.v(LOGTAG, "Socket#shutdownOutput", e);
+        }
+        try {
+            socket.close();
+        } catch (IOException e) {
+            Log.v(LOGTAG, "Socket#close", e);
+        }
+    }
+
+    private class SocketPipe implements Runnable {
+
+        private Socket in, out;
+
+        public SocketPipe(Socket in, Socket out) {
+            this.in = in;
+            this.out = out;
+        }
+
+        public void run() {
+            try {
+                int length;
+                InputStream is = in.getInputStream();
+                OutputStream os = out.getOutputStream();
+                byte[] buffer = new byte[4096];
+                while ((length = is.read(buffer)) > 0) {
+                    os.write(buffer, 0, length);
+                }
+            } catch (IOException ioe) {
+            } finally {
+                server.unregister(Forwarder.this);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SocketPipe{" + in + "=>" + out  + "}";
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 12abce5..083cda3 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1467,6 +1467,7 @@
     public synchronized boolean restart() {
         if (mRunState == RUN_STATE_STOPPED) {
             mRunState = RUN_STATE_STARTING;
+            resetInterface(true);
             return WifiNative.startDriverCommand();
         } else if (mRunState == RUN_STATE_STOPPING) {
             mRunState = RUN_STATE_STARTING;