Merge "Fix bug 4064086 Use a death handler on audio focus changes from mode" into honeycomb-mr1
diff --git a/api/current.xml b/api/current.xml
index 557590a..cbccf93 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -95457,6 +95457,32 @@
  visibility="public"
 >
 </method>
+<method name="hasPermission"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+</method>
+<method name="hasPermission"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+</method>
 <method name="isFunctionEnabled"
  return="boolean"
  abstract="false"
@@ -95509,6 +95535,36 @@
 <parameter name="device" type="android.hardware.usb.UsbDevice">
 </parameter>
 </method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
 <field name="ACTION_USB_ACCESSORY_ATTACHED"
  type="java.lang.String"
  transient="false"
@@ -95586,6 +95642,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_PERMISSION_GRANTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;permission&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="USB_CONFIGURATION"
  type="java.lang.String"
  transient="false"
@@ -207176,21 +207243,6 @@
  visibility="public"
 >
 </method>
-<method name="entryEvicted"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="protected"
->
-<parameter name="key" type="K">
-</parameter>
-<parameter name="value" type="V">
-</parameter>
-</method>
 <method name="entryRemoved"
  return="void"
  abstract="false"
@@ -244871,6 +244923,25 @@
 <parameter name="realm" type="java.lang.String">
 </parameter>
 </method>
+<method name="onReceivedLoginRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="realm" type="java.lang.String">
+</parameter>
+<parameter name="account" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.String">
+</parameter>
+</method>
 <method name="onReceivedSslError"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 539e946..cc1f81c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -401,10 +401,10 @@
                     return new UiModeManager();
                 }});
 
