Merge "Document that degenerate lines wont be drawn" into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index a4b4992..3878aa1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9036,12 +9036,12 @@
     ctor public Picture();
     ctor public Picture(android.graphics.Picture);
     method public android.graphics.Canvas beginRecording(int, int);
-    method public static android.graphics.Picture createFromStream(java.io.InputStream);
+    method public static deprecated android.graphics.Picture createFromStream(java.io.InputStream);
     method public void draw(android.graphics.Canvas);
     method public void endRecording();
     method public int getHeight();
     method public int getWidth();
-    method public void writeToStream(java.io.OutputStream);
+    method public deprecated void writeToStream(java.io.OutputStream);
   }
 
   public class PixelFormat {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 1bada67..d9846ec 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -25,6 +25,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Provides access to environment variables.
@@ -36,12 +37,16 @@
     private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE";
     private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
     private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
+    private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
 
     /** {@hide} */
     public static String DIRECTORY_ANDROID = "Android";
 
-    private static final File ROOT_DIRECTORY
-            = getDirectory("ANDROID_ROOT", "/system");
+    private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
+    private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
+
+    private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull(
+            ENV_EMULATED_STORAGE_TARGET);
 
     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
 
@@ -178,7 +183,7 @@
      * Gets the Android root directory.
      */
     public static File getRootDirectory() {
-        return ROOT_DIRECTORY;
+        return DIR_ANDROID_ROOT;
     }
 
     /**
@@ -632,6 +637,19 @@
         return path == null ? new File(defaultPath) : new File(path);
     }
 
+    private static String getCanonicalPathOrNull(String variableName) {
+        String path = System.getenv(variableName);
+        if (path == null) {
+            return null;
+        }
+        try {
+            return new File(path).getCanonicalPath();
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to resolve canonical path for " + path);
+            return null;
+        }
+    }
+
     private static void throwIfSystem() {
         if (Process.myUid() == Process.SYSTEM_UID) {
             Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
@@ -649,4 +667,40 @@
         }
         return cur;
     }
+
+    /**
+     * If the given path exists on emulated external storage, return the
+     * translated backing path hosted on internal storage. This bypasses any
+     * emulation later, improving performance. This is <em>only</em> suitable
+     * for read-only access.
+     * <p>
+     * Returns original path if given path doesn't meet these criteria. Callers
+     * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
+     * permission.
+     *
+     * @hide
+     */
+    public static File maybeTranslateEmulatedPathToInternal(File path) {
+        // Fast return if not emulated, or missing variables
+        if (!Environment.isExternalStorageEmulated()
+                || CANONCIAL_EMULATED_STORAGE_TARGET == null) {
+            return path;
+        }
+
+        try {
+            final String rawPath = path.getCanonicalPath();
+            if (rawPath.startsWith(CANONCIAL_EMULATED_STORAGE_TARGET)) {
+                final File internalPath = new File(DIR_MEDIA_STORAGE,
+                        rawPath.substring(CANONCIAL_EMULATED_STORAGE_TARGET.length()));
+                if (internalPath.exists()) {
+                    return internalPath;
+                }
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to resolve canonical path for " + path);
+        }
+
+        // Unable to translate to internal path; use original
+        return path;
+    }
 }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0ab49ac..d901d0a 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1114,6 +1114,11 @@
      * false. See also {@link #setDatabasePath} for how to correctly set up the
      * database storage API.
      *
+     * This setting is global in effect, across all WebView instances in a process.
+     * Note you should only modify this setting prior to making <b>any</b> WebView
+     * page load within a given process, as the WebView implementation may ignore
+     * changes to this setting after that point.
+     *
      * @param flag true if the WebView should use the database storage API
      */
     public synchronized void setDatabaseEnabled(boolean flag) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f3983187..175cbcb 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -208,8 +208,7 @@
  * and default scaling is not applied to the web page; if the value is "1.5", then the device is
  * considered a high density device (hdpi) and the page content is scaled 1.5x; if the
  * value is "0.75", then the device is considered a low density device (ldpi) and the content is
- * scaled 0.75x. However, if you specify the {@code "target-densitydpi"} meta property
- * (discussed below), then you can stop this default scaling behavior.</li>
+ * scaled 0.75x.</li>
  * <li>The {@code -webkit-device-pixel-ratio} CSS media query. Use this to specify the screen
  * densities for which this style sheet is to be used. The corresponding value should be either
  * "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium
@@ -219,29 +218,6 @@
  * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
  * which is the high density pixel ratio.</p>
  * </li>
- * <li>The {@code target-densitydpi} property for the {@code viewport} meta tag. You can use
- * this to specify the target density for which the web page is designed, using the following
- * values:
- * <ul>
- * <li>{@code device-dpi} - Use the device's native dpi as the target dpi. Default scaling never
- * occurs.</li>
- * <li>{@code high-dpi} - Use hdpi as the target dpi. Medium and low density screens scale down
- * as appropriate.</li>
- * <li>{@code medium-dpi} - Use mdpi as the target dpi. High density screens scale up and
- * low density screens scale down. This is also the default behavior.</li>
- * <li>{@code low-dpi} - Use ldpi as the target dpi. Medium and high density screens scale up
- * as appropriate.</li>
- * <li><em>{@code <value>}</em> - Specify a dpi value to use as the target dpi (accepted
- * values are 70-400).</li>
- * </ul>
- * <p>Here's an example meta tag to specify the target density:</p>
- * <pre>&lt;meta name="viewport" content="target-densitydpi=device-dpi" /&gt;</pre></li>
- * </ul>
- * <p>If you want to modify your web page for different densities, by using the {@code
- * -webkit-device-pixel-ratio} CSS media query and/or the {@code
- * window.devicePixelRatio} DOM property, then you should set the {@code target-densitydpi} meta
- * property to {@code device-dpi}. This stops Android from performing scaling in your web page and
- * allows you to make the necessary adjustments for each density via CSS and JavaScript.</p>
  *
  * <h3>HTML5 Video support</h3>
  *
diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java
index 0c6b780..cf69a9d 100644
--- a/core/java/com/android/internal/view/ActionBarPolicy.java
+++ b/core/java/com/android/internal/view/ActionBarPolicy.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Build;
@@ -44,7 +45,10 @@
     }
 
     public boolean showsOverflowMenuButton() {
-        return !ViewConfiguration.get(mContext).hasPermanentMenuKey();
+        return !ViewConfiguration.get(mContext).hasPermanentMenuKey() ||
+                ((mContext.getResources().getConfiguration().uiMode &
+                        Configuration.UI_MODE_TYPE_TELEVISION) ==
+                        Configuration.UI_MODE_TYPE_TELEVISION);
     }
 
     public int getEmbeddedMenuWidthLimit() {
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0df8638..b4c4a1b 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -166,7 +166,7 @@
 
     struct Stats stats;
     memset(&stats, 0, sizeof(Stats));
-    if (parseIfaceStats(NULL, &stats) == 0) {
+    if (parseIfaceStats(iface8.c_str(), &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
         return UNKNOWN;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 91688db..9bb90f1 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1566,6 +1566,10 @@
      * Save the canvas state, draw the picture, and restore the canvas state.
      * This differs from picture.draw(canvas), which does not perform any
      * save/restore.
+     *
+     * <p>
+     * <strong>Note:</strong> This forces the picture to internally call
+     * {@link Picture#endRecording} in order to prepare for playback.
      * 
      * @param picture  The picture to be drawn
      */
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 997141d..71e02f6 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -20,13 +20,12 @@
 import java.io.OutputStream;
 
 /**
- * A picture records drawing calls (via the canvas returned by beginRecording)
- * and can then play them back (via picture.draw(canvas) or canvas.drawPicture).
- * The picture's contents can also be written to a stream, and then later
- * restored to a new picture (via writeToStream / createFromStream). For most
- * content (esp. text, lines, rectangles), drawing a sequence from a picture can
- * be faster than the equivalent API calls, since the picture performs its
- * playback without incurring any java-call overhead.
+ * A Picture records drawing calls (via the canvas returned by beginRecording)
+ * and can then play them back into Canvas (via {@link Picture#draw(Canvas)} or 
+ * {@link Canvas#drawPicture(Picture)}).For most content (e.g. text, lines, rectangles),
+ * drawing a sequence from a picture can be faster than the equivalent API
+ * calls, since the picture performs its playback without incurring any
+ * method-call overhead.
  */
 public class Picture {
     private Canvas mRecordingCanvas;
@@ -39,6 +38,9 @@
 
     private static final int WORKING_STREAM_STORAGE = 16 * 1024;
 
+    /**
+     * Creates an empty picture that is ready to record.
+     */
     public Picture() {
         this(nativeConstructor(0), false);
     }
@@ -55,9 +57,10 @@
     /**
      * To record a picture, call beginRecording() and then draw into the Canvas
      * that is returned. Nothing we appear on screen, but all of the draw
-     * commands (e.g. drawRect(...)) will be recorded. To stop recording, call
-     * endRecording(). At this point the Canvas that was returned must no longer
-     * be referenced, and nothing should be drawn into it.
+     * commands (e.g. {@link Canvas#drawRect(Rect, Paint)}) will be recorded.
+     * To stop recording, call endRecording(). After endRecording() the Canvas
+     * that was returned must no longer be used, and nothing should be drawn
+     * into it.
      */
     public Canvas beginRecording(int width, int height) {
         int ni = nativeBeginRecording(mNativePicture, width, height);
@@ -68,8 +71,8 @@
     /**
      * Call endRecording when the picture is built. After this call, the picture
      * may be drawn, but the canvas that was returned by beginRecording must not
-     * be referenced anymore. This is automatically called if Picture.draw() or
-     * Canvas.drawPicture() is called.
+     * be used anymore. This is automatically called if {@link Picture#draw}
+     * or {@link Canvas#drawPicture(Picture)} is called.
      */
     public void endRecording() {
         if (mRecordingCanvas != null) {
@@ -94,6 +97,10 @@
      * Draw this picture on the canvas. The picture may have the side effect
      * of changing the matrix and clip of the canvas.
      * 
+     * <p>
+     * <strong>Note:</strong> This forces the picture to internally call
+     * {@link Picture#endRecording()} in order to prepare for playback.
+     *
      * @param canvas  The picture is drawn to this canvas 
      */
     public void draw(Canvas canvas) {
@@ -105,26 +112,39 @@
 
     /**
      * Create a new picture (already recorded) from the data in the stream. This
-     * data was generated by a previous call to writeToStream().
-     * 
+     * data was generated by a previous call to writeToStream(). Pictures that
+     * have been persisted across device restarts are not guaranteed to decode
+     * properly and are highly discouraged.
+     *
+     * <p>
      * <strong>Note:</strong> a picture created from an input stream cannot be
      * replayed on a hardware accelerated canvas.
      * 
-     * @see #writeToStream(java.io.OutputStream) 
+     * @see #writeToStream(java.io.OutputStream)
+     * @deprecated The recommended alternative is to not use writeToStream and
+     * instead draw the picture into a Bitmap from which you can persist it as
+     * raw or compressed pixels.
      */
+    @Deprecated
     public static Picture createFromStream(InputStream stream) {
         return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]), true);
     }
 
     /**
      * Write the picture contents to a stream. The data can be used to recreate
-     * the picture in this or another process by calling createFromStream.
+     * the picture in this or another process by calling createFromStream(...)
+     * The resulting stream is NOT to be persisted across device restarts as
+     * there is no guarantee that the Picture can be successfully reconstructed.
      *
+     * <p>
      * <strong>Note:</strong> a picture created from an input stream cannot be
      * replayed on a hardware accelerated canvas.
-     * 
-     * @see #createFromStream(java.io.InputStream) 
+     *
+     * @see #createFromStream(java.io.InputStream)
+     * @deprecated The recommended alternative is to draw the picture into a
+     * Bitmap from which you can persist it as raw or compressed pixels.
      */
+    @Deprecated
     public void writeToStream(OutputStream stream) {
         // do explicit check before calling the native method
         if (stream == null) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 5befb95..a1cc2e8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -50,9 +50,9 @@
 Caches::Caches(): Singleton<Caches>(), mExtensions(Extensions::getInstance()), mInitialized(false) {
     init();
     initFont();
-    initExtensions();
     initConstraints();
     initProperties();
+    initExtensions();
 
     mDebugLevel = readDebugLevel();
     ALOGD("Enabling debug mode %d", mDebugLevel);
@@ -103,15 +103,21 @@
 void Caches::initExtensions() {
     if (mExtensions.hasDebugMarker()) {
         eventMark = glInsertEventMarkerEXT;
-        startMark = glPushGroupMarkerEXT;
-        endMark = glPopGroupMarkerEXT;
+        if ((drawDeferDisabled || drawReorderDisabled)) {
+            startMark = glPushGroupMarkerEXT;
+            endMark = glPopGroupMarkerEXT;
+        } else {
+            startMark = startMarkNull;
+            endMark = endMarkNull;
+        }
+
     } else {
         eventMark = eventMarkNull;
         startMark = startMarkNull;
         endMark = endMarkNull;
     }
 
-    if (mExtensions.hasDebugLabel()) {
+    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
         setLabel = glLabelObjectEXT;
         getLabel = glGetObjectLabelEXT;
     } else {
@@ -164,6 +170,20 @@
         debugStencilClip = kStencilHide;
     }
 
+    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
+        drawDeferDisabled = !strcasecmp(property, "true");
+        INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
+    } else {
+        INIT_LOGD("  Draw defer enabled");
+    }
+
+    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
+        drawReorderDisabled = !strcasecmp(property, "true");
+        INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
+    } else {
+        INIT_LOGD("  Draw reorder enabled");
+    }
+
     return (prevDebugLayersUpdates != debugLayersUpdates) ||
             (prevDebugOverdraw != debugOverdraw) ||
             (prevDebugStencilClip != debugStencilClip);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index c35ad883..ca699d5 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -240,6 +240,9 @@
     Program* currentProgram;
     bool scissorEnabled;
 
+    bool drawDeferDisabled;
+    bool drawReorderDisabled;
+
     // VBO to draw with
     GLuint meshBuffer;
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 8962964..a4e9950 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -146,6 +146,8 @@
     if (isEmpty()) return status; // nothing to flush
 
     DEFER_LOGD("--flushing");
+    renderer.eventMark("Flush");
+
     DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
     int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     int opCount = 0;
@@ -166,6 +168,7 @@
     }
 
     DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
+
     renderer.restoreToCount(restoreTo);
     renderer.setDrawModifiers(restoreDrawModifiers);
     clear();
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 9ecfb5a..4a72477 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -147,7 +147,8 @@
 
         if (!renderer.storeDisplayState(state)) {
             // op wasn't quick-rejected, so defer
-            deferredList->add(this, renderer.disallowReorder());
+            deferredList->add(this, renderer.getCaches().drawReorderDisabled);
+            onDrawOpDeferred(renderer);
         }
 
         return DrawGlInfo::kStatusDone;
@@ -156,6 +157,9 @@
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
             bool caching, int multipliedAlpha) = 0;
 
+    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+    }
+
     // returns true if bounds exist
     virtual bool getLocalBounds(Rect& localBounds) { return false; }
 
@@ -1081,6 +1085,12 @@
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
+    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+        SkPaint* paint = getPaint(renderer);
+        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, mText, mCount, mat4::identity());
+    }
+
     virtual DeferredDisplayList::OpBatchId getBatchId() {
         return mPaint->getColor() == 0xff000000 ?
                 DeferredDisplayList::kOpBatch_Text :
@@ -1156,6 +1166,19 @@
         mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
     }
 
+    /*
+     * When this method is invoked the state field  is initialized to have the
+     * final rendering state. We can thus use it to process data as it will be
+     * used at draw time.
+     */
+    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+        SkPaint* paint = getPaint(renderer);
+        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
+        const bool pureTranslate = state.mMatrix.isPureTranslate();
+        fontRenderer.precache(paint, mText, mCount,
+                pureTranslate ? mat4::identity() : state.mMatrix);
+    }
+
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
             bool caching, int multipliedAlpha) {
         return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 16218fa..b011443 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -403,11 +403,7 @@
 
     DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
             hOffset, vOffset, paint);
-    if (addDrawOp(op)) {
-        // precache if draw operation is visible
-        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
-        fontRenderer.precache(paint, text, count, mat4::identity());
-    }
+    addDrawOp(op);
     return DrawGlInfo::kStatusDone;
 }
 
@@ -420,11 +416,7 @@
     paint = refPaint(paint);
 
     DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
-    if (addDrawOp(op)) {
-        // precache if draw operation is visible
-        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
-        fontRenderer.precache(paint, text, count, mat4::identity());
-    }
+    addDrawOp(op);
     return DrawGlInfo::kStatusDone;
 }
 
@@ -439,13 +431,7 @@
     paint = refPaint(paint);
 
     DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count, x, y, positions, paint, length);