-        registerService(USB_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
+        registerService(USB_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(USB_SERVICE);
-                    return new UsbManager(IUsbManager.Stub.asInterface(b));
+                    return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
                 }});
 
         registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 440cb54..efe2633 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1150,8 +1150,12 @@
      * fail (most commonly returning {@link #ENCRYPTION_STATUS_ACTIVE}).
      *
      * <p>This policy controls encryption of the secure (application data) storage area.  Data
-     * written to other areas (e.g. the directory returned by
-     * {@link android.os.Environment#getExternalStorageDirectory()} may or may not be encrypted.
+     * written to other storage areas may or may not be encrypted, and this policy does not require
+     * or control the encryption of any other storage areas.
+     * There is one exception:  If {@link android.os.Environment#isExternalStorageEmulated()} is
+     * {@code true}, then the directory returned by
+     * {@link android.os.Environment#getExternalStorageDirectory()} must be written to disk
+     * within the encrypted storage area.
      *
      * <p>Important Note:  On some devices, it is possible to encrypt storage without requiring
      * the user to create a device PIN or Password.  In this case, the storage is encrypted, but
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index be65bdb..c79a458 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.usb;
 
+import android.app.PendingIntent;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.os.Bundle;
@@ -50,6 +51,25 @@
      */
     void setAccessoryPackage(in UsbAccessory accessory, String packageName);
 
+    /* Returns true if the caller has permission to access the device. */
+    boolean hasDevicePermission(in UsbDevice device);
+
+    /* Returns true if the caller has permission to access the accessory. */
+    boolean hasAccessoryPermission(in UsbAccessory accessory);
+
+    /* Requests permission for the given package to access the device.
+     * Will display a system dialog to query the user if permission
+     * had not already been given.
+     */
+    void requestDevicePermission(in UsbDevice device, String packageName, in PendingIntent pi);
+
+    /* Requests permission for the given package to access the accessory.
+     * Will display a system dialog to query the user if permission
+     * had not already been given. Result is returned via pi.
+     */
+    void requestAccessoryPermission(in UsbAccessory accessory, String packageName,
+            in PendingIntent pi);
+
     /* Grants permission for the given UID to access the device */
     void grantDevicePermission(in UsbDevice device, int uid);
 
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 6683179..9f1b8ea 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,6 +17,8 @@
 
 package android.hardware.usb;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -176,12 +178,24 @@
      */
     public static final String EXTRA_ACCESSORY = "accessory";
 
-    private IUsbManager mService;
+    /**
+     * Name of extra added to the {@link android.app.PendingIntent}
+     * passed into
+     * {#requestPermission(android.content.Context, android.hardware.usb.UsbDevice, android.app.PendingIntent)}
+     * or
+     * {#requestPermission(android.content.Context, android.hardware.usb.UsbAccessory, android.app.PendingIntent)}
+     * containing a boolean value indicating whether the user granted permission or not.
+     */
+    public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+    private final Context mContext;
+    private final IUsbManager mService;
 
     /**
      * {@hide}
      */
-    public UsbManager(IUsbManager service) {
+    public UsbManager(Context context, IUsbManager service) {
+        mContext = context;
         mService = service;
     }
 
@@ -245,7 +259,7 @@
                 return new UsbAccessory[] { accessory };
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getAccessoryList" , e);
+            Log.e(TAG, "RemoteException in getAccessoryList", e);
             return null;
         }
     }
@@ -260,11 +274,87 @@
         try {
             return mService.openAccessory(accessory);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openAccessory" , e);
+            Log.e(TAG, "RemoteException in openAccessory", e);
             return null;
         }
     }
 
+    /**
+     * Returns true if the caller has permission to access the device.
+     *
+     * @param device to check permissions for
+     * @return true if caller has permission
+     */
+    public boolean hasPermission(UsbDevice device) {
+        try {
+            return mService.hasDevicePermission(device);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in hasPermission", e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the caller has permission to access the accessory.
+     *
+     * @param accessory to check permissions for
+     * @return true if caller has permission
+     */
+    public boolean hasPermission(UsbAccessory accessory) {
+        try {
+            return mService.hasAccessoryPermission(accessory);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in hasPermission", e);
+            return false;
+        }
+    }
+
+    /**
+     * Requests permission for the given package to access the device.
+     * This may result in a system dialog being displayed to the user
+     * if permission had not already been granted.
+     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+     * The following extras will be added to pi:
+     * <ul>
+     * <li> {@link #EXTRA_DEVICE} containing the device passed into this call
+     * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+     * permission was granted by the user
+     * </ul>
+     *
+     * @param device to request permissions for
+     * @param pi PendingIntent for returning result
+     */
+    public void requestPermission(UsbDevice device, PendingIntent pi) {
+        try {
+            mService.requestDevicePermission(device, mContext.getPackageName(), pi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in requestPermission", e);
+        }
+    }
+
+    /**
+     * Requests permission for the given package to access the accessory.
+     * This may result in a system dialog being displayed to the user
+     * if permission had not already been granted.
+     * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+     * The following extras will be added to pi:
+     * <ul>
+     * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
+     * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+     * permission was granted by the user
+     * </ul>
+     *
+     * @param accessory to request permissions for
+     * @param pi PendingIntent for returning result
+     */
+    public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+        try {
+            mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in requestPermission", e);
+        }
+    }
+
     private static File getFunctionEnableFile(String function) {
         return new File("/sys/class/usb_composite/" + function + "/enable");
     }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ec5030c..e308c2c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -423,9 +423,16 @@
 
     /**
      * Returns whether the device has an external storage device which is
-     * emulated. If true, the device does not have real external storage
-     * and certain system services such as the package manager use this
+     * emulated. If true, the device does not have real external storage, and the directory
+     * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
+     * the internal storage system.
+     *
+     * <p>Certain system services, such as the package manager, use this
      * to determine where to install an application.
+     *
+     * <p>Emulated external storage may also be encrypted - see
+     * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
+     * android.content.ComponentName, boolean)} for additional details.
      */
     public static boolean isExternalStorageEmulated() {
         if (mIsExternalStorageEmulated == null) {
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index a1501e6..834dac3 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -139,8 +139,7 @@
      * Caches {@code value} for {@code key}. The value is moved to the head of
      * the queue.
      *
-     * @return the previous value mapped by {@code key}. Although that entry is
-     *     no longer cached, it has not been passed to {@link #entryEvicted}.
+     * @return the previous value mapped by {@code key}.
      */
     public final V put(K key, V value) {
         if (key == null || value == null) {
@@ -195,15 +194,14 @@
                 evictionCount++;
             }
 
-            entryEvicted(key, value);
+            entryRemoved(true, key, value, null);
         }
     }
 
     /**
      * Removes the entry for {@code key} if it exists.
      *
-     * @return the previous value mapped by {@code key}. Although that entry is
-     *     no longer cached, it has not been passed to {@link #entryEvicted}.
+     * @return the previous value mapped by {@code key}.
      */
     public final V remove(K key) {
         if (key == null) {
@@ -226,16 +224,6 @@
     }
 
     /**
-     * Calls {@link #entryRemoved}.
-     *
-     * @deprecated replaced by entryRemoved
-     */
-    @Deprecated
-    protected void entryEvicted(K key, V value) {
-        entryRemoved(true, key, value, null);
-    }
-
-    /**
      * Called for entries that have been evicted or removed. This method is
      * invoked when a value is evicted to make space, removed by a call to
      * {@link #remove}, or replaced by a call to {@link #put}. The default
@@ -291,7 +279,7 @@
     }
 
     /**
-     * Clear the cache, calling {@link #entryEvicted} on each removed entry.
+     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
      */
     public final void evictAll() {
         trimToSize(-1); // -1 will evict 0-sized elements
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 9a6a274..fa5479b 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -245,11 +245,12 @@
     private static native void nDestroyDisplayList(int displayList);
 
     @Override
-    public boolean drawDisplayList(DisplayList displayList) {
-        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    public boolean drawDisplayList(DisplayList displayList, Rect dirty) {
+        return nDrawDisplayList(mRenderer,
+                ((GLES20DisplayList) displayList).mNativeDisplayList, dirty);
     }
 
-    private static native boolean nDrawDisplayList(int renderer, int displayList);
+    private static native boolean nDrawDisplayList(int renderer, int displayList, Rect dirty);
 
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index e6fecc8..cb1003a 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -53,8 +53,13 @@
      * Draws the specified display list onto this canvas.
      * 
      * @param displayList The display list to replay.
+     * @param dirty The dirty region to redraw in the next pass, matters only
+     *        if this method returns true, can be null.
+     * 
+     * @return True if the content of the display list requires another
+     *         drawing pass (invalidate()), false otherwise
      */
-    abstract boolean drawDisplayList(DisplayList displayList);
+    abstract boolean drawDisplayList(DisplayList displayList, Rect dirty);
 
     /**
      * Draws the specified layer onto this canvas.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b53aa21..0cf7ae6 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -269,7 +269,7 @@
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
 
-        private static Thread sEglThread;        
+        private static Thread sEglThread;
 
         EGLSurface mEglSurface;
         
@@ -284,6 +284,8 @@
         final boolean mTranslucent;
 
         private boolean mDestroyed;
+        
+        private final Rect mRedrawClip = new Rect();
 
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
@@ -606,8 +608,13 @@
 
                         DisplayList displayList = view.getDisplayList();
                         if (displayList != null) {
-                            if (canvas.drawDisplayList(displayList)) {
-                                view.invalidate();
+                            if (canvas.drawDisplayList(displayList, mRedrawClip)) {
+                                if (mRedrawClip.isEmpty() || view.getParent() == null) {
+                                    view.invalidate();
+                                } else {
+                                    view.getParent().invalidateChild(view, mRedrawClip);
+                                }
+                                mRedrawClip.setEmpty();
                             }
                         } else {
                             // Shouldn't reach here
@@ -646,8 +653,8 @@
         private int checkCurrent() {
             // TODO: Don't check the current context when we have one per UI thread
             // TODO: Use a threadlocal flag to know whether the surface has changed
-            if (sEgl.eglGetCurrentContext() != sEglContext ||
-                    sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
+            if (!sEglContext.equals(sEgl.eglGetCurrentContext()) ||
+                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
                     fallback(true);
                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9f1eef9..f9692da 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2585,7 +2585,7 @@
                     }
                 } else {
                     child.mPrivateFlags &= ~DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawDisplayList(displayList);
+                    ((HardwareCanvas) canvas).drawDisplayList(displayList, null);
                 }
             }
         } else if (cache != null) {
@@ -3680,7 +3680,7 @@
                     // flag coming from the child that initiated the invalidate
                     if (view != null) {
                         if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
-                                view.getSolidColor() == 0 && !view.isOpaque()) {
+                                view.getSolidColor() == 0) {
                             opaqueFlag = DIRTY;
                         }
                         if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index ab4bfe1..c7a7374 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1237,11 +1237,17 @@
         }
     }
 
-
     /*package*/ SearchBox getSearchBox() {
         return mSearchBox;
     }
 
+    /**
+     * Called by JNI when processing the X-Auto-Login header.
+     */
+    private void autoLogin(String realm, String account, String args) {
+        mCallbackProxy.onReceivedLoginRequest(realm, account, args);
+    }
+
     //==========================================================================
     // native functions
     //==========================================================================
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index c66d701..23fd12d 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -117,6 +117,7 @@
     private static final int AUTH_CREDENTIALS                    = 137;
     private static final int SET_INSTALLABLE_WEBAPP              = 138;
     private static final int NOTIFY_SEARCHBOX_LISTENERS          = 139;
+    private static final int AUTO_LOGIN                          = 140;
 
     // Message triggered by the client to resume execution
     private static final int NOTIFY                              = 200;
@@ -770,7 +771,7 @@
                             (WebHistoryItem) msg.obj, msg.arg1);
                 }
                 break;
-            case AUTH_CREDENTIALS:
+            case AUTH_CREDENTIALS: {
                 String host = msg.getData().getString("host");
                 String realm = msg.getData().getString("realm");
                 username = msg.getData().getString("username");
@@ -778,6 +779,7 @@
                 mWebView.setHttpAuthUsernamePassword(
                         host, realm, username, password);
                 break;
+            }
             case SET_INSTALLABLE_WEBAPP:
                 if (mWebChromeClient != null) {
                     mWebChromeClient.setInstallableWebApp();
@@ -789,6 +791,17 @@
                 @SuppressWarnings("unchecked")
                 List<String> suggestions = (List<String>) msg.obj;
                 searchBox.handleSuggestions(msg.getData().getString("query"), suggestions);
+                break;
+            case AUTO_LOGIN: {
+                if (mWebViewClient != null) {
+                    String realm = msg.getData().getString("realm");
+                    String account = msg.getData().getString("account");
+                    String args = msg.getData().getString("args");
+                    mWebViewClient.onReceivedLoginRequest(mWebView, realm,
+                            account, args);
+                }
+                break;
+            }
         }
     }
 
@@ -1051,6 +1064,20 @@
         sendMessage(msg);
     }
 
+    void onReceivedLoginRequest(String realm, String account, String args) {
+        // Do an unsynchronized quick check to avoid posting if no callback has
+        // been set.
+        if (mWebViewClient == null) {
+            return;
+        }
+        Message msg = obtainMessage(AUTO_LOGIN);
+        Bundle bundle = msg.getData();
+        bundle.putString("realm", realm);
+        bundle.putString("account", account);
+        bundle.putString("args", args);
+        sendMessage(msg);
+    }
+
     //--------------------------------------------------------------------------
     // DownloadListener functions.
     //--------------------------------------------------------------------------
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 2dac7e9..3cb5e24 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -31,7 +31,7 @@
     public static final boolean CACHE_MANAGER = false;
     public static final boolean CALLBACK_PROXY = false;
     public static final boolean COOKIE_MANAGER = false;
-    public static final boolean COOKIE_SYNC_MANAGER = true;
+    public static final boolean COOKIE_SYNC_MANAGER = false;
     public static final boolean FRAME_LOADER = false;
     public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
     public static final boolean LOAD_LISTENER = false;
@@ -41,7 +41,7 @@
     public static final boolean URL_UTIL = false;
     public static final boolean WEB_BACK_FORWARD_LIST = false;
     public static final boolean WEB_SETTINGS = false;
-    public static final boolean WEB_SYNC_MANAGER = true;
+    public static final boolean WEB_SYNC_MANAGER = false;
     public static final boolean WEB_TEXT_VIEW = false;
     public static final boolean WEB_VIEW = false;
     public static final boolean WEB_VIEW_CORE = false;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f0a3a0f..9b1f157 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -351,7 +351,8 @@
 
     private ZoomManager mZoomManager;
 
-    private Rect mGLRectViewport = new Rect();
+    private final Rect mGLRectViewport = new Rect();
+    private final Rect mViewRectViewport = new Rect();
     private boolean mGLViewportEmpty = false;
 
     /**
@@ -3016,7 +3017,8 @@
     }
 
     /**
-     * Start an ActionMode for finding text in this WebView.
+     * Start an ActionMode for finding text in this WebView.  Only works if this
+     *              WebView is attached to the view system.
      * @param text If non-null, will be the initial text to search for.
      *             Otherwise, the last String searched for in this WebView will
      *             be used to start.
@@ -3026,7 +3028,7 @@
      */
     public boolean showFindDialog(String text, boolean showIme) {
         FindActionModeCallback callback = new FindActionModeCallback(mContext);
-        if (startActionMode(callback) == null) {
+        if (getParent() == null || startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
             return false;
         }
@@ -4034,15 +4036,10 @@
         }
     }
 
-    void setBaseLayer(int layer, Rect invalRect, boolean showVisualIndciator) {
+    void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator) {
         if (mNativeClass == 0)
             return;
-        if (invalRect == null) {
-            Rect rect = new Rect(0, 0, mContentWidth, mContentHeight);
-            nativeSetBaseLayer(layer, rect, showVisualIndciator);
-        } else {
-            nativeSetBaseLayer(layer, invalRect, showVisualIndciator);
-        }
+        nativeSetBaseLayer(layer, invalRegion, showVisualIndicator);
     }
 
     private void onZoomAnimationStart() {
@@ -4152,7 +4149,7 @@
 
         if (canvas.isHardwareAccelerated()) {
             int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
-                    getScale(), extras);
+                    mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras);
             ((HardwareCanvas) canvas).callDrawGLFunction(functor);
         } else {
             DrawFilter df = null;
@@ -5258,6 +5255,7 @@
             // Then need to invert the Y axis, just for GL
             View rootView = getRootView();
             int rootViewHeight = rootView.getHeight();
+            mViewRectViewport.set(mGLRectViewport);
             int savedWebViewBottom = mGLRectViewport.bottom;
             mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
             mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
@@ -5265,7 +5263,8 @@
         } else {
             mGLViewportEmpty = true;
         }
-        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport);
+        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
+                mGLViewportEmpty ? null : mViewRectViewport);
     }
 
     /**
@@ -5567,7 +5566,7 @@
                         ted.mReprocess = mDeferTouchProcess;
                         ted.mNativeLayer = nativeScrollableLayer(
                                 contentX, contentY, ted.mNativeLayerRect, null);
-                        ted.mDontEnqueueResult = true;
+                        ted.mSequence = mTouchEventQueue.nextTouchSequence();
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         if (mDeferTouchProcess) {
                             // still needs to set them for compute deltaX/Y
@@ -5614,7 +5613,7 @@
                     ted.mReprocess = mDeferTouchProcess;
                     ted.mNativeLayer = mScrollingLayer;
                     ted.mNativeLayerRect.set(mScrollingLayerRect);
-                    ted.mDontEnqueueResult = true;
+                    ted.mSequence = mTouchEventQueue.nextTouchSequence();
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     mLastSentTouchTime = eventTime;
                     if (mDeferTouchProcess) {
@@ -5796,7 +5795,7 @@
                     ted.mReprocess = mDeferTouchProcess;
                     ted.mNativeLayer = mScrollingLayer;
                     ted.mNativeLayerRect.set(mScrollingLayerRect);
-                    ted.mDontEnqueueResult = true;
+                    ted.mSequence = mTouchEventQueue.nextTouchSequence();
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                 }
                 mLastTouchUpTime = eventTime;
@@ -5819,7 +5818,7 @@
                             ted.mNativeLayer = nativeScrollableLayer(
                                     contentX, contentY,
                                     ted.mNativeLayerRect, null);
-                            ted.mDontEnqueueResult = true;
+                            ted.mSequence = mTouchEventQueue.nextTouchSequence();
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         } else if (mPreventDefault != PREVENT_DEFAULT_YES){
                             mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -6037,7 +6036,7 @@
             ted.mAction = MotionEvent.ACTION_CANCEL;
             ted.mNativeLayer = nativeScrollableLayer(
                     x, y, ted.mNativeLayerRect, null);
-            ted.mDontEnqueueResult = true;
+            ted.mSequence = mTouchEventQueue.nextTouchSequence();
             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
             mPreventDefault = PREVENT_DEFAULT_IGNORE;
         }
@@ -7521,7 +7520,7 @@
                         ted.mNativeLayer = nativeScrollableLayer(
                                 ted.mPoints[0].x, ted.mPoints[0].y,
                                 ted.mNativeLayerRect, null);
-                        ted.mDontEnqueueResult = true;
+                        ted.mSequence = mTouchEventQueue.nextTouchSequence();
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
                         mTouchMode = TOUCH_DONE_MODE;
@@ -7567,7 +7566,7 @@
                 case NEW_PICTURE_MSG_ID: {
                     // called for new content
                     final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
-                    setBaseLayer(draw.mBaseLayer, draw.mInvalRegion.getBounds(),
+                    setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
                             getSettings().getShowVisualIndicator());
                     final Point viewSize = draw.mViewSize;
                     WebViewCore.ViewState viewState = draw.mViewState;
@@ -7737,9 +7736,12 @@
                         break;
                     }
                     TouchEventData ted = (TouchEventData) msg.obj;
-                    if (!ted.mDontEnqueueResult) {
-                        mTouchEventQueue.enqueueTouchEvent(ted);
-                    }
+
+                    // WebCore is responding to us; remove pending timeout.
+                    // It will be re-posted when needed.
+                    removeMessages(PREVENT_DEFAULT_TIMEOUT);
+
+                    mTouchEventQueue.enqueueTouchEvent(ted);
                     break;
 
                 case REQUEST_KEYBOARD:
@@ -8531,8 +8533,9 @@
             boolean splitIfNeeded);
     private native void     nativeDumpDisplayTree(String urlOrNull);
     private native boolean  nativeEvaluateLayersAnimations();
-    private native int      nativeGetDrawGLFunction(Rect rect, float scale, int extras);
-    private native void     nativeUpdateDrawGLFunction(Rect rect);
+    private native int      nativeGetDrawGLFunction(Rect rect, Rect viewRect,
+            float scale, int extras);
+    private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect);
     private native boolean  nativeDrawGL(Rect rect, float scale, int extras);
     private native void     nativeExtendSelection(int x, int y);
     private native int      nativeFindAll(String findLower, String findUpper,
@@ -8608,7 +8611,7 @@
     private native void     nativeSetFindIsEmpty();
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetHeightCanMeasure(boolean measure);
-    private native void     nativeSetBaseLayer(int layer, Rect invalRect,
+    private native void     nativeSetBaseLayer(int layer, Region invalRegion,
             boolean showVisualIndicator);
     private native void     nativeShowCursorTimed();
     private native void     nativeReplaceBaseContent(int content);
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index db605de..65026a5 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -256,4 +256,18 @@
      */
     public void onScaleChanged(WebView view, float oldScale, float newScale) {
     }
+
+    /**
+     * Notify the host application that a request to automatically log in the
+     * user has been processed.
+     * @param view The WebView requesting the login.
+     * @param realm The account realm used to look up accounts.
+     * @param account An optional account. If not null, the account should be
+     *                checked against accounts on the device. If it is a valid
+     *                account, it should be used to log in the user.
+     * @param args Authenticator specific arguments used to log in the user.
+     */
+    public void onReceivedLoginRequest(WebView view, String realm,
+            String account, String args) {
+    }
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index f367b93..b920a30 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -827,7 +827,6 @@
         Rect mNativeLayerRect = new Rect();
         long mSequence;
         boolean mNativeResult;
-        boolean mDontEnqueueResult;
     }
 
     static class GeolocationPermissionsData {
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index f27ced8..942425af 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -16,6 +16,9 @@
 
 package android.webkit;
 
+import java.util.LinkedList;
+import java.util.Queue;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Canvas;
@@ -23,6 +26,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.ScaleGestureDetector;
 import android.view.View;
@@ -112,6 +116,24 @@
     private float mZoomCenterY;
 
     /*
+     * Similar to mZoomCenterX(Y), these track the focus point of the scale
+     * gesture. The difference is these get updated every time when onScale is
+     * invoked no matter if a zooming really happens.
+     */
+    private float mFocusX;
+    private float mFocusY;
+
+    /*
+     * mFocusMovement keeps track of the total movement that the focus point
+     * has been through. Comparing to the difference of mCurrlen and mPrevLen,
+     * it determines if the gesture is for panning or zooming or both.
+     */
+    private static final int FOCUS_QUEUE_SIZE = 5;
+    private float mFocusMovementSum;
+    private Queue<Float> mFocusMovementQueue;
+
+
+    /*
      * These values represent the point around which the screen should be
      * centered after zooming. In other words it is used to determine the center
      * point of the visible document after the page has finished zooming. This
@@ -196,6 +218,8 @@
          * viewport size is.
          */
         setZoomOverviewWidth(WebView.DEFAULT_VIEWPORT_WIDTH);
+
+        mFocusMovementQueue = new LinkedList<Float>();
     }
 
     /**
@@ -715,10 +739,11 @@
     }
 
     private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
-
         public boolean onScaleBegin(ScaleGestureDetector detector) {
             mInitialZoomOverview = false;
             dismissZoomPicker();
+            mFocusMovementSum = 0;
+            mFocusMovementQueue.clear();
             mWebView.mViewManager.startZoom();
             mWebView.onPinchToZoomAnimationStart();
             return true;
@@ -729,6 +754,29 @@
             float scale = Math.max(
                     computeScaleWithLimits(detector.getScaleFactor() * mActualScale),
                     getZoomOverviewScale());
+
+            float prevFocusX = mFocusX;
+            float prevFocusY = mFocusY;
+            mFocusX = detector.getFocusX();
+            mFocusY = detector.getFocusY();
+            float focusDelta = (prevFocusX == 0 && prevFocusY == 0) ? 0 :
+                    FloatMath.sqrt((mFocusX - prevFocusX) * (mFocusX - prevFocusX)
+                                   + (mFocusY - prevFocusY) * (mFocusY - prevFocusY));
+            mFocusMovementSum += focusDelta;
+            mFocusMovementQueue.add(focusDelta);
+            if (mFocusMovementQueue.size() > FOCUS_QUEUE_SIZE) {
+                mFocusMovementSum -= mFocusMovementQueue.remove();
+            }
+            float deltaSpan = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan());
+
+            // If the user moves the fingers but keeps the same distance between them,
+            // we should do panning only.
+            if (mFocusMovementSum > deltaSpan) {
+                mFocusMovementSum = 0;
+                mFocusMovementQueue.clear();
+                return true;
+            }
+
             if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) {
                 mPinchToZoomAnimating = true;
                 // limit the scale change per step
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d92588cb..17b3bda 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -477,8 +477,7 @@
                 break;
             case MotionEvent.ACTION_POINTER_DOWN: {
                 final int index = ev.getActionIndex();
-                final float x = ev.getX(index);
-                mLastMotionX = x;
+                mLastMotionX = ev.getX(index);
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
@@ -1446,6 +1445,7 @@
         super.setOverScrollMode(mode);
     }
 
+    @SuppressWarnings({"SuspiciousNameCombination"})
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 9002b1d..72b70bc 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1039,7 +1039,7 @@
      *
      * @return true if the popup is translated upwards to fit on screen
      */
-    boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
             int xoff, int yoff) {
 
         anchor.getLocationInWindow(mDrawingLocation);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 2d164fd..6088654 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -83,6 +83,7 @@
     private CursorAdapter mSuggestionsAdapter;
     private View mSearchButton;
     private View mSubmitButton;
+    private View mSearchPlate;
     private View mSubmitArea;
     private ImageView mCloseButton;
     private View mSearchEditFrame;
@@ -190,6 +191,7 @@
         mQueryTextView.setSearchView(this);
 
         mSearchEditFrame = findViewById(R.id.search_edit_frame);
+        mSearchPlate = findViewById(R.id.search_plate);
         mSubmitArea = findViewById(R.id.submit_area);
         mSubmitButton = findViewById(R.id.search_go_btn);
         mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
@@ -258,6 +260,7 @@
         mSearchable = searchable;
         if (mSearchable != null) {
             updateSearchAutoComplete();
+            updateQueryHint();
         }
         // Cache the voice search capability
         mVoiceButtonEnabled = hasVoiceSearch();
@@ -575,19 +578,19 @@
     }
 
     private void updateSubmitButton(boolean hasText) {
-        mSubmitButton.setVisibility(
-                isSubmitAreaEnabled() ? (hasText ? VISIBLE : INVISIBLE) : GONE);
+        int visibility = GONE;
+        if (isSubmitAreaEnabled() && hasFocus() && (hasText || !mVoiceButtonEnabled)) {
+            visibility = VISIBLE;
+        }
+        mSubmitButton.setVisibility(visibility);
     }
 
     private void updateSubmitArea() {
         int visibility = GONE;
-        if (isSubmitAreaEnabled()) {
-            if (mSubmitButton.getVisibility() == VISIBLE
-                    || mVoiceButton.getVisibility() == VISIBLE) {
-                visibility = VISIBLE;
-            } else {
-                visibility = INVISIBLE;
-            }
+        if (isSubmitAreaEnabled()
+                && (mSubmitButton.getVisibility() == VISIBLE
+                        || mVoiceButton.getVisibility() == VISIBLE)) {
+            visibility = VISIBLE;
         }
         mSubmitArea.setVisibility(visibility);
     }
@@ -601,6 +604,11 @@
         mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
     }
 
+    private void updateFocusedState(boolean focused) {
+        mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+        mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+    }
+
     private void setImeVisibility(boolean visible) {
         InputMethodManager imm = (InputMethodManager)
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -851,16 +859,11 @@
      * Update the visibility of the voice button.  There are actually two voice search modes,
      * either of which will activate the button.
      * @param empty whether the search query text field is empty. If it is, then the other
-     * criteria apply to make the voice button visible. Otherwise the voice button will not
-     * be visible - i.e., if the user has typed a query, remove the voice button.
+     * criteria apply to make the voice button visible.
      */
     private void updateVoiceButton(boolean empty) {
-        // If the voice button is to be visible, show it
-        // Else, make it gone if the submit button is enabled, otherwise invisible to
-        // avoid losing the real-estate
-        int visibility = mSubmitButtonEnabled ? GONE : INVISIBLE;
-
-        if (mVoiceButtonEnabled && !isIconified() && empty) {
+        int visibility = GONE;
+        if (mVoiceButtonEnabled && !isIconified() && (empty || !mSubmitButtonEnabled)) {
             visibility = VISIBLE;
             mSubmitButton.setVisibility(GONE);
         }
@@ -958,7 +961,8 @@
     }
 
     void onTextFocusChanged() {
-        updateCloseButton();
+        updateViewsVisibility(isIconified());
+        updateFocusedState(mQueryTextView.hasFocus());
     }
 
     private boolean onItemClicked(int position, int actionKey, String actionMsg) {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index bab469b..21c61bd 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -531,6 +531,8 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        boolean expandClipRegion = false;
+
         canvas.getClipBounds(stackInvalidateRect);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -540,12 +542,22 @@
                     child.getAlpha() == 0f || child.getVisibility() != VISIBLE) {
                 lp.resetInvalidateRect();
             }
-            stackInvalidateRect.union(lp.getInvalidateRect());
+            Rect childInvalidateRect = lp.getInvalidateRect();
+            if (!childInvalidateRect.isEmpty()) {
+                expandClipRegion = true;
+                stackInvalidateRect.union(childInvalidateRect);
+            }
         }
-        canvas.save(Canvas.CLIP_SAVE_FLAG);
-        canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
-        super.dispatchDraw(canvas);
-        canvas.restore();
+
+        // We only expand the clip bounds if necessary.
+        if (expandClipRegion) {
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
+            super.dispatchDraw(canvas);
+            canvas.restore();
+        } else {
+            super.dispatchDraw(canvas);
+        }
     }
 
     private void onLayout() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 09c1ac5..13b9285f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4498,8 +4498,6 @@
         */
 
         canvas.restore();
-
-        updateCursorControllerPositions();
     }
 
     private void updateCursorsPositions() {
@@ -4557,15 +4555,7 @@
      * @hide
      */
     protected void updateCursorControllerPositions() {
-        // No need to create the controllers if they were not already
-        if (mInsertionPointCursorController != null &&
-                mInsertionPointCursorController.isShowing()) {
-            mInsertionPointCursorController.updatePosition();
-        }
-        if (mSelectionModifierCursorController != null &&
-                mSelectionModifierCursorController.isShowing()) {
-            mSelectionModifierCursorController.updatePosition();
-        }
+        // TODO remove
     }
 
     @Override
@@ -7356,14 +7346,9 @@
             }
 
             if (isTextEditable() || mTextIsSelectable) {
-                if (mScrollX != oldScrollX || mScrollY != oldScrollY) {
+                if (mScrollX != oldScrollX || mScrollY != oldScrollY) { // TODO remove
                     // Hide insertion anchor while scrolling. Leave selection.
-                    hideInsertionPointCursorController();
-                    // No need to create the controller, since there is nothing to update.
-                    if (mSelectionModifierCursorController != null &&
-                            mSelectionModifierCursorController.isShowing()) {
-                        mSelectionModifierCursorController.updatePosition();
-                    }
+                    hideInsertionPointCursorController(); // TODO any motion should hide it
                 }
 
                 if (touchIsFinished) {
@@ -7373,7 +7358,6 @@
                         handled |= imm != null && imm.showSoftInput(this, 0);
                     }
 
-
                     boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
                     if (!selectAllGotFocus && hasSelection()) {
                         startSelectionActionMode();
@@ -8653,26 +8637,31 @@
         }
     }
 
-    private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
+    private class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
         private Drawable mDrawable;
-        private final ScrollingPopupWindow mContainer;
-        private int mPositionX;
-        private int mPositionY;
+        private final PopupWindow mContainer;
+        // Position with respect to the parent TextView
+        private int mPositionX, mPositionY;
         private final CursorController mController;
         private boolean mIsDragging;
-        private float mTouchToWindowOffsetX;
-        private float mTouchToWindowOffsetY;
+        // Offset from touch position to mPosition
+        private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
         private float mHotspotX;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
         // Where the touch position should be on the handle to ensure a maximum cursor visibility
         private float mIdealVerticalOffset;
-        private int mLastParentX;
-        private int mLastParentY;
+        // Parent's (TextView) position in window
+        private int mLastParentX, mLastParentY;
         private float mDownPositionX, mDownPositionY;
+        // PopupWindow container absolute position with respect to the enclosing window
         private int mContainerPositionX, mContainerPositionY;
-        private long mTouchTimer;
+        // Visible or not (scrolled off screen), whether or not this handle should be visible
+        private boolean mIsActive = false;
+        // The insertion handle can have an associated PastePopupMenu
         private boolean mIsInsertionHandle = false;
+        // Used to detect taps on the insertion handle, which will affect the PastePopupMenu
+        private long mTouchTimer;
         private PastePopupMenu mPastePopupWindow;
 
         // Touch-up filter: number of previous positions remembered
@@ -8684,12 +8673,12 @@
         private int mPreviousOffsetIndex = 0;
         private int mNumberPreviousOffsets = 0;
 
-        public void startTouchUpFilter(int offset) {
+        private void startTouchUpFilter(int offset) {
             mNumberPreviousOffsets = 0;
             addPositionToTouchUpFilter(offset);
         }
 
-        public void addPositionToTouchUpFilter(int offset) {
+        private void addPositionToTouchUpFilter(int offset) {
             if (mNumberPreviousOffsets > 0 &&
                     mPreviousOffsets[mPreviousOffsetIndex] == offset) {
                 // Make sure only actual changes of position are recorded.
@@ -8702,7 +8691,7 @@
             mNumberPreviousOffsets++;
         }
 
-        public void filterOnTouchUp() {
+        private void filterOnTouchUp() {
             final long now = SystemClock.uptimeMillis();
             int i = 0;
             int index = mPreviousOffsetIndex;
@@ -8725,16 +8714,17 @@
         public HandleView(CursorController controller, int pos) {
             super(TextView.this.mContext);
             mController = controller;
-            mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
+            mContainer = new PopupWindow(TextView.this.mContext, null,
                     com.android.internal.R.attr.textSelectHandleWindowStyle);
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
             mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mContainer.setContentView(this);
 
-            setOrientation(pos);
+            setPosition(pos);
         }
 
-        public void setOrientation(int pos) {
+        private void setPosition(int pos) {
             int handleWidth;
             switch (pos) {
                 case LEFT: {
@@ -8774,38 +8764,48 @@
             }
 
             final int handleHeight = mDrawable.getIntrinsicHeight();
-
             mTouchOffsetY = -0.3f * handleHeight;
             mIdealVerticalOffset = 0.7f * handleHeight;
+
             invalidate();
         }
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            setMeasuredDimension(mDrawable.getIntrinsicWidth(),
-                    mDrawable.getIntrinsicHeight());
+            setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
         }
 
         public void show() {
-            if (!isPositionVisible()) {
-                hide();
-                return;
-            }
-            mContainer.setContentView(this);
-            mContainerPositionX = mPositionX;
-            mContainerPositionY = mPositionY - TextView.this.getHeight();
-            mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
+            updateContainerPosition();
+            if (isShowing()) {
+                mContainer.update(mContainerPositionX, mContainerPositionY,
+                        mRight - mLeft, mBottom - mTop);
 
-            // Hide paste view when handle is moved on screen.
+                hidePastePopupWindow();
+            } else {
+                mContainer.showAtLocation(TextView.this, 0,
+                        mContainerPositionX, mContainerPositionY);
+
+                mIsActive = true;
+
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.addOnPreDrawListener(this);
+            }
+        }
+
+        private void dismiss() {
+            mIsDragging = false;
+            mContainer.dismiss();
             hidePastePopupWindow();
         }
 
         public void hide() {
-            mIsDragging = false;
-            mContainer.dismiss();
-            hidePastePopupWindow();
+            dismiss();
+
+            mIsActive = false;
+
             ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.removeOnScrollChangedListener(this);
+            vto.removeOnPreDrawListener(this);
         }
 
         public boolean isShowing() {
@@ -8856,44 +8856,59 @@
         private void moveTo(int x, int y) {
             mPositionX = x - TextView.this.mScrollX;
             mPositionY = y - TextView.this.mScrollY;
-            if (isPositionVisible()) {
-                int[] coords = null;
-                if (mContainer.isShowing()) {
-                    final int containerPositionX = mPositionX;
-                    final int containerPositionY = mPositionY - TextView.this.getHeight();
 
-                    if (containerPositionX != mContainerPositionX || 
-                        containerPositionY != mContainerPositionY) {
-                        mContainerPositionX = containerPositionX;
-                        mContainerPositionY = containerPositionY;
+            if (mIsDragging) {
+                TextView.this.getLocationInWindow(mTempCoords);
+                if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
+                    mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
+                    mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
+                    mLastParentX = mTempCoords[0];
+                    mLastParentY = mTempCoords[1];
+                }
+                // Hide paste popup window as soon as the handle is dragged.
+                hidePastePopupWindow();
+            }
+        }
 
-                        mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
-                                mRight - mLeft, mBottom - mTop);
+        /**
+         * Updates the global container's position.
+         * @return whether or not the position has actually changed
+         */
+        private boolean updateContainerPosition() {
+            // TODO Prevent this using different HandleView subclasses
+            mController.updateOffset(this, mController.getCurrentOffset(this));
+            TextView.this.getLocationInWindow(mTempCoords);
+            final int containerPositionX = mTempCoords[0] + mPositionX;
+            final int containerPositionY = mTempCoords[1] + mPositionY;
 
-                        // Hide paste popup window as soon as a scroll occurs.
-                        hidePastePopupWindow();
+            if (containerPositionX != mContainerPositionX ||
+                containerPositionY != mContainerPositionY) {
+                mContainerPositionX = containerPositionX;
+                mContainerPositionY = containerPositionY;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean onPreDraw() {
+            if (updateContainerPosition()) {
+                if (isPositionVisible()) {
+                    mContainer.update(mContainerPositionX, mContainerPositionY,
+                            mRight - mLeft, mBottom - mTop);
+
+                    if (mIsActive && !isShowing()) {
+                        show();
                     }
                 } else {
-                    show();
+                    if (isShowing()) {
+                        dismiss();
+                    }
                 }
 
-                if (mIsDragging) {
-                    if (coords == null) {
-                        coords = mTempCoords;
-                        TextView.this.getLocationInWindow(coords);
-                    }
-                    if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
-                        mTouchToWindowOffsetX += coords[0] - mLastParentX;
-                        mTouchToWindowOffsetY += coords[1] - mLastParentY;
-                        mLastParentX = coords[0];
-                        mLastParentY = coords[1];
-                    }
-                    // Hide paste popup window as soon as the handle is dragged.
-                    hidePastePopupWindow();
-                }
-            } else {
-                hide();
+                // Hide paste popup as soon as the view is scrolled or moved
+                hidePastePopupWindow();
             }
+            return true;
         }
 
         @Override
@@ -8979,7 +8994,7 @@
             return mIsDragging;
         }
 
-        void positionAtCursor(final int offset) {
+        void positionAtCursor(int offset) {
             addPositionToTouchUpFilter(offset);
             final int width = mDrawable.getIntrinsicWidth();
             final int height = mDrawable.getIntrinsicHeight();
@@ -9013,50 +9028,6 @@
                 mPastePopupWindow.hide();
             }
         }
-
-        /**
-         * A popup window, attached to a view, and that listens to scroll events in its anchors'
-         * view hierarchy, so that it is automatically moved on such events.
-         */
-        private class ScrollingPopupWindow extends PopupWindow {
-
-            private int[] mDrawingLocations = new int[2];
-
-            public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
-                super(context, attrs, defStyle);
-            }
-
-            @Override
-            public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-                    int xoff, int yoff) {
-                anchor.getLocationInWindow(mDrawingLocations);
-                p.x = mDrawingLocations[0] + xoff;
-                p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;
-
-                // Hide paste popup as soon as the view is scrolled.
-                hidePastePopupWindow();
-
-                if (!isPositionVisible()) {
-                    dismiss();
-                    onHandleBecomeInvisible();
-                }
-
-                return false;
-            }
-        }
-
-        public void onScrollChanged() {
-            if (isPositionVisible()) {
-                show();
-                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-                vto.removeOnScrollChangedListener(this);
-            }
-        }
-
-        public void onHandleBecomeInvisible() {
-            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
-            vto.addOnScrollChangedListener(this);
-        }
     }
 
     private class InsertionPointCursorController implements CursorController {
@@ -9074,7 +9045,7 @@
         }
 
         public void show(int delayBeforePaste) {
-            updatePosition();
+            getHandle().show();
             hideDelayed();
             removePastePopupCallback();
             final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
@@ -9213,7 +9184,6 @@
             if (mEndHandle == null) mEndHandle = new HandleView(this, HandleView.RIGHT);
 
             mIsShowing = true;
-            updatePosition();
 
             mStartHandle.show();
             mEndHandle.show();
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index a41b348..586ba87 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -43,6 +43,7 @@
 import android.view.ViewParent;
 import android.view.Window;
 import android.widget.AdapterView;
+import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -957,4 +958,60 @@
             }
         }
     }
+
+    private static class HomeView extends FrameLayout {
+        private View mUpView;
+        private View mIconView;
+
+        public HomeView(Context context) {
+            this(context, null);
+        }
+
+        public HomeView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        protected void onFinishInflate() {
+            mUpView = findViewById(com.android.internal.R.id.up);
+            mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
+            final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+            int width = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+            int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
+            measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+            height = Math.max(height,
+                    iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+            setMeasuredDimension(width, height);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            final int vCenter = (b - t) / 2;
+            int width = r - l;
+            if (mUpView.getVisibility() != GONE) {
+                final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+                final int upHeight = mUpView.getMeasuredHeight();
+                final int upWidth = mUpView.getMeasuredWidth();
+                final int upTop = t + vCenter - upHeight / 2;
+                mUpView.layout(l, upTop, l + upWidth, upTop + upHeight);
+                final int upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
+                width -= upOffset;
+                l += upOffset;
+            }
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            final int iconHeight = mIconView.getMeasuredHeight();
+            final int iconWidth = mIconView.getMeasuredWidth();
+            final int hCenter = (r - l) / 2;
+            final int iconLeft = l + iconLp.leftMargin + hCenter - iconWidth / 2;
+            final int iconTop = t + iconLp.topMargin + vCenter - iconHeight / 2;
+            mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
+        }
+    }
 }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 7a609a5..a78f660 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -35,7 +35,6 @@
 
 #include <DisplayListRenderer.h>
 #include <LayerRenderer.h>
-#include <OpenGLDebugRenderer.h>
 #include <OpenGLRenderer.h>
 #include <SkiaShader.h>
 #include <SkiaColorFilter.h>
@@ -60,7 +59,6 @@
 
 // Debug
 #define DEBUG_RENDERER 0
-#define PROFILE_RENDERER 0
 
 // Debug
 #if DEBUG_RENDERER
@@ -99,11 +97,7 @@
 
 static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) {
     RENDERER_LOGD("Create OpenGLRenderer");
-#if PROFILE_RENDERER
-    return new OpenGLDebugRenderer;
-#else
     return new OpenGLRenderer;
-#endif
 }
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
@@ -139,7 +133,8 @@
 
 static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
-    return renderer->callDrawGLFunction(functor);
+    android::uirenderer::Rect dirty;
+    return renderer->callDrawGLFunction(functor, dirty);
 }
 
 // ----------------------------------------------------------------------------
@@ -503,8 +498,14 @@
 }
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
-        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
-    return renderer->drawDisplayList(displayList);
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList, jobject dirty) {
+    android::uirenderer::Rect bounds;
+    bool redraw = renderer->drawDisplayList(displayList, bounds);
+    if (redraw && dirty != NULL) {
+        env->CallVoidMethod(dirty, gRectClassInfo.set,
+                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
+    }
+    return redraw;
 }
 
 // ----------------------------------------------------------------------------
@@ -663,7 +664,8 @@
     { "nGetDisplayList",         "(I)I",       (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
-    { "nDrawDisplayList",        "(II)Z",      (void*) android_view_GLES20Canvas_drawDisplayList },
+    { "nDrawDisplayList",        "(IILandroid/graphics/Rect;)Z",
+                                               (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0ad174f..c684e7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1379,12 +1379,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <activity android:name="com.android.server.usb.UsbResolverActivity"
-            android:theme="@style/Theme.Holo.Dialog.Alert"
-            android:finishOnCloseSystemDialogs="true"
-            android:excludeFromRecents="true">
-        </activity>
-
         <service android:name="com.android.server.LoadAverageService"
                 android:exported="true" />
 
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml
index 7867577..c82f91d 100644
--- a/core/res/res/layout/action_bar_home.xml
+++ b/core/res/res/layout/action_bar_home.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="wrap_content"
-              android:layout_height="match_parent"
-              android:background="?android:attr/selectableItemBackground"
-              android:orientation="horizontal">
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+      class="com.android.internal.widget.ActionBarView$HomeView"
+      android:layout_width="wrap_content"
+      android:layout_height="match_parent"
+      android:background="?android:attr/selectableItemBackground" >
     <ImageView android:id="@android:id/up"
                android:src="?android:attr/homeAsUpIndicator"
-               android:layout_gravity="top|left"
+               android:layout_gravity="center_vertical|left"
                android:visibility="gone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
@@ -33,4 +33,4 @@
                android:paddingRight="16dip"
                android:layout_gravity="center"
                android:scaleType="center" />
-</LinearLayout>
+</view>
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 93b6deb..c52b73f 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -54,6 +54,10 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="center_vertical"
+        android:layout_marginLeft="4dip"
+        android:layout_marginRight="4dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginBottom="4dip"
         android:orientation="horizontal">
 
         <!-- Inner layout contains the app icon, button(s) and EditText -->
diff --git a/core/res/res/raw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..492658d
--- /dev/null
+++ b/core/res/res/raw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+    <title>New incognito tab</title>
+  </head>
+  <body>
+    <p><strong>You've gone incognito</strong>. Pages you view in this tab
+      won't appear in your browser history or search history, and they won't
+      leave other traces, like cookies, on your device after you close the
+      incognito tab. Any files you download or bookmarks you create will be
+      preserved, however.</p>
+
+    <p><strong>Going incognito doesn't affect the behavior of other people,
+      servers, or software. Be wary of:</strong></p>
+
+    <ul>
+      <li>Websites that collect or share information about you</li>
+      <li>Internet service providers or employers that track the pages you visit</li>
+      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+      <li>Surveillance by secret agents</li>
+      <li>People standing behind you</li>
+    </ul>
+  </body>
+</html>
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 7e46e26..5a97158 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -183,20 +183,15 @@
      * Replacing the value for a key doesn't cause an eviction but it does bring
      * the replaced entry to the front of the queue.
      */
-    public void testPutDoesNotCauseEviction() {
-        final List<String> evictionLog = new ArrayList<String>();
-        List<String> expectedEvictionLog = new ArrayList<String>();
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected void entryEvicted(String key, String value) {
-                evictionLog.add(key + "=" + value);
-            }
-        };
+    public void testPutCauseEviction() {
+        List<String> log = new ArrayList<String>();
+        LruCache<String, String> cache = newRemovalLogCache(log);
 
         cache.put("a", "A");
         cache.put("b", "B");
         cache.put("c", "C");
         cache.put("b", "B2");
-        assertEquals(expectedEvictionLog, evictionLog);
+        assertEquals(Arrays.asList("b=B>B2"), log);
         assertSnapshot(cache, "a", "A", "c", "C", "b", "B2");
     }
 
diff --git a/docs/html/images/avd-manager.png b/docs/html/images/avd-manager.png
index 69ce972..c33d8a8 100644
--- a/docs/html/images/avd-manager.png
+++ b/docs/html/images/avd-manager.png
Binary files differ
diff --git a/docs/html/images/billing_package.png b/docs/html/images/billing_package.png
old mode 100755
new mode 100644
index ec04c2d..951e117
--- a/docs/html/images/billing_package.png
+++ b/docs/html/images/billing_package.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-isLib.png b/docs/html/images/developing/adt-props-isLib.png
index 18bdb33..49c9111 100644
--- a/docs/html/images/developing/adt-props-isLib.png
+++ b/docs/html/images/developing/adt-props-isLib.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-libRef.png b/docs/html/images/developing/adt-props-libRef.png
index e61df51..73bccbd 100644
--- a/docs/html/images/developing/adt-props-libRef.png
+++ b/docs/html/images/developing/adt-props-libRef.png
Binary files differ
diff --git a/docs/html/images/licensing_add_library.png b/docs/html/images/licensing_add_library.png
index 90b4435..3bbe6d5 100644
--- a/docs/html/images/licensing_add_library.png
+++ b/docs/html/images/licensing_add_library.png
Binary files differ
diff --git a/docs/html/images/licensing_gapis_8.png b/docs/html/images/licensing_gapis_8.png
index 43ad262..480d989 100644
--- a/docs/html/images/licensing_gapis_8.png
+++ b/docs/html/images/licensing_gapis_8.png
Binary files differ
diff --git a/docs/html/images/licensing_package.png b/docs/html/images/licensing_package.png
index 5da5632..eb2c5cf 100644
--- a/docs/html/images/licensing_package.png
+++ b/docs/html/images/licensing_package.png
Binary files differ
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index 3955bc3..565f4a3 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -26,6 +26,7 @@
     Functor() {}
     virtual ~Functor() {}
     virtual status_t operator ()() { return true; }
+    virtual status_t operator ()(float* data, uint32_t len) { return true; }
 };
 
 }; // namespace android
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 38e0848..f4a0161 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -15,7 +15,6 @@
 		LayerCache.cpp \
 		LayerRenderer.cpp \
 		Matrix.cpp \
-		OpenGLDebugRenderer.cpp \
 		OpenGLRenderer.cpp \
 		Patch.cpp \
 		PatchCache.cpp \
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d5d2ba0..737fa02 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -166,7 +166,7 @@
 void DisplayList::init() {
 }
 
-bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
     mReader.rewind();
@@ -189,7 +189,7 @@
             case DrawGLFunction: {
                 Functor *functor = (Functor *) getInt();
                 DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-                needsInvalidate |= renderer.callDrawGLFunction(functor);
+                needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
             }
             break;
             case Save: {
@@ -287,7 +287,7 @@
                 DisplayList* displayList = getDisplayList();
                 DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op],
                     displayList, level + 1);
-                needsInvalidate |= renderer.drawDisplayList(displayList, level + 1);
+                needsInvalidate |= renderer.drawDisplayList(displayList, dirty, level + 1);
             }
             break;
             case DrawLayer: {
@@ -589,7 +589,8 @@
 void DisplayListRenderer::resume() {
 }
 
-bool DisplayListRenderer::callDrawGLFunction(Functor *functor) {
+bool DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+    // Ignore dirty during recording, it matters only when we replay
     addOp(DisplayList::DrawGLFunction);
     addInt((int) functor);
     return false; // No invalidate needed at record-time
@@ -673,7 +674,9 @@
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
-bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) {
+    // dirty is an out parameter and should not be recorded,
+    // it matters only when replaying the display list
     addOp(DisplayList::DrawDisplayList);
     addDisplayList(displayList);
     return false;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index e8f189d..f24545d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -103,7 +103,7 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    bool replay(OpenGLRenderer& renderer, uint32_t level = 0);
+    bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
 private:
     void init();
@@ -214,7 +214,7 @@
     void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     void finish();
 
-    bool callDrawGLFunction(Functor *functor);
+    bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     void interrupt();
     void resume();
@@ -238,7 +238,7 @@
 
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0);
     void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
deleted file mode 100644
index 05870bb..0000000
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include <utils/StopWatch.h>
-
-#include "OpenGLDebugRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-void OpenGLDebugRenderer::prepareDirty(float left, float top,
-        float right, float bottom, bool opaque) {
-    mPrimitivesCount = 0;
-    LOGD("========= Frame start =========");
-    OpenGLRenderer::prepareDirty(left, top, right, bottom, opaque);
-}
-
-void OpenGLDebugRenderer::finish() {
-    LOGD("========= Frame end =========");
-    LOGD("Primitives draw count = %d", mPrimitivesCount);
-    OpenGLRenderer::finish();
-}
-
-void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
-    mPrimitivesCount++;
-    StopWatch w("composeLayer");
-    return OpenGLRenderer::composeLayer(current, previous);
-}
-
-int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom,
-        SkPaint* p, int flags) {
-    mPrimitivesCount++;
-    StopWatch w("saveLayer");
-    return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
-}
-
-bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
-    mPrimitivesCount++;
-    StopWatch w("drawDisplayList");
-    return OpenGLRenderer::drawDisplayList(displayList);
-}
-
-void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLayer");
-    OpenGLRenderer::drawLayer(layer, x, y, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmap");
-    OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapMatrix");
-    OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-        float srcRight, float srcBottom, float dstLeft, float dstTop,
-        float dstRight, float dstBottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapRect");
-    OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
-            dstLeft, dstTop, dstRight, dstBottom, paint);
-}
-
-void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPatch");
-    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
-            left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    mPrimitivesCount++;
-    StopWatch w("drawColor");
-    OpenGLRenderer::drawColor(color, mode);
-}
-
-void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRect");
-    OpenGLRenderer::drawRect(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRoundRect");
-    OpenGLRenderer::drawRoundRect(left, top, right, bottom, rx, ry, paint);
-}
-
-void OpenGLDebugRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawCircle");
-    OpenGLRenderer::drawCircle(x, y, radius, paint);
-}
-
-void OpenGLDebugRenderer::drawOval(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawOval");
-    OpenGLRenderer::drawOval(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawArc");
-    OpenGLRenderer::drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
-}
-
-void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPath");
-    OpenGLRenderer::drawPath(path, paint);
-}
-
-void OpenGLDebugRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLines");
-    OpenGLRenderer::drawLines(points, count, paint);
-}
-
-void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawText");
-    OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
deleted file mode 100644
index 1a18a67..0000000
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
-#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
-
-#include "OpenGLRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Renderer
-///////////////////////////////////////////////////////////////////////////////
-
-class OpenGLDebugRenderer: public OpenGLRenderer {
-public:
-    OpenGLDebugRenderer(): mPrimitivesCount(0) {
-    }
-
-    ~OpenGLDebugRenderer() {
-    }
-
-    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    void finish();
-
-    int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* p, int flags);
-
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
-    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, SkPaint* paint);
-    void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, SkPaint* paint);
-    void drawCircle(float x, float y, float radius, SkPaint* paint);
-    void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
-    void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
-    void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, SkPaint* paint);
-    void drawText(const char* text, int bytesCount, int count, float x, float y,
-            SkPaint* paint);
-
-protected:
-    void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
-
-private:
-    uint32_t mPrimitivesCount;
-
-}; // class OpenGLDebugRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index dfca7eb..1f65201 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -210,7 +210,7 @@
     glBlendEquation(GL_FUNC_ADD);
 }
 
-bool OpenGLRenderer::callDrawGLFunction(Functor *functor) {
+bool OpenGLRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     interrupt();
     if (mDirtyClip) {
         setScissorFromClip();
@@ -226,9 +226,16 @@
     }
 #endif
 
-    status_t result = (*functor)();
+    float bounds[4];
+    status_t result = (*functor)(&bounds[0], 4);
+
+    if (result != 0) {
+        Rect localDirty(bounds[0], bounds[1], bounds[2], bounds[3]);
+        dirty.unionWith(localDirty);
+    }
+
     resume();
-    return (result == 0) ? false : true;
+    return result != 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1057,11 +1064,11 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) {
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList) {
-        return displayList->replay(*this, level);
+        return displayList->replay(*this, dirty, level);
     }
     return false;
 }
@@ -1522,7 +1529,6 @@
             break;
     }
 
-    // TODO: Handle paint->getTextScaleX()
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7bbf034..9d86388 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -70,7 +70,7 @@
     virtual void interrupt();
     virtual void resume();
 
-    virtual bool callDrawGLFunction(Functor *functor);
+    virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     int getSaveCount() const;
     virtual int save(int flags);
@@ -96,7 +96,7 @@
     bool quickReject(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    virtual bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 62c4250..d46686d 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -42,6 +42,17 @@
 
         textSize = paint->getTextSize();
         typeface = paint->getTypeface();
+
+        flags = 0;
+        if (paint->isFakeBoldText()) {
+            flags |= Font::kFakeBold;
+        }
+
+        const float skewX = paint->getTextSkewX();
+        italicStyle = *(uint32_t*) &skewX;
+
+        const float scaleXFloat = paint->getTextScaleX();
+        scaleX = *(uint32_t*) &scaleXFloat;
     }
 
     ~ShadowText() {
@@ -51,6 +62,9 @@
     uint32_t len;
     float textSize;
     SkTypeface* typeface;
+    uint32_t flags;
+    uint32_t italicStyle;
+    uint32_t scaleX;
     const char16_t* text;
     String16 str;
 
@@ -65,7 +79,13 @@
             LTE_INT(radius) {
                 LTE_FLOAT(textSize) {
                     LTE_INT(typeface) {
-                        return strncmp16(text, rhs.text, len >> 1) < 0;
+                        LTE_INT(flags) {
+                            LTE_INT(italicStyle) {
+                                LTE_INT(scaleX) {
+                                    return strncmp16(text, rhs.text, len >> 1) < 0;
+                                }
+                            }
+                        }
                     }
                 }
             }
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index b2f547b..7069b23 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -140,7 +140,7 @@
         try {
           properties = mMANativeHelper.getMediaProperties(filename);
         } catch (Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found");
+            throw new IllegalArgumentException(e.getMessage() + " : " + filename);
         }
         switch (mMANativeHelper.getFileType(properties.fileType)) {
             case MediaProperties.FILE_3GP:
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index c91d796..4758de6 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -115,7 +115,7 @@
         try {
              properties = mMANativeHelper.getMediaProperties(filename);
         } catch ( Exception e) {
-            throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
+            throw new IllegalArgumentException(e.getMessage() + " : " + filename);
         }
 
         switch (mMANativeHelper.getFileType(properties.fileType)) {
diff --git a/media/java/android/mtp/MtpClient.java b/media/java/android/mtp/MtpClient.java
index 40e2f9b..d25dcb9 100644
--- a/media/java/android/mtp/MtpClient.java
+++ b/media/java/android/mtp/MtpClient.java
@@ -16,6 +16,7 @@
 
 package android.mtp;
 
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -41,6 +42,9 @@
 
     private static final String TAG = "MtpClient";
 
+    private static final String ACTION_USB_PERMISSION =
+            "android.mtp.MtpClient.action.USB_PERMISSION";
+
     private final Context mContext;
     private final UsbManager mUsbManager;
     private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
@@ -49,29 +53,47 @@
     // mDevices is also used for synchronization in this class.
     private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
 
+    private final PendingIntent mPermissionIntent;
+
     private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
             UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
             String deviceName = usbDevice.getDeviceName();
 
             synchronized (mDevices) {
                 MtpDevice mtpDevice = mDevices.get(deviceName);
 
-                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                     if (mtpDevice == null) {
                         mtpDevice = openDeviceLocked(usbDevice);
                     }
                     if (mtpDevice != null) {
-                        mDevices.put(deviceName, mtpDevice);
                         for (Listener listener : mListeners) {
                             listener.deviceAdded(mtpDevice);
                         }
                     }
-                } else if (mtpDevice != null) {
-                    mDevices.remove(deviceName);
-                    for (Listener listener : mListeners) {
-                        listener.deviceRemoved(mtpDevice);
+                } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+                    if (mtpDevice != null) {
+                        mDevices.remove(deviceName);
+                        for (Listener listener : mListeners) {
+                            listener.deviceRemoved(mtpDevice);
+                        }
+                    }
+                } else if (ACTION_USB_PERMISSION.equals(action)) {
+                    boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
+                            false);
+                    Log.d(TAG, "ACTION_USB_PERMISSION: " + permission);
+                    if (permission) {
+                        if (mtpDevice == null) {
+                            mtpDevice = openDeviceLocked(usbDevice);
+                        }
+                        if (mtpDevice != null) {
+                            for (Listener listener : mListeners) {
+                                listener.deviceAdded(mtpDevice);
+                            }
+                        }
                     }
                 }
             }
@@ -126,10 +148,11 @@
     public MtpClient(Context context) {
         mContext = context;
         mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
-
+        mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
         IntentFilter filter = new IntentFilter();
         filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
         filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        filter.addAction(ACTION_USB_PERMISSION);
         context.registerReceiver(mUsbReceiver, filter);
     }
 
@@ -142,9 +165,14 @@
      */
     private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
         if (isCamera(usbDevice)) {
-            MtpDevice mtpDevice = new MtpDevice(usbDevice);
-            if (mtpDevice.open(mUsbManager)) {
-                return mtpDevice;
+            if (!mUsbManager.hasPermission(usbDevice)) {
+                mUsbManager.requestPermission(usbDevice, mPermissionIntent);
+            } else {
+                MtpDevice mtpDevice = new MtpDevice(usbDevice);
+                if (mtpDevice.open(mUsbManager)) {
+                    mDevices.put(usbDevice.getDeviceName(), mtpDevice);
+                    return mtpDevice;
+                }
             }
         }
         return null;
@@ -218,13 +246,8 @@
             // Query the USB manager since devices might have attached
             // before we added our listener.
             for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
-                String deviceName = usbDevice.getDeviceName();
-                MtpDevice mtpDevice = mDevices.get(deviceName);
-                if (mtpDevice == null) {
-                   mtpDevice = openDeviceLocked(usbDevice);
-                }
-                if (mtpDevice != null) {
-                    mDevices.put(deviceName, mtpDevice);
+                if (mDevices.get(usbDevice.getDeviceName()) == null) {
+                    openDeviceLocked(usbDevice);
                 }
             }
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 98de2f7..b4a4689 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -20,6 +20,7 @@
 import android.content.ContentValues;
 import android.content.IContentProvider;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.media.MediaScanner;
@@ -62,8 +63,8 @@
     // true if the database has been modified in the current MTP session
     private boolean mDatabaseModified;
 
-    // database for writable MTP device properties
-    private SQLiteDatabase mDevicePropDb;
+    // SharedPreferences for writable MTP device properties
+    private SharedPreferences mDeviceProperties;
     private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1;
 
     // FIXME - this should be passed in via the constructor
@@ -96,9 +97,6 @@
     private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
                                             + Files.FileColumns.FORMAT + "=?";
 
-    private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" };
-    private  static final String DEVICE_PROPERTY_WHERE = "code=?";
-
     private final MediaScanner mMediaScanner;
 
     static {
@@ -114,7 +112,7 @@
         mMediaStoragePath = storagePath;
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
         mMediaScanner = new MediaScanner(context);
-        openDevicePropertiesDatabase(context);
+        initDeviceProperties(context);
     }
 
     @Override
@@ -126,19 +124,38 @@
         }
     }
 