-    if (addDrawOp(op)) {
-        // precache if draw operation is visible
-        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
-        const bool pureTranslate = mSnapshot->transform->isPureTranslate();
-        fontRenderer.precache(paint, text, count,
-                pureTranslate ? mat4::identity() : *mSnapshot->transform);
-    }
+    addDrawOp(op);
     return DrawGlInfo::kStatusDone;
 }
 
@@ -515,17 +501,15 @@
     addOpInternal(op);
 }
 
-bool DisplayListRenderer::addDrawOp(DrawOp* op) {
-    bool rejected = false;
+void DisplayListRenderer::addDrawOp(DrawOp* op) {
     Rect localBounds;
     if (op->getLocalBounds(localBounds)) {
-        rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
+        bool rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
                 localBounds.right, localBounds.bottom);
         op->setQuickRejected(rejected);
     }
     mHasDrawOps = true;
     addOpInternal(op);
-    return !rejected;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index bff3b97..38619bf 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -195,7 +195,7 @@
 
     LinearAllocator& alloc() { return mDisplayListData->allocator; }
     void addStateOp(StateOp* op);
-    bool addDrawOp(DrawOp* op); // returns true if op not rejected
+    void addDrawOp(DrawOp* op);
     void addOpInternal(DisplayListOp* op) {
         insertRestoreToCount();
         insertTranslate();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7e9734f..ff6f332 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -122,8 +122,6 @@
     mFirstSnapshot = new Snapshot;
 
     mScissorOptimizationDisabled = false;
-    mDrawDeferDisabled = false;
-    mDrawReorderDisabled = false;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -140,20 +138,6 @@
     } else {
         INIT_LOGD("  Scissor optimization enabled");
     }
-
-    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
-        mDrawDeferDisabled = !strcasecmp(property, "true");
-        INIT_LOGD("  Draw defer %s", mDrawDeferDisabled ? "disabled" : "enabled");
-    } else {
-        INIT_LOGD("  Draw defer enabled");
-    }
-
-    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
-        mDrawReorderDisabled = !strcasecmp(property, "true");
-        INIT_LOGD("  Draw reorder %s", mDrawReorderDisabled ? "disabled" : "enabled");
-    } else {
-        INIT_LOGD("  Draw reorder enabled");
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -462,6 +446,10 @@
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
 
+void OpenGLRenderer::eventMark(const char* name) const {
+    mCaches.eventMark(0, name);
+}
+
 void OpenGLRenderer::startMark(const char* name) const {
     mCaches.startMark(0, name);
 }
@@ -1815,7 +1803,7 @@
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
-        if (CC_UNLIKELY(mDrawDeferDisabled)) {
+        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             return displayList->replay(*this, dirty, flags, 0);
         }
 
@@ -2710,7 +2698,7 @@
     setupDrawShaderUniforms(!isPerspective);
     setupDrawTextGammaUniforms();
 
-    const Rect* clip = mSnapshot->hasPerspectiveTransform() ? NULL : mSnapshot->clipRect;
+    const Rect* clip = isPerspective ? NULL : mSnapshot->clipRect;
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     const bool hasActiveLayer = hasLayer();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index cfad593..1bfd3c0 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -270,8 +270,6 @@
                 (mSnapshot->flags & Snapshot::kFlagFboTarget); // ensure we're not in a layer
     }
 