-    private void openDevicePropertiesDatabase(Context context) {
-        mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
-        int version = mDevicePropDb.getVersion();
+    private void initDeviceProperties(Context context) {
+        final String devicePropertiesName = "device-properties";
+        mDeviceProperties = context.getSharedPreferences(devicePropertiesName, Context.MODE_PRIVATE);
+        File databaseFile = context.getDatabasePath(devicePropertiesName);
 
-        // initialize if necessary
-        if (version != DEVICE_PROPERTIES_DATABASE_VERSION) {
-            mDevicePropDb.execSQL("CREATE TABLE properties (" +
-                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
-                    "code INTEGER UNIQUE ON CONFLICT REPLACE," +
-                    "value TEXT" +
-                    ");");
-            mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);");
-            mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION);
+        if (databaseFile.exists()) {
+            // for backward compatibility - read device properties from sqlite database
+            // and migrate them to shared prefs
+            SQLiteDatabase db = null;
+            Cursor c = null;
+            try {
+                db = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
+                if (db != null) {
+                    c = db.query("properties", new String[] { "_id", "code", "value" },
+                            null, null, null, null, null);
+                    if (c != null) {
+                        SharedPreferences.Editor e = mDeviceProperties.edit();
+                        while (c.moveToNext()) {
+                            String name = c.getString(1);
+                            String value = c.getString(2);
+                            e.putString(name, value);
+                        }
+                        e.commit();
+                    }
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "failed to migrate device properties", e);
+            } finally {
+                if (c != null) c.close();
+                if (db != null) db.close();
+            }
+            databaseFile.delete();
         }
     }
 
@@ -567,30 +584,15 @@
         switch (property) {
             case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
             case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
-                // writable string properties kept in our device property database
-                Cursor c = null;
-                try {
-                    c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION,
-                        DEVICE_PROPERTY_WHERE, new String[] {  Integer.toString(property) },
-                        null, null, null);
-
-                    if (c != null && c.moveToNext()) {
-                        String value = c.getString(1);
-                        int length = value.length();
-                        if (length > 255) {
-                            length = 255;
-                        }
-                        value.getChars(0, length, outStringValue, 0);
-                        outStringValue[length] = 0;
-                    } else {
-                        outStringValue[0] = 0;
-                    }
-                    return MtpConstants.RESPONSE_OK;
-                } finally {
-                    if (c != null) {
-                        c.close();
-                    }
+                // writable string properties kept in shared preferences
+                String value = mDeviceProperties.getString(Integer.toString(property), "");
+                int length = value.length();
+                if (length > 255) {
+                    length = 255;
                 }
+                value.getChars(0, length, outStringValue, 0);
+                outStringValue[length] = 0;
+                return MtpConstants.RESPONSE_OK;
 
             case MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE:
                 // use screen size as max image size
@@ -612,16 +614,11 @@
         switch (property) {
             case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
             case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
-                // writable string properties kept in our device property database
-                try {
-                    ContentValues values = new ContentValues();
-                    values.put("code", property);
-                    values.put("value", stringValue);
-                    mDevicePropDb.insert("properties", "code", values);
-                    return MtpConstants.RESPONSE_OK;
-                } catch (Exception e) {
-                    return MtpConstants.RESPONSE_GENERAL_ERROR;
-                }
+                // writable string properties kept in shared prefs
+                SharedPreferences.Editor e = mDeviceProperties.edit();
+                e.putString(Integer.toString(property), stringValue);
+                return (e.commit() ? MtpConstants.RESPONSE_OK
+                        : MtpConstants.RESPONSE_GENERAL_ERROR);
         }
 
         return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index 423e93f..035f59a 100755
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -207,6 +207,7 @@
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_HIGH                        ),
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL                   ),
     VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_NOMORE_SPACE                                 ),