-    bool disallowReorder() { return mDrawReorderDisabled; }
-
     bool storeDisplayState(DeferredDisplayState& state);
     void restoreDisplayState(const DeferredDisplayState& state);
 
@@ -282,6 +280,10 @@
         return mSnapshot->transform->isSimple();
     }
 
+    Caches& getCaches() {
+        return mCaches;
+    }
+
     /**
      * Sets the alpha on the current snapshot. This alpha value will be modulated
      * with other alpha values when drawing primitives.
@@ -291,6 +293,11 @@
     }
 
     /**
+     * Inserts a named event marker in the stream of GL commands.
+     */
+    void eventMark(const char* name) const;
+
+    /**
      * Inserts a named group marker in the stream of GL commands. This marker
      * can be used by tools to group commands into logical groups. A call to
      * this method must always be followed later on by a call to endMark().
@@ -439,10 +446,6 @@
         return false;
     }
 
-    Caches& getCaches() {
-        return mCaches;
-    }
-
 private:
     /**
      * Discards the content of the framebuffer if supported by the driver.
@@ -957,8 +960,6 @@
     // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in
     // Properties.h
     bool mScissorOptimizationDisabled;
-    bool mDrawDeferDisabled;
-    bool mDrawReorderDisabled;
 
     // No-ops start/endTiling when set
     bool mSuppressTiling;
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index d48b612..bf522b7 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -57,6 +57,9 @@
     mLookupTransform[SkMatrix::kMScaleY] = matrix.data[mat4::kScaleY];
     mLookupTransform[SkMatrix::kMSkewX] = matrix.data[mat4::kSkewX];
     mLookupTransform[SkMatrix::kMSkewY] = matrix.data[mat4::kSkewY];
+    if (!mLookupTransform.invert(&mInverseLookupTransform)) {
+        ALOGW("Could not query the inverse lookup transform for this font");
+    }
 }
 
 Font::~Font() {
@@ -184,18 +187,13 @@
 
 void Font::drawCachedGlyphPerspective(CachedGlyphInfo* glyph, int x, int y,
         uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
-    SkMatrix i;
-    if (!mDescription.mLookupTransform.invert(&i)) {
-        return;
-    }
-
     SkPoint p[4];
-    p[0].set(glyph->mBitmapLeft, glyph->mBitmapTop + glyph->mBitmapHeight);
-    p[1].set(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop + glyph->mBitmapHeight);
-    p[2].set(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop);
-    p[3].set(glyph->mBitmapLeft, glyph->mBitmapTop);
+    p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + glyph->mBitmapHeight);
+    p[1].iset(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop + glyph->mBitmapHeight);
+    p[2].iset(glyph->mBitmapLeft + glyph->mBitmapWidth, glyph->mBitmapTop);
+    p[3].iset(glyph->mBitmapLeft, glyph->mBitmapTop);
 
-    i.mapPoints(p, 4);
+    mDescription.mInverseLookupTransform.mapPoints(p, 4);
 
     p[0].offset(x, y);
     p[1].offset(x, y);
@@ -208,10 +206,10 @@
     float v2 = glyph->mBitmapMaxV;
 
     mState->appendRotatedMeshQuad(
-            p[0].fX, p[0].fY, u1, v2,
-            p[1].fX, p[1].fY, u2, v2,
-            p[2].fX, p[2].fY, u2, v1,
-            p[3].fX, p[3].fY, u1, v1, glyph->mCacheTexture);
+            p[0].x(), p[0].y(), u1, v2,
+            p[1].x(), p[1].y(), u2, v2,
+            p[2].x(), p[2].y(), u2, v1,
+            p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
 }
 
 void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
@@ -265,14 +263,14 @@
     const float v2 = glyph->mBitmapMaxV;
 
     mState->appendRotatedMeshQuad(
-            position->fX + destination[0].fX,
-            position->fY + destination[0].fY, u1, v2,
-            position->fX + destination[1].fX,
-            position->fY + destination[1].fY, u2, v2,
-            position->fX + destination[2].fX,
-            position->fY + destination[2].fY, u2, v1,
-            position->fX + destination[3].fX,
-            position->fY + destination[3].fY, u1, v1,
+            position->x() + destination[0].x(),
+            position->y() + destination[0].y(), u1, v2,
+            position->x() + destination[1].x(),
+            position->y() + destination[1].y(), u2, v2,
+            position->x() + destination[2].x(),
+            position->y() + destination[2].y(), u2, v1,
+            position->x() + destination[3].x(),
+            position->y() + destination[3].y(), u1, v1,
             glyph->mCacheTexture);
 }
 
@@ -284,7 +282,8 @@
 
         // Is the glyph still in texture cache?
         if (!cachedGlyph->mIsValid) {
-            const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit, &mDescription.mLookupTransform);
+            const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit,
+                    &mDescription.mLookupTransform);
             updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
         }
     } else {
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 542b552..b2382f4 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -70,6 +70,7 @@
         float mStrokeWidth;
         bool mAntiAliasing;
         SkMatrix mLookupTransform;
+        SkMatrix mInverseLookupTransform;
     };
 
     ~Font();
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 3dcd232..57c87e4 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -7,6 +7,8 @@
     <uses-permission android:name="android.permission.ASEC_DESTROY"/>
     <uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <!-- Used to improve MeasureUtils performance on emulated storage -->
+    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
     <uses-permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" />
 
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 731a09c..de77cac 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -16,16 +16,12 @@
 
 package com.android.defcontainer;
 
-import com.android.internal.app.IMediaContainerService;
-import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.PackageHelper;
-
 import android.app.IntentService;
 import android.content.Intent;
-import android.content.pm.MacAuthenticatedInputStream;
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.IPackageManager;
 import android.content.pm.LimitedLengthInputStream;
+import android.content.pm.MacAuthenticatedInputStream;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
@@ -43,10 +39,16 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.app.IMediaContainerService;
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.PackageHelper;
+
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -228,9 +230,10 @@
         public long calculateDirectorySize(String path) throws RemoteException {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
 
-            final File directory = new File(path);
-            if (directory.exists() && directory.isDirectory()) {
-                return MeasurementUtils.measureDirectory(path);
+            final File dir = Environment.maybeTranslateEmulatedPathToInternal(new File(path));
+            if (dir.exists() && dir.isDirectory()) {
+                final String targetPath = dir.getAbsolutePath();
+                return MeasurementUtils.measureDirectory(targetPath);
             } else {
                 return 0L;
             }
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index e2d9d6e..f337600 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -46,6 +46,7 @@
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
+                android:layout_gravity="left"
                 android:orientation="horizontal">
             </LinearLayout>
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a766bad..d8bcf2cd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7419,29 +7419,63 @@
         SystemProperties.set("ctl.start", "bugreport");
     }
 
+    public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+        return r != null ? getInputDispatchingTimeoutLocked(r.app) : KEY_DISPATCHING_TIMEOUT;
+    }
+
+    public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
+        if (r != null && (r.instrumentationClass != null || r.usingWrapper)) {
+            return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
+        }
+        return KEY_DISPATCHING_TIMEOUT;
+    }
+
+
     public long inputDispatchingTimedOut(int pid, final boolean aboveSystem) {
         if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.FILTER_EVENTS);
         }
-
         ProcessRecord proc;
-
-        // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut().
+        long timeout;
         synchronized (this) {
             synchronized (mPidsSelfLocked) {
                 proc = mPidsSelfLocked.get(pid);
             }
-            if (proc != null) {
+            timeout = getInputDispatchingTimeoutLocked(proc);
+        }
+
+        if (!inputDispatchingTimedOut(proc, null, null, aboveSystem)) {
+            return -1;
+        }
+
+        return timeout;
+    }
+
+    /**
+     * Handle input dispatching timeouts.
+     * Returns whether input dispatching should be aborted or not.
+     */
+    public boolean inputDispatchingTimedOut(final ProcessRecord proc,
+            final ActivityRecord activity, final ActivityRecord parent,
+            final boolean aboveSystem) {
+        if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.FILTER_EVENTS);
+        }
+
+        if (proc != null) {
+            synchronized (this) {
                 if (proc.debugging) {
-                    return -1;
+                    return false;
                 }
 
                 if (mDidDexOpt) {
                     // Give more time since we were dexopting.
                     mDidDexOpt = false;
-                    return -1;
+                    return false;
                 }
 
                 if (proc.instrumentationClass != null) {
@@ -7449,25 +7483,18 @@
                     info.putString("shortMsg", "keyDispatchingTimedOut");
                     info.putString("longMsg", "Timed out while dispatching key event");
                     finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
-                    proc = null;
+                    return true;
                 }
             }
-        }
-
-        if (proc != null) {
-            final ProcessRecord pr = proc;
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    appNotResponding(pr, null, null, aboveSystem, "keyDispatchingTimedOut");
+                    appNotResponding(proc, activity, parent, aboveSystem, "keyDispatchingTimedOut");
                 }
             });