+    VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_FILE_DRM_PROTECTED                           ),
 
     // M4READER_Common.h
     VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READER_UNKNOWN_STREAM_TYPE                       ),
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
index 73a7c9c..3b795ce 100755
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
@@ -204,10 +204,17 @@
                 result = getClipProperties(
                         pEnv, thiz, pFile, clipType, pClipProperties);
 
-                // Check if the creation succeeded.
-                videoEditJava_checkAndThrowIllegalArgumentException(
-                        &gotten, pEnv,(M4NO_ERROR != result),
-                        "Invalid File or File not found");
+                if (M4MCS_ERR_FILE_DRM_PROTECTED == result) {
+                    // Check if the creation succeeded.
+                    videoEditJava_checkAndThrowIllegalArgumentException(
+                            &gotten, pEnv,(M4NO_ERROR != result),
+                            "Invalid File - DRM Protected ");
+                } else {
+                    // Check if the creation succeeded.
+                    videoEditJava_checkAndThrowIllegalArgumentException(
+                            &gotten, pEnv,(M4NO_ERROR != result),
+                            "Invalid File or File not found ");
+                }
 
                 /**
                  * Max resolution supported is 1280 x 720.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d3d1750..fee245f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -8,6 +8,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.MANAGE_USB" />
 
     <application
         android:persistent="true"
@@ -39,5 +40,22 @@
             android:exported="true">
         </activity>
 
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbPermissionActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
+        <!-- started from UsbDeviceSettingsManager -->
+        <activity android:name=".usb.UsbResolverActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
     </application>
 </manifest>
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
index bfa6c36..3f172e6 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
@@ -38,8 +38,8 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginLeft="123dip"
-        android:layout_marginTop="16dip"
+        android:layout_marginLeft="131dip"
+        android:layout_marginTop="13dip"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
index eda19b7..42940be 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
@@ -51,7 +51,7 @@
                 android:stackFromBottom="true"
                 android:fadingEdge="vertical"
                 android:scrollbars="none"
-                android:fadingEdgeLength="30dip"
+                android:fadingEdgeLength="20dip"
                 android:listSelector="@drawable/recents_thumbnail_bg_selector"
             />
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ebd48e7..becad6a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -115,4 +115,11 @@
 
     <!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] -->
     <string name="status_bar_use_physical_keyboard">Use physical keyboard</string>
+
+    <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
+    <string name="usb_device_permission_prompt">Allow the application %1$s to access the USB device?</string>
+
+    <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
+    <string name="usb_accessory_permission_prompt">Allow the application %1$s to access the USB accessory?</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
new file mode 100644
index 0000000..1edebbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+
+// This class is used to close UsbPermissionsActivity and UsbResolverActivity
+// if their device/accessory is disconnected while the dialog is still open
+class UsbDisconnectedReceiver extends BroadcastReceiver {
+    private final Activity mActivity;
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+
+    public UsbDisconnectedReceiver(Activity activity, UsbDevice device) {
+       mActivity = activity;
+        mDevice = device;
+
+        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        activity.registerReceiver(this, filter);
+    }
+
+    public UsbDisconnectedReceiver(Activity activity, UsbAccessory accessory) {
+        mActivity = activity;
+        mAccessory = accessory;
+
+        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        activity.registerReceiver(this, filter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+            UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (device != null && device.equals(mDevice)) {
+                mActivity.finish();
+            }
+        } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+            UsbAccessory accessory =
+                    (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null && accessory.equals(mAccessory)) {
+                mActivity.finish();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
new file mode 100644
index 0000000..f1784df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbPermissionActivity extends AlertActivity
+        implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+    private static final String TAG = "UsbPermissionActivity";
+
+    private CheckBox mAlwaysCheck;
+    private TextView mClearDefaultHint;
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+    private PendingIntent mPendingIntent;
+    private String mPackageName;
+    private int mUid;
+    private boolean mPermissionGranted;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+       Intent intent = getIntent();
+        mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+        mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
+        mUid = intent.getIntExtra("uid", 0);
+        mPackageName = intent.getStringExtra("package");
+
+        PackageManager packageManager = getPackageManager();
+        ApplicationInfo aInfo;
+        try {
+            aInfo = packageManager.getApplicationInfo(mPackageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "unable to look up package name", e);
+            finish();
+            return;
+        }
+        String appName = aInfo.loadLabel(packageManager).toString();
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mIcon = aInfo.loadIcon(packageManager);
+        ap.mTitle = appName;
+        if (mDevice == null) {
+            ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+        } else {
+            ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+        }
+        ap.mPositiveButtonText = getString(com.android.internal.R.string.ok);
+        ap.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        // add "always use" checkbox
+        LayoutInflater inflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+        mAlwaysCheck = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+        mAlwaysCheck.setText(com.android.internal.R.string.alwaysUse);
+        mAlwaysCheck.setOnCheckedChangeListener(this);
+        mClearDefaultHint = (TextView)ap.mView.findViewById(
+                                                    com.android.internal.R.id.clearDefaultHint);
+        mClearDefaultHint.setVisibility(View.GONE);
+
+        setupAlert();
+
+    }
+
+    @Override
+    public void onDestroy() {
+        IBinder b = ServiceManager.getService(USB_SERVICE);
+        IUsbManager service = IUsbManager.Stub.asInterface(b);
+
+        // send response via pending intent
+        Intent intent = new Intent();
+        try {
+            if (mDevice != null) {
+                intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+                if (mPermissionGranted) {
+                    service.grantDevicePermission(mDevice, mUid);
+                    if (mAlwaysCheck.isChecked()) {
+                        service.setDevicePackage(mDevice, mPackageName);
+                    }
+                }
+            }
+            if (mAccessory != null) {
+                intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+                if (mPermissionGranted) {
+                    service.grantAccessoryPermission(mAccessory, mUid);
+                    if (mAlwaysCheck.isChecked()) {
+                        service.setAccessoryPackage(mAccessory, mPackageName);
+                    }
+                }
+            }
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
+            mPendingIntent.send(this, 0, intent);
+        } catch (PendingIntent.CanceledException e) {
+            Log.w(TAG, "PendingIntent was cancelled");
+        } catch (RemoteException e) {
+            Log.e(TAG, "IUsbService connection failed", e);
+        }
+
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onDestroy();
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            mPermissionGranted = true;
+        }
+        finish();
+    }
+
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (mClearDefaultHint == null) return;
+
+        if(isChecked) {
+            mClearDefaultHint.setVisibility(View.VISIBLE);
+        } else {
+            mClearDefaultHint.setVisibility(View.GONE);
+        }
+    }
+}
diff --git a/services/java/com/android/server/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
similarity index 70%
rename from services/java/com/android/server/usb/UsbResolverActivity.java
rename to packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index e8a09a5..84d73dd 100644
--- a/services/java/com/android/server/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.usb;
+package com.android.systemui.usb;
 
 import com.android.internal.app.ResolverActivity;
 
@@ -39,6 +39,10 @@
     public static final String TAG = "UsbResolverActivity";
     public static final String EXTRA_RESOLVE_INFOS = "rlist";
 
+    private UsbDevice mDevice;
+    private UsbAccessory mAccessory;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Intent intent = getIntent();
@@ -50,7 +54,6 @@
         }
         Intent target = (Intent)targetParcelable;
         ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
-        Log.d(TAG, "rList.size() " + rList.size());
         CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
         super.onCreate(savedInstanceState, target, title, null, rList,
                 true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
@@ -58,6 +61,27 @@
                          This is necessary because this activity is needed for the user to allow
                          the application permission to access the device */
                 );
+
+        mDevice = (UsbDevice)target.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        if (mDevice != null) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+        } else {
+            mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (mAccessory == null) {
+                Log.e(TAG, "no device or accessory");
+                finish();
+                return;
+            }
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onDestroy();
     }
 
     protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
@@ -65,28 +89,24 @@
             IBinder b = ServiceManager.getService(USB_SERVICE);
             IUsbManager service = IUsbManager.Stub.asInterface(b);
             int uid = ri.activityInfo.applicationInfo.uid;
-            String action = intent.getAction();
 
-            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
-                UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (mDevice != null) {
                 // grant permission for the device
-                service.grantDevicePermission(device, uid);
+                service.grantDevicePermission(mDevice, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setDevicePackage(device, ri.activityInfo.packageName);
+                    service.setDevicePackage(mDevice, ri.activityInfo.packageName);
                 } else {
-                    service.setDevicePackage(device, null);
+                    service.setDevicePackage(mDevice, null);
                 }
-            } else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
-                UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(
-                        UsbManager.EXTRA_ACCESSORY);
+            } else if (mAccessory != null) {
                 // grant permission for the accessory
-                service.grantAccessoryPermission(accessory, uid);
+                service.grantAccessoryPermission(mAccessory, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setAccessoryPackage(accessory, ri.activityInfo.packageName);
+                    service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
                 } else {
-                    service.setAccessoryPackage(accessory, null);
+                    service.setAccessoryPackage(mAccessory, null);
                 }
             }
 
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index adc49ae..3c6c427 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -62,6 +62,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -99,9 +100,6 @@
     /* Chipset supports background scan */
     private final boolean mBackgroundScanSupported;
 
-    // true if the user enabled Wifi while in airplane mode
-    private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
-
     private final LockList mLocks = new LockList();
     // some wifi lock statistics
     private int mFullHighPerfLocksAcquired;
@@ -144,6 +142,14 @@
     private static final String ACTION_DEVICE_IDLE =
             "com.android.server.WifiManager.action.DEVICE_IDLE";
 
+    private static final int WIFI_DISABLED                  = 0;
+    private static final int WIFI_ENABLED                   = 1;
+    /* Wifi enabled while in airplane mode */
+    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
+
+    private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+    private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+
     private boolean mIsReceiverRegistered = false;
 
 
@@ -338,11 +344,11 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        // clear our flag indicating the user has overwridden airplane mode
-                        mAirplaneModeOverwridden.set(false);
-                        // on airplane disable, restore Wifi if the saved state indicates so
-                        if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
-                            persistWifiEnabled(true);
+                        mAirplaneModeOn.set(isAirplaneModeOn());
+                        /* On airplane mode disable, restore wifi state if necessary */
+                        if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
+                            mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+                                persistWifiEnabled(true);
                         }
                         updateWifiState();
                     }
@@ -402,9 +408,10 @@
      * This function is used only at boot time
      */
     public void checkAndStartWifi() {
-        /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
-        boolean wifiEnabled = !isAirplaneModeOn()
-                && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
+        mAirplaneModeOn.set(isAirplaneModeOn());
+        mWifiState.set(getPersistedWifiState());
+        /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
+        boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
         setWifiEnabled(wifiEnabled);
@@ -423,21 +430,39 @@
         return (wifiSavedState == 1);
     }
 