-            if (proc.instrumentationClass != null || proc.usingWrapper) {
-                return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
-            }
         }
 
-        return KEY_DISPATCHING_TIMEOUT;
+        return true;
     }
 
     public Bundle getTopActivityExtras(int requestType) {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index cde17c9..054d213 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -867,51 +867,20 @@
     }
 
     public boolean keyDispatchingTimedOut() {
-        // TODO: Unify this code with ActivityManagerService.inputDispatchingTimedOut().
         ActivityRecord r;
-        ProcessRecord anrApp = null;
+        ProcessRecord anrApp;
         synchronized(service) {
             r = getWaitingHistoryRecordLocked();
-            if (r != null && r.app != null) {
-                if (r.app.debugging) {
-                    return false;
-                }
-                
-                if (service.mDidDexOpt) {
-                    // Give more time since we were dexopting.
-                    service.mDidDexOpt = false;
-                    return false;
-                }
-                
-                if (r.app.instrumentationClass == null) { 
-                    anrApp = r.app;
-                } else {
-                    Bundle info = new Bundle();
-                    info.putString("shortMsg", "keyDispatchingTimedOut");
-                    info.putString("longMsg", "Timed out while dispatching key event");
-                    service.finishInstrumentationLocked(
-                            r.app, Activity.RESULT_CANCELED, info);
-                }
-            }
+            anrApp = r != null ? r.app : null;
         }
-        
-        if (anrApp != null) {
-            service.appNotResponding(anrApp, r, this, false, "keyDispatchingTimedOut");
-        }
-        
-        return true;
+        return service.inputDispatchingTimedOut(anrApp, r, this, false);
     }
     
     /** Returns the key dispatching timeout for this application token. */
     public long getKeyDispatchingTimeout() {
         synchronized(service) {
             ActivityRecord r = getWaitingHistoryRecordLocked();
-            if (r != null && r.app != null
-                    && (r.app.instrumentationClass != null || r.app.usingWrapper)) {
-                return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
-            }
-
-            return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
+            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 28f6bb2..900a38a 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1378,7 +1378,7 @@
     private static final String FLAGS_STR = "flags=";
     private static final String SSID_STR = "ssid=";
     private static final String DELIMITER_STR = "====";
-    private static final int SCAN_BUF_RANGE = 3900;
+    private static final String END_STR = "####";
 
     /**
      * Format:
@@ -1417,11 +1417,12 @@
             if (TextUtils.isEmpty(tmpResults)) break;
             scanResultsBuf.append(tmpResults);
             scanResultsBuf.append("\n");
-            if (tmpResults.length() < SCAN_BUF_RANGE) break;
             String[] lines = tmpResults.split("\n");
             sid = -1;
             for (int i=lines.length - 1; i >= 0; i--) {
-                if (lines[i].startsWith(ID_STR)) {
+                if (lines[i].startsWith(END_STR)) {
+                    break;
+                } else if (lines[i].startsWith(ID_STR)) {
                     try {
                         sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
                     } catch (NumberFormatException e) {
@@ -1472,7 +1473,7 @@
                 } else if (line.startsWith(SSID_STR)) {
                     wifiSsid = WifiSsid.createFromAsciiEncoded(
                             line.substring(SSID_STR.length()));
-                } else if (line.startsWith(DELIMITER_STR)) {
+                } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
                     if (bssid != null) {
                         String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
                         String key = bssid + ssid;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index b6bbfc4..1ba991e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -155,6 +155,7 @@
     /** copy constructor */
     public WifiP2pWfdInfo(WifiP2pWfdInfo source) {
         if (source != null) {
+            mWfdEnabled = source.mWfdEnabled;
             mDeviceInfo = source.mDeviceInfo;
             mCtrlPort = source.mCtrlPort;
             mMaxThroughput = source.mMaxThroughput;