-    private boolean getPersistedWifiEnabled() {
+    private int getPersistedWifiState() {
         final ContentResolver cr = mContext.getContentResolver();
         try {
-            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
+            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
         } catch (Settings.SettingNotFoundException e) {
-            Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
-            return false;
+            Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
+            return WIFI_DISABLED;
+        }
+    }
+
+    private boolean shouldWifiBeEnabled() {
+        if (mAirplaneModeOn.get()) {
+            return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+        } else {
+            return mWifiState.get() != WIFI_DISABLED;
         }
     }
 
     private void persistWifiEnabled(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
-        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
+        if (enabled) {
+            if (isAirplaneModeOn() && isAirplaneToggleable()) {
+                mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+            } else {
+                mWifiState.set(WIFI_ENABLED);
+            }
+        } else {
+            mWifiState.set(WIFI_DISABLED);
+        }
+        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
     }
 
+
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
      * @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -490,11 +515,6 @@
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
 
-        // set a flag if the user is enabling Wifi while in airplane mode
-        if (enable && isAirplaneModeOn() && isAirplaneToggleable()) {
-            mAirplaneModeOverwridden.set(true);
-        }
-
         if (enable) {
             reportStartWorkSource();
         }
@@ -1037,11 +1057,8 @@
     }
 
     private void updateWifiState() {
-        boolean wifiEnabled = getPersistedWifiEnabled();
-        boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
         boolean lockHeld = mLocks.hasLocks();
         int strongestLockMode = WifiManager.WIFI_MODE_FULL;
-        boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
 
         if (lockHeld) {
@@ -1053,11 +1070,11 @@
         }
 
         /* Disable tethering when airplane mode is enabled */
-        if (airplaneMode) {
+        if (mAirplaneModeOn.get()) {
             mWifiStateMachine.setWifiApEnabled(null, false);
         }
 
-        if (wifiShouldBeEnabled) {
+        if (shouldWifiBeEnabled()) {
             if (wifiShouldBeStarted) {
                 reportStartWorkSource();
                 mWifiStateMachine.setWifiEnabled(true);
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 2f22fe1..29e6f94 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -16,11 +16,13 @@
 
 package com.android.server.usb;
 
+import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -602,50 +604,20 @@
     }
 
     public void deviceAttached(UsbDevice device) {
-        Intent deviceIntent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
-        deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        deviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         ArrayList<ResolveInfo> matches;
         String defaultPackage;
         synchronized (mLock) {
-            matches = getDeviceMatchesLocked(device, deviceIntent);
+            matches = getDeviceMatchesLocked(device, intent);
             // Launch our default activity directly, if we have one.
             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
             defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
         }
 
-        int count = matches.size();
-        // don't show the resolver activity if there are no choices available
-        if (count == 0) return;
-
-        if (defaultPackage != null) {
-            for (int i = 0; i < count; i++) {
-                ResolveInfo rInfo = matches.get(i);
-                if (rInfo.activityInfo != null &&
-                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
-                    try {
-                        deviceIntent.setComponent(new ComponentName(
-                                defaultPackage, rInfo.activityInfo.name));
-                        mContext.startActivity(deviceIntent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.e(TAG, "startActivity failed", e);
-                    }
-                    return;
-                }
-            }
-        }
-
-        Intent intent = new Intent(mContext, UsbResolverActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        intent.putExtra(Intent.EXTRA_INTENT, deviceIntent);
-        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
-        try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "unable to start UsbResolverActivity");
-        }
+        resolveActivity(intent, matches, defaultPackage, device, null);
     }
 
     public void deviceDetached(UsbDevice device) {
@@ -656,49 +628,86 @@
     }
 
     public void accessoryAttached(UsbAccessory accessory) {
-        Intent accessoryIntent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
-        accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-        accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         ArrayList<ResolveInfo> matches;
         String defaultPackage;
         synchronized (mLock) {
-            matches = getAccessoryMatchesLocked(accessory, accessoryIntent);
+            matches = getAccessoryMatchesLocked(accessory, intent);
             // Launch our default activity directly, if we have one.
             // Otherwise we will start the UsbResolverActivity to allow the user to choose.
             defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
         }
 
+        resolveActivity(intent, matches, defaultPackage, null, accessory);
+    }
+
+    private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
+            String defaultPackage, UsbDevice device, UsbAccessory accessory) {
         int count = matches.size();
         // don't show the resolver activity if there are no choices available
         if (count == 0) return;
 
-        if (defaultPackage != null) {
-            for (int i = 0; i < count; i++) {
-                ResolveInfo rInfo = matches.get(i);
-                if (rInfo.activityInfo != null &&
-                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
-                    try {
-                        accessoryIntent.setComponent(new ComponentName(
-                                defaultPackage, rInfo.activityInfo.name));
-                        mContext.startActivity(accessoryIntent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.e(TAG, "startActivity failed", e);
-                    }
-                    return;
+        ResolveInfo defaultRI = null;
+        if (count == 1 && defaultPackage == null) {
+            // Check to see if our single choice is on the system partition.
+            // If so, treat it as our default without calling UsbResolverActivity
+            ResolveInfo rInfo = matches.get(0);
+            if (rInfo.activityInfo != null &&
+                    rInfo.activityInfo.applicationInfo != null &&
+                    (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                defaultRI = rInfo;
+                int uid = rInfo.activityInfo.applicationInfo.uid;
+                // grant permission
+                if (device != null) {
+                    grantDevicePermission(device, uid);
+                } else if (accessory != null) {
+                    grantAccessoryPermission(accessory, uid);
                 }
             }
         }
 
-        Intent intent = new Intent(mContext, UsbResolverActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (defaultRI == null && defaultPackage != null) {
+            // look for default activity
+            for (int i = 0; i < count; i++) {
+                ResolveInfo rInfo = matches.get(i);
+                if (rInfo.activityInfo != null &&
+                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
+                    defaultRI = rInfo;
+                    break;
+                }
+            }
+        }
 
-        intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
-        intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
-        try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "unable to start UsbResolverActivity");
+        if (defaultRI != null) {
+            // start default activity directly
+            try {
+                intent.setComponent(
+                        new ComponentName(defaultRI.activityInfo.packageName,
+                                defaultRI.activityInfo.name));
+                mContext.startActivity(intent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "startActivity failed", e);
+            }
+        } else {
+            long identity = Binder.clearCallingIdentity();
+
+            // start UsbResolverActivity so user can choose an activity
+            Intent resolverIntent = new Intent();
+            resolverIntent.setClassName("com.android.systemui",
+                    "com.android.systemui.usb.UsbResolverActivity");
+            resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
+            resolverIntent.putParcelableArrayListExtra("rlist", matches);
+            try {
+                mContext.startActivity(resolverIntent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "unable to start UsbResolverActivity");
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
@@ -709,40 +718,121 @@
         mContext.sendBroadcast(intent);
     }
 
-    public void checkPermission(UsbDevice device) {
-        if (device == null) return;
+    public boolean hasPermission(UsbDevice device) {
         synchronized (mLock) {
-            ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid());
+            ArrayList<DeviceFilter> filterList =
+                    mDevicePermissionMap.get(Binder.getCallingUid());
             if (filterList != null) {
                 int count = filterList.size();
                 for (int i = 0; i < count; i++) {
                     DeviceFilter filter = filterList.get(i);
                     if (filter.equals(device)) {
                         // permission allowed
-                        return;
+                        return true;
                     }
                 }
             }
         }
-        throw new SecurityException("User has not given permission to device " + device);
+        return false;
     }
 
-    public void checkPermission(UsbAccessory accessory) {
-        if (accessory == null) return;
+    public boolean hasPermission(UsbAccessory accessory) {
         synchronized (mLock) {
-            ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
+            ArrayList<AccessoryFilter> filterList =
+                    mAccessoryPermissionMap.get(Binder.getCallingUid());
             if (filterList != null) {
                 int count = filterList.size();
                 for (int i = 0; i < count; i++) {
                     AccessoryFilter filter = filterList.get(i);
                     if (filter.equals(accessory)) {
                         // permission allowed
-                        return;
+                        return true;
                     }
                 }
             }
         }
-        throw new SecurityException("User has not given permission to accessory " + accessory);
+        return false;
+    }
+
+    public void checkPermission(UsbDevice device) {
+        if (!hasPermission(device)) {
+            throw new SecurityException("User has not given permission to device " + device);
+        }
+    }
+
+    public void checkPermission(UsbAccessory accessory) {
+        if (!hasPermission(accessory)) {
+            throw new SecurityException("User has not given permission to accessory " + accessory);
+        }
+    }
+
+    private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
+        int uid = Binder.getCallingUid();
+
+        // compare uid with packageName to foil apps pretending to be someone else
+        try {
+            ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
+            if (aInfo.uid != uid) {
+                throw new IllegalArgumentException("package " + packageName +
+                        " does not match caller's uid " + uid);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException("package " + packageName + " not found");
+        }
+
+        long identity = Binder.clearCallingIdentity();
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.usb.UsbPermissionActivity");
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(Intent.EXTRA_INTENT, pi);
+        intent.putExtra("package", packageName);
+        intent.putExtra("uid", uid);
+        try {
+            mContext.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.e(TAG, "unable to start UsbPermissionActivity");
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
+      Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+      if (hasPermission(device)) {
+            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+            try {
+                pi.send(mContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        // start UsbPermissionActivity so user can choose an activity
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        requestPermissionDialog(intent, packageName, pi);
+    }
+
+    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+      Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+        if (hasPermission(accessory)) {
+            intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+           try {
+                pi.send(mContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        requestPermissionDialog(intent, packageName, pi);
     }
 
     public void setDevicePackage(UsbDevice device, String packageName) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 8170c61..d0a2492 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.usb;
 
+import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -454,6 +455,24 @@
         mDeviceManager.setAccessoryPackage(accessory, packageName);
     }
 
+    public boolean hasDevicePermission(UsbDevice device) {
+        return mDeviceManager.hasPermission(device);
+    }
+
+    public boolean hasAccessoryPermission(UsbAccessory accessory) {
+        return mDeviceManager.hasPermission(accessory);
+    }
+
+    public void requestDevicePermission(UsbDevice device, String packageName,
+            PendingIntent pi) {
+        mDeviceManager.requestPermission(device, packageName, pi);
+    }
+
+    public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
+            PendingIntent pi) {
+        mDeviceManager.requestPermission(accessory, packageName, pi);
+    }
+
     public void grantDevicePermission(UsbDevice device, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         mDeviceManager.grantDevicePermission(device, uid);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index eed41a0..8ccfbba 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4791,13 +4791,17 @@
                 if (maxLayer < ws.mAnimLayer) {
                     maxLayer = ws.mAnimLayer;
                 }
-                final Rect wf = ws.mFrame;
-                final Rect cr = ws.mContentInsets;
-                int left = wf.left + cr.left;
-                int top = wf.top + cr.top;
-                int right = wf.right - cr.right;
-                int bottom = wf.bottom - cr.bottom;
-                frame.union(left, top, right, bottom);
+                
+                // Don't include wallpaper in bounds calculation
+                if (!ws.mIsWallpaper) {
+                    final Rect wf = ws.mFrame;
+                    final Rect cr = ws.mContentInsets;
+                    int left = wf.left + cr.left;
+                    int top = wf.top + cr.top;
+                    int right = wf.right - cr.right;
+                    int bottom = wf.bottom - cr.bottom;
+                    frame.union(left, top, right, bottom);
+                }
             }
             Binder.restoreCallingIdentity(ident);
 
@@ -5460,8 +5464,9 @@
             shortSize = (int)(shortSize/dm.density);
 
             // These semi-magic numbers define our compatibility modes for
-            // applications with different screens.  Don't change unless you
-            // make sure to test lots and lots of apps!
+            // applications with different screens.  These are guarantees to
+            // app developers about the space they can expect for a particular
+            // configuration.  DO NOT CHANGE!
             if (longSize < 470) {
                 // This is shorter than an HVGA normal density screen (which
                 // is 480 pixels on its long side).
@@ -5469,12 +5474,12 @@
                         | Configuration.SCREENLAYOUT_LONG_NO;
             } else {
                 // What size is this screen screen?
-                if (longSize >= 800 && shortSize >= 600) {
-                    // SVGA or larger screens at medium density are the point
+                if (longSize >= 960 && shortSize >= 720) {
+                    // 1.5xVGA or larger screens at medium density are the point
                     // at which we consider it to be an extra large screen.
                     mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
-                } else if (longSize >= 530 && shortSize >= 400) {
-                    // SVGA or larger screens at high density are the point
+                } else if (longSize >= 640 && shortSize >= 480) {
+                    // VGA or larger screens at medium density are the point
                     // at which we consider it to be a large screen.
                     mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
                 } else {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 3be3b1b..bd4e787 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -727,14 +727,14 @@
     };
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Going to sleep.");
 #endif
         android_server_PowerManagerService_goToSleep(when);
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Poking user activity.");
 #endif
         android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
@@ -743,7 +743,7 @@
     if (wmActions & WM_ACTION_PASS_TO_USER) {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
     } else {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
         LOGD("handleInterceptActions: Not passing key to user.");
 #endif
     }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index e7f431c..3c8432e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -58,10 +58,12 @@
             mScaledPaint = new Paint();
             mScaledPaint.setAntiAlias(true);
             mScaledPaint.setTextSize(16.0f);
+            mScaledPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff00ff00);
 
             mSkewPaint = new Paint();
             mSkewPaint.setAntiAlias(true);
-            mSkewPaint.setTextSize(16.0f);            
+            mSkewPaint.setTextSize(16.0f);
+            mSkewPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff000000);
         }
 
         @Override
@@ -106,11 +108,11 @@
             mStrikePaint.setUnderlineText(true);
             
             mSkewPaint.setTextSkewX(-0.25f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 200, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 200, mSkewPaint);
             mSkewPaint.setTextSkewX(0.5f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 230, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 230, mSkewPaint);
             mSkewPaint.setTextSkewX(0.0f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 260, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 260, mSkewPaint);
 
             mScaledPaint.setTextScaleX(0.5f);
             canvas.drawText("Hello OpenGL renderer!", 500, 200, mScaledPaint);
@@ -125,4 +127,4 @@
             canvas.restore();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 6c9f48f..db14e53 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -28,10 +28,12 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
 
 /**
  * Delegate implementing the native methods of android.graphics.Path
@@ -331,58 +333,91 @@
 
     @LayoutlibDelegate
     /*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addOval is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                oval.left, oval.top, oval.width(), oval.height()), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addCircle is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Ellipse2D.Float(
+                x - radius, y - radius, radius * 2, radius * 2), false);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addArc(int nPath, RectF oval,
             float startAngle, float sweepAngle) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addArc is not supported.", null, null /*data*/);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        // because x/y is the center of the circle, need to offset this by the radius
+        pathDelegate.mPath.append(new Arc2D.Float(
+                oval.left, oval.top, oval.width(), oval.height(),
+                startAngle, sweepAngle, Arc2D.OPEN), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF rect,
-            float rx, float ry, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(
+            int nPath, RectF rect, float rx, float ry, int dir) {
+
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return;
+        }
+
+        pathDelegate.mPath.append(new RoundRectangle2D.Float(
+                rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addRoundRect is not supported.", null, null /*data*/);
+    /*package*/ static void native_addRoundRect(int nPath, RectF rect, float[] radii, int dir) {
+        // Java2D doesn't support different rounded corners in each corner, so just use the
+        // first value.
+        native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+
+        // there can be a case where this API is used but with similar values for all corners, so
+        // in that case we don't warn.
+        // we only care if 2 corners are different so just compare to the next one.
+        for (int i = 0 ; i < 3 ; i++) {
+            if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
+                Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                        "Different corner sizes are not supported in Path.addRoundRect.",
+                        null, null /*data*/);
+                break;
+            }
+        }
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src) {
-        native_addPath(nPath, src, 0, 0);
+        addPath(nPath, src, null /*transform*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_addPath(int nPath, int src, int matrix) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.addPath is not supported.", null, null /*data*/);
+        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+        if (matrixDelegate == null) {
+            return;
+        }
+
+        addPath(nPath, src, matrixDelegate.getAffineTransform());
     }
 
     @LayoutlibDelegate
@@ -487,6 +522,26 @@
         return null;
     }
 
+    private static void addPath(int destPath, int srcPath, AffineTransform transform) {
+        Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
+        if (destPathDelegate == null) {
+            return;
+        }
+
+        Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
+        if (srcPathDelegate == null) {
+            return;
+        }
+
+        if (transform != null) {
+            destPathDelegate.mPath.append(
+                    srcPathDelegate.mPath.getPathIterator(transform), false);
+        } else {
+            destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
+        }
+    }
+
+
     /**
      * Returns whether the path is empty.
      * @return true if the path is empty.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index acc7379..e6e9647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -192,7 +192,7 @@
                 Capability.UNBOUND_RENDERING,
                 Capability.CUSTOM_BACKGROUND_COLOR,
                 Capability.RENDER,
-                Capability.LAYOUT_ONLY,
+                //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
                 Capability.EMBEDDED_LAYOUT,
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index c1d7600..138a455 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -412,9 +412,7 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
@@ -486,23 +484,32 @@
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
-        }
-
-        if (RenderResources.REFERENCE_NULL.equals(s)) {
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
             return defValue;
         }
 
-        // FIXME huh?
+        if (ResourceHelper.stringToFloat(s, mValue)) {
+            float f = mValue.getDimension(mBridgeResources.mMetrics);
 
-        float f = getDimension(index, defValue);
-        final int res = (int)(f+0.5f);
-        if (res != 0) return res;
-        if (f == 0) return 0;
-        if (f > 0) return 1;
+            if (f < 0) {
+                // negative values are not allowed in pixel dimensions
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Negative pixel dimension: " + s,
+                        null, null /*data*/);
+                return defValue;
+            }
 
-        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
-                "Can't convert to dimension: " + Integer.toString(index),
-                null, null /*data*/);
+            if (f == 0) return 0;
+            if (f < 1) return 1;
+
+            return (int)(f+0.5f);
+        }
+
+        // looks like we were unable to resolve the dimension value
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                    s, mNames[index]), null /*data*/);
 
         return defValue;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 69f46e6..649160e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -377,7 +377,7 @@
         }
 
         // check the first character
-        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+        if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
             return false;
         }