Merge "Remove defunct flag"
diff --git a/api/current.txt b/api/current.txt
index fd901f2f..52900c9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27211,7 +27211,6 @@
     method public final java.lang.CharSequence coerceToString();
     method public static final java.lang.String coerceToString(int, int);
     method public static float complexToDimension(int, android.util.DisplayMetrics);
-    method public static float complexToDimensionNoisy(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelOffset(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelSize(int, android.util.DisplayMetrics);
     method public static float complexToFloat(int);
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 22322e3..f532f7c 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -457,8 +457,10 @@
                     mSocket.close();
                     mSocket = null;
                 }
-                if(mPfd != null)
-                    mPfd.detachFd();
+                if (mPfd != null) {
+                    mPfd.close();
+                    mPfd = null;
+                }
            }
         }
     }
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 60ccc61..433d5d1c 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -738,14 +738,16 @@
         File dir = file.getParentFile();
         if (dir != null) {
             final String prefix = file.getName() + "-mj";
-            final FileFilter filter = new FileFilter() {
+            File[] files = dir.listFiles(new FileFilter() {
                 @Override
                 public boolean accept(File candidate) {
                     return candidate.getName().startsWith(prefix);
                 }
-            };
-            for (File masterJournal : dir.listFiles(filter)) {
-                deleted |= masterJournal.delete();
+            });
+            if (files != null) {
+                for (File masterJournal : files) {
+                    deleted |= masterJournal.delete();
+                }
             }
         }
         return deleted;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1ce958b..2afea1f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.telephony.SignalStrength;
+import android.text.format.DateFormat;
 import android.util.Printer;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -895,6 +896,11 @@
     public abstract long getNetworkActivityPackets(int type, int which);
 
     /**
+     * Return the wall clock time when battery stats data collection started.
+     */
+    public abstract long getStartClockTime();
+
+    /**
      * Return whether we are currently running on battery.
      */
     public abstract boolean getIsOnBattery();
@@ -1210,7 +1216,8 @@
         dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 
                 which == STATS_SINCE_CHARGED ? getStartCount() : "N/A",
                 whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
-                totalRealtime / 1000, totalUptime / 1000); 
+                totalRealtime / 1000, totalUptime / 1000,
+                getStartClockTime());
         
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
@@ -1587,7 +1594,9 @@
                 formatTimeMs(sb, totalUptime / 1000);
                 sb.append("uptime, ");
         pw.println(sb.toString());
-        
+        pw.print("  Start clock time: ");
+        pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
+
         final long screenOnTime = getScreenOnTime(batteryRealtime, which);
         final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index ed45298..931fb81 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -290,18 +290,14 @@
         return -1;
     }
 
+    /**
+     * @hide Was accidentally exposed in API level 1 for debugging purposes.
+     * Kept for compatibility just in case although the debugging code has been removed.
+     */
+    @Deprecated
     public static float complexToDimensionNoisy(int data, DisplayMetrics metrics)
     {
-        float res = complexToDimension(data, metrics);
-        System.out.println(
-            "Dimension (0x" + ((data>>TypedValue.COMPLEX_MANTISSA_SHIFT)
-                               & TypedValue.COMPLEX_MANTISSA_MASK)
-            + "*" + (RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT)
-                                & TypedValue.COMPLEX_RADIX_MASK] / MANTISSA_MULT)
-            + ")" + DIMENSION_UNIT_STRS[(data>>COMPLEX_UNIT_SHIFT)
-                                & COMPLEX_UNIT_MASK]
-            + " = " + res);
-        return res;
+        return complexToDimension(data, metrics);
     }
 
     /**
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 1811111..986c296 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1413,15 +1413,13 @@
     }
 
     @Override
-    boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
+    void attachFunctor(View.AttachInfo attachInfo, int functor) {
         if (mCanvas != null) {
             mCanvas.attachFunctor(functor);
             mFunctorsRunnable.attachInfo = attachInfo;
             attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
             attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
-            return true;
         }
-        return false;
     }
 
     /**
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ac728f1..676ac10 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -466,9 +466,8 @@
      * @see HardwareCanvas#callDrawGLFunction(int)
      * @see #detachFunctor(int)
      *
-     * @return true if the functor was attached successfully
      */
-    abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
+    abstract void attachFunctor(View.AttachInfo attachInfo, int functor);
 
     /**
      * Initializes the hardware renderer for the specified surface and setup the
diff --git a/core/java/android/view/RemoteGLRenderer.java b/core/java/android/view/RemoteGLRenderer.java
deleted file mode 100644
index 2919775..0000000
--- a/core/java/android/view/RemoteGLRenderer.java
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Surface.OutOfResourcesException;
-
-import java.io.PrintWriter;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Hardware renderer using OpenGL that's used as the remote endpoint
- * of ThreadedRenderer
- *
- * Currently this is mostly a copy of GLRenderer, but with a few modifications
- * to deal with the threading issues. Ideally native-side functionality
- * will replace this, but we need this to bootstrap without risking breaking
- * changes in GLRenderer
- *
- * @hide
- */
-public class RemoteGLRenderer extends HardwareRenderer {
-    static final int SURFACE_STATE_ERROR = 0;
-    static final int SURFACE_STATE_SUCCESS = 1;
-    static final int SURFACE_STATE_UPDATED = 2;
-
-    static final int FUNCTOR_PROCESS_DELAY = 4;
-
-    /**
-     * Number of frames to profile.
-     */
-    private static final int PROFILE_MAX_FRAMES = 128;
-
-    /**
-     * Number of floats per profiled frame.
-     */
-    private static final int PROFILE_FRAME_DATA_COUNT = 3;
-
-    private static final int PROFILE_DRAW_MARGIN = 0;
-    private static final int PROFILE_DRAW_WIDTH = 3;
-    private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
-    private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
-    private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
-    private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
-    private static final int PROFILE_DRAW_DP_PER_MS = 7;
-
-    private static final String[] VISUALIZERS = {
-            PROFILE_PROPERTY_VISUALIZE_BARS,
-            PROFILE_PROPERTY_VISUALIZE_LINES
-    };
-
-    private static final String[] OVERDRAW = {
-            OVERDRAW_PROPERTY_SHOW,
-            OVERDRAW_PROPERTY_COUNT
-    };
-    private static final int OVERDRAW_TYPE_COUNT = 1;
-    private static final int GL_VERSION = 2;
-
-    int mWidth = -1, mHeight = -1;
-
-    HardwareCanvas mCanvas;
-
-    String mName;
-
-    long mFrameCount;
-    Paint mDebugPaint;
-
-    boolean mDirtyRegionsEnabled;
-    boolean mSurfaceUpdated;
-
-    boolean mProfileEnabled;
-    int mProfileVisualizerType = -1;
-    float[] mProfileData;
-    ReentrantLock mProfileLock;
-    int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-
-    GraphDataProvider mDebugDataProvider;
-    float[][] mProfileShapes;
-    Paint mProfilePaint;
-
-    boolean mDebugDirtyRegions;
-    int mDebugOverdraw = -1;
-    HardwareLayer mDebugOverdrawLayer;
-    Paint mDebugOverdrawPaint;
-
-    final boolean mTranslucent;
-
-    private final Rect mRedrawClip = new Rect();
-
-    private final int[] mSurfaceSize = new int[2];
-    private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
-
-    private long mDrawDelta = Long.MAX_VALUE;
-
-    private GLES20Canvas mGlCanvas;
-
-    private DisplayMetrics mDisplayMetrics;
-    private ThreadedRenderer mOwningRenderer;
-    private long mNativeCanvasContext;
-
-    HardwareCanvas createCanvas() {
-        return mGlCanvas = new GLES20Canvas(mTranslucent);
-    }
-
-    void initCaches() {
-        if (GLES20Canvas.initCaches()) {
-            // Caches were (re)initialized, rebind atlas
-            initAtlas();
-        }
-    }
-
-    void initAtlas() {
-        IBinder binder = ServiceManager.getService("assetatlas");
-        if (binder == null) return;
-
-        IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
-        try {
-            if (atlas.isCompatible(android.os.Process.myPpid())) {
-                GraphicBuffer buffer = atlas.getBuffer();
-                if (buffer != null) {
-                    int[] map = atlas.getMap();
-                    if (map != null) {
-                        GLES20Canvas.initAtlas(buffer, map);
-                    }
-                    // If IAssetAtlas is not the same class as the IBinder
-                    // we are using a remote service and we can safely
-                    // destroy the graphic buffer
-                    if (atlas.getClass() != binder.getClass()) {
-                        buffer.destroy();
-                    }
-                }
-            }
-        } catch (RemoteException e) {
-            Log.w(LOG_TAG, "Could not acquire atlas", e);
-        }
-    }
-
-    boolean canDraw() {
-        return mCanvas != null && mGlCanvas != null;
-    }
-
-    int onPreDraw(Rect dirty) {
-        return mGlCanvas.onPreDraw(dirty);
-    }
-
-    void onPostDraw() {
-        mGlCanvas.onPostDraw();
-    }
-
-    void drawProfileData(View.AttachInfo attachInfo) {
-        if (mDebugDataProvider != null) {
-            final GraphDataProvider provider = mDebugDataProvider;
-            initProfileDrawData(attachInfo, provider);
-
-            final int height = provider.getVerticalUnitSize();
-            final int margin = provider.getHorizontaUnitMargin();
-            final int width = provider.getHorizontalUnitSize();
-
-            int x = 0;
-            int count = 0;
-            int current = 0;
-
-            final float[] data = provider.getData();
-            final int elementCount = provider.getElementCount();
-            final int graphType = provider.getGraphType();
-
-            int totalCount = provider.getFrameCount() * elementCount;
-            if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
-                totalCount -= elementCount;
-            }
-
-            for (int i = 0; i < totalCount; i += elementCount) {
-                if (data[i] < 0.0f) break;
-
-                int index = count * 4;
-                if (i == provider.getCurrentFrame() * elementCount) current = index;
-
-                x += margin;
-                int x2 = x + width;
-
-                int y2 = mHeight;
-                int y1 = (int) (y2 - data[i] * height);
-
-                switch (graphType) {
-                    case GraphDataProvider.GRAPH_TYPE_BARS: {
-                        for (int j = 0; j < elementCount; j++) {
-                            //noinspection MismatchedReadAndWriteOfArray
-                            final float[] r = mProfileShapes[j];
-                            r[index] = x;
-                            r[index + 1] = y1;
-                            r[index + 2] = x2;
-                            r[index + 3] = y2;
-
-                            y2 = y1;
-                            if (j < elementCount - 1) {
-                                y1 = (int) (y2 - data[i + j + 1] * height);
-                            }
-                        }
-                    } break;
-                    case GraphDataProvider.GRAPH_TYPE_LINES: {
-                        for (int j = 0; j < elementCount; j++) {
-                            //noinspection MismatchedReadAndWriteOfArray
-                            final float[] r = mProfileShapes[j];
-                            r[index] = (x + x2) * 0.5f;
-                            r[index + 1] = index == 0 ? y1 : r[index - 1];
-                            r[index + 2] = r[index] + width;
-                            r[index + 3] = y1;
-
-                            y2 = y1;
-                            if (j < elementCount - 1) {
-                                y1 = (int) (y2 - data[i + j + 1] * height);
-                            }
-                        }
-                    } break;
-                }
-
-
-                x += width;
-                count++;
-            }
-
-            x += margin;
-
-            drawGraph(graphType, count);
-            drawCurrentFrame(graphType, current);
-            drawThreshold(x, height);
-        }
-    }
-
-    private void drawGraph(int graphType, int count) {
-        for (int i = 0; i < mProfileShapes.length; i++) {
-            mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
-            switch (graphType) {
-                case GraphDataProvider.GRAPH_TYPE_BARS:
-                    mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
-                    break;
-                case GraphDataProvider.GRAPH_TYPE_LINES:
-                    mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
-                    break;
-            }
-        }
-    }
-
-    private void drawCurrentFrame(int graphType, int index) {
-        if (index >= 0) {
-            mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
-            switch (graphType) {
-                case GraphDataProvider.GRAPH_TYPE_BARS:
-                    mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                            mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
-                            mProfilePaint);
-                    break;
-                case GraphDataProvider.GRAPH_TYPE_LINES:
-                    mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                            mProfileShapes[2][index], mHeight, mProfilePaint);
-                    break;
-            }
-        }
-    }
-
-    private void drawThreshold(int x, int height) {
-        float threshold = mDebugDataProvider.getThreshold();
-        if (threshold > 0.0f) {
-            mDebugDataProvider.setupThresholdPaint(mProfilePaint);
-            int y = (int) (mHeight - threshold * height);
-            mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
-        }
-    }
-
-    private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
-        if (mProfileShapes == null) {
-            final int elementCount = provider.getElementCount();
-            final int frameCount = provider.getFrameCount();
-
-            mProfileShapes = new float[elementCount][];
-            for (int i = 0; i < elementCount; i++) {
-                mProfileShapes[i] = new float[frameCount * 4];
-            }
-
-            mProfilePaint = new Paint();
-        }
-
-        mProfilePaint.reset();
-        if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
-            mProfilePaint.setAntiAlias(true);
-        }
-
-        if (mDisplayMetrics == null) {
-            mDisplayMetrics = new DisplayMetrics();
-        }
-
-        attachInfo.mDisplay.getMetrics(mDisplayMetrics);
-        provider.prepare(mDisplayMetrics);
-    }
-
-    @Override
-    void destroy(boolean full) {
-        try {
-            if (full && mCanvas != null) {
-                mCanvas = null;
-            }
-            if (mNativeCanvasContext != 0) {
-                destroyContext(mNativeCanvasContext);
-                mNativeCanvasContext = 0;
-            }
-            setEnabled(false);
-        } finally {
-            if (full && mGlCanvas != null) {
-                mGlCanvas = null;
-            }
-        }
-    }
-
-    @Override
-    void pushLayerUpdate(HardwareLayer layer) {
-        mGlCanvas.pushLayerUpdate(layer);
-    }
-
-    @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
-        mGlCanvas.cancelLayerUpdate(layer);
-    }
-
-    @Override
-    void flushLayerUpdates() {
-        mGlCanvas.flushLayerUpdates();
-    }
-
-    @Override
-    HardwareLayer createHardwareLayer(boolean isOpaque) {
-        return new GLES20TextureLayer(isOpaque);
-    }
-
-    @Override
-    public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
-        return new GLES20RenderLayer(width, height, isOpaque);
-    }
-
-    void countOverdraw(HardwareCanvas canvas) {
-        ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
-    }
-
-    float getOverdraw(HardwareCanvas canvas) {
-        return ((GLES20Canvas) canvas).getOverdraw();
-    }
-
-    @Override
-    public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        return ((GLES20TextureLayer) layer).getSurfaceTexture();
-    }
-
-    @Override
-    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
-        ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
-    }
-
-    @Override
-    boolean safelyRun(Runnable action) {
-        boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
-
-        if (needsContext) {
-            if (!usePBufferSurface()) {
-                return false;
-            }
-        }
-
-        action.run();
-
-        return true;
-    }
-
-    @Override
-    void destroyLayers(final View view) {
-        if (view != null) {
-            safelyRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (mCanvas != null) {
-                        mCanvas.clearLayerUpdates();
-                    }
-                    destroyHardwareLayer(view);
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                }
-            });
-        }
-    }
-
-    private static void destroyHardwareLayer(View view) {
-        view.destroyLayer(true);
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyHardwareLayer(group.getChildAt(i));
-            }
-        }
-    }
-
-    @Override
-    void destroyHardwareResources(final View view) {
-        if (view != null) {
-            safelyRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (mCanvas != null) {
-                        mCanvas.clearLayerUpdates();
-                    }
-                    destroyResources(view);
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                }
-            });
-        }
-    }
-
-    private static void destroyResources(View view) {
-        view.destroyHardwareResources();
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyResources(group.getChildAt(i));
-            }
-        }
-    }
-
-    RemoteGLRenderer(ThreadedRenderer owningRenderer, boolean translucent) {
-        mOwningRenderer = owningRenderer;
-        mTranslucent = translucent;
-
-        loadSystemProperties();
-    }
-
-    @Override
-    boolean loadSystemProperties() {
-        boolean value;
-        boolean changed = false;
-
-        String profiling = SystemProperties.get(PROFILE_PROPERTY);
-        int graphType = search(VISUALIZERS, profiling);
-        value = graphType >= 0;
-
-        if (graphType != mProfileVisualizerType) {
-            changed = true;
-            mProfileVisualizerType = graphType;
-
-            mProfileShapes = null;
-            mProfilePaint = null;
-
-            if (value) {
-                mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
-            } else {
-                mDebugDataProvider = null;
-            }
-        }
-
-        // If on-screen profiling is not enabled, we need to check whether
-        // console profiling only is enabled
-        if (!value) {
-            value = Boolean.parseBoolean(profiling);
-        }
-
-        if (value != mProfileEnabled) {
-            changed = true;
-            mProfileEnabled = value;
-
-            if (mProfileEnabled) {
-                Log.d(LOG_TAG, "Profiling hardware renderer");
-
-                int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
-                        PROFILE_MAX_FRAMES);
-                mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                }
-
-                mProfileLock = new ReentrantLock();
-            } else {
-                mProfileData = null;
-                mProfileLock = null;
-                mProfileVisualizerType = -1;
-            }
-
-            mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-        }
-
-        value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
-        if (value != mDebugDirtyRegions) {
-            changed = true;
-            mDebugDirtyRegions = value;
-
-            if (mDebugDirtyRegions) {
-                Log.d(LOG_TAG, "Debugging dirty regions");
-            }
-        }
-
-        String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
-        int debugOverdraw = search(OVERDRAW, overdraw);
-        if (debugOverdraw != mDebugOverdraw) {
-            changed = true;
-            mDebugOverdraw = debugOverdraw;
-
-            if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
-                if (mDebugOverdrawLayer != null) {
-                    mDebugOverdrawLayer.destroy();
-                    mDebugOverdrawLayer = null;
-                    mDebugOverdrawPaint = null;
-                }
-            }
-        }
-
-        if (GLRenderer.loadProperties()) {
-            changed = true;
-        }
-
-        return changed;
-    }
-
-    private static int search(String[] values, String value) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i].equals(value)) return i;
-        }
-        return -1;
-    }
-
-    @Override
-    void dumpGfxInfo(PrintWriter pw) {
-        if (mProfileEnabled) {
-            pw.printf("\n\tDraw\tProcess\tExecute\n");
-
-            mProfileLock.lock();
-            try {
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    if (mProfileData[i] < 0) {
-                        break;
-                    }
-                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
-                            mProfileData[i + 2]);
-                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                }
-                mProfileCurrentFrame = mProfileData.length;
-            } finally {
-                mProfileLock.unlock();
-            }
-        }
-    }
-
-    @Override
-    long getFrameCount() {
-        return mFrameCount;
-    }
-
-    /**
-     * Indicates whether this renderer instance can track and update dirty regions.
-     */
-    boolean hasDirtyRegions() {
-        return mDirtyRegionsEnabled;
-    }
-
-    private void triggerSoftwareFallback() {
-        destroy(true);
-        // we'll try again if it was context lost
-        setRequested(false);
-        Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
-                + "Switching back to software rendering.");
-    }
-
-    @Override
-    boolean initialize(Surface surface) throws OutOfResourcesException {
-        if (isRequested() && !isEnabled()) {
-            mNativeCanvasContext = createContext();
-            boolean surfaceCreated = createEglSurface(surface);
-
-            if (surfaceCreated) {
-                if (mCanvas == null) {
-                    mCanvas = createCanvas();
-                }
-                setEnabled(true);
-                initAtlas();
-                return true;
-            } else {
-                destroy(true);
-                setRequested(false);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    void updateSurface(Surface surface) throws OutOfResourcesException {
-        if (isRequested() && isEnabled()) {
-            createEglSurface(surface);
-        }
-    }
-
-    boolean createEglSurface(Surface surface) throws OutOfResourcesException {
-        // Create an EGL surface we can render into.
-        if (!setSurface(mNativeCanvasContext, surface)) {
-            return false;
-        }
-        makeCurrent(mNativeCanvasContext);
-        mSurfaceUpdated = true;
-
-        initCaches();
-        return true;
-    }
-
-    @Override
-    void invalidate(Surface surface) {
-        setSurface(mNativeCanvasContext, null);
-        setEnabled(false);
-
-        if (surface.isValid()) {
-            if (createEglSurface(surface) && mCanvas != null) {
-                setEnabled(true);
-            }
-        }
-    }
-
-    @Override
-    boolean validate() {
-        return checkRenderContext() != SURFACE_STATE_ERROR;
-    }
-
-    @Override
-    void setup(int width, int height) {
-        if (validate()) {
-            mCanvas.setViewport(width, height);
-            mWidth = width;
-            mHeight = height;
-        }
-    }
-
-    @Override
-    int getWidth() {
-        return mWidth;
-    }
-
-    @Override
-    int getHeight() {
-        return mHeight;
-    }
-
-    @Override
-    void setName(String name) {
-        mName = name;
-    }
-
-    // TODO: Ping pong is fun and all, but this isn't the time or place
-    // However we don't yet have the ability for the RenderThread to run
-    // independently nor have a way to postDelayed, so this will work for now
-    private Runnable mDispatchFunctorsRunnable = new Runnable() {
-        @Override
-        public void run() {
-            ThreadedRenderer.postToRenderThread(mFunctorsRunnable);
-        }
-    };
-
-    class FunctorsRunnable implements Runnable {
-        View.AttachInfo attachInfo;
-
-        @Override
-        public void run() {
-            final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
-            if (renderer == null || !renderer.isEnabled() || renderer != mOwningRenderer) {
-                return;
-            }
-
-            if (checkRenderContext() != SURFACE_STATE_ERROR) {
-                int status = mCanvas.invokeFunctors(mRedrawClip);
-                handleFunctorStatus(attachInfo, status);
-            }
-        }
-    }
-
-    /**
-     * @param displayList The display list to draw
-     * @param attachInfo AttachInfo tied to the specified view.
-     * @param callbacks Callbacks invoked when drawing happens.
-     * @param dirty The dirty rectangle to update, can be null.
-     */
-    void drawDisplayList(DisplayList displayList, View.AttachInfo attachInfo,
-            HardwareDrawCallbacks callbacks, Rect dirty) {
-        if (canDraw()) {
-            if (!hasDirtyRegions()) {
-                dirty = null;
-            }
-
-            final int surfaceState = checkRenderContext();
-            if (surfaceState != SURFACE_STATE_ERROR) {
-                HardwareCanvas canvas = mCanvas;
-
-                if (mProfileEnabled) {
-                    mProfileLock.lock();
-                }
-
-                dirty = beginFrame(canvas, dirty, surfaceState);
-
-                int saveCount = 0;
-                int status = DisplayList.STATUS_DONE;
-
-                long start = GLRenderer.getSystemTime();
-                try {
-                    status = prepareFrame(dirty);
-
-                    saveCount = canvas.save();
-                    callbacks.onHardwarePreDraw(canvas);
-
-                    status |= doDrawDisplayList(attachInfo, canvas, displayList, status);
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "An error has occurred while drawing:", e);
-                } finally {
-                    callbacks.onHardwarePostDraw(canvas);
-                    canvas.restoreToCount(saveCount);
-
-                    mDrawDelta = GLRenderer.getSystemTime() - start;
-
-                    if (mDrawDelta > 0) {
-                        mFrameCount++;
-
-                        debugOverdraw(attachInfo, dirty, canvas, displayList);
-                        debugDirtyRegions(dirty, canvas);
-                        drawProfileData(attachInfo);
-                    }
-                }
-
-                onPostDraw();
-
-                swapBuffers(status);
-
-                if (mProfileEnabled) {
-                    mProfileLock.unlock();
-                }
-
-                attachInfo.mIgnoreDirtyState = false;
-            }
-        }
-    }
-
-    @Override
-    void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
-            Rect dirty) {
-        throw new IllegalAccessError();
-    }
-
-    private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
-            HardwareCanvas canvas, DisplayList displayList) {
-
-        if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
-            if (mDebugOverdrawLayer == null) {
-                mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
-            } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
-                    mDebugOverdrawLayer.getHeight() != mHeight) {
-                mDebugOverdrawLayer.resize(mWidth, mHeight);
-            }
-
-            if (!mDebugOverdrawLayer.isValid()) {
-                mDebugOverdraw = -1;
-                return;
-            }
-
-            HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
-            countOverdraw(layerCanvas);
-            final int restoreCount = layerCanvas.save();
-            layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
-            layerCanvas.restoreToCount(restoreCount);
-            mDebugOverdrawLayer.end(canvas);
-
-            float overdraw = getOverdraw(layerCanvas);
-            DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
-
-            drawOverdrawCounter(canvas, overdraw, metrics.density);
-        }
-    }
-
-    private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
-        final String text = String.format("%.2fx", overdraw);
-        final Paint paint = setupPaint(density);
-        // HSBtoColor will clamp the values in the 0..1 range
-        paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
-
-        canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
-    }
-
-    private Paint setupPaint(float density) {
-        if (mDebugOverdrawPaint == null) {
-            mDebugOverdrawPaint = new Paint();
-            mDebugOverdrawPaint.setAntiAlias(true);
-            mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
-            mDebugOverdrawPaint.setTextSize(density * 20.0f);
-        }
-        return mDebugOverdrawPaint;
-    }
-
-    private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
-        // We had to change the current surface and/or context, redraw everything
-        if (surfaceState == SURFACE_STATE_UPDATED) {
-            dirty = null;
-            GLRenderer.beginFrame(null);
-        } else {
-            int[] size = mSurfaceSize;
-            GLRenderer.beginFrame(size);
-
-            if (size[1] != mHeight || size[0] != mWidth) {
-                mWidth = size[0];
-                mHeight = size[1];
-
-                canvas.setViewport(mWidth, mHeight);
-
-                dirty = null;
-            }
-        }
-
-        if (mDebugDataProvider != null) dirty = null;
-
-        return dirty;
-    }
-
-    private int prepareFrame(Rect dirty) {
-        int status;
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
-        try {
-            status = onPreDraw(dirty);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-        return status;
-    }
-
-    private int doDrawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
-            DisplayList displayList, int status) {
-
-        long drawDisplayListStartTime = 0;
-        if (mProfileEnabled) {
-            drawDisplayListStartTime = System.nanoTime();
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
-        try {
-            status |= canvas.drawDisplayList(displayList, mRedrawClip,
-                    DisplayList.FLAG_CLIP_CHILDREN);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-
-        if (mProfileEnabled) {
-            long now = System.nanoTime();
-            float total = (now - drawDisplayListStartTime) * 0.000001f;
-            mProfileData[mProfileCurrentFrame + 1] = total;
-        }
-
-        handleFunctorStatus(attachInfo, status);
-        return status;
-    }
-
-    private void swapBuffers(int status) {
-        if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
-            long eglSwapBuffersStartTime = 0;
-            if (mProfileEnabled) {
-                eglSwapBuffersStartTime = System.nanoTime();
-            }
-
-            if (!swapBuffers(mNativeCanvasContext)) {
-                triggerSoftwareFallback();
-            }
-            mSurfaceUpdated = false;
-
-            if (mProfileEnabled) {
-                long now = System.nanoTime();
-                float total = (now - eglSwapBuffersStartTime) * 0.000001f;
-                mProfileData[mProfileCurrentFrame + 2] = total;
-            }
-        }
-    }
-
-    private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
-        if (mDebugDirtyRegions) {
-            if (mDebugPaint == null) {
-                mDebugPaint = new Paint();
-                mDebugPaint.setColor(0x7fff0000);
-            }
-
-            if (dirty != null && (mFrameCount & 1) == 0) {
-                canvas.drawRect(dirty, mDebugPaint);
-            }
-        }
-    }
-
-    private void handleFunctorStatus(final View.AttachInfo attachInfo, int status) {
-        // If the draw flag is set, functors will be invoked while executing
-        // the tree of display lists
-        if ((status & DisplayList.STATUS_DRAW) != 0) {
-            // TODO: Can we just re-queue ourselves up to draw next frame instead
-            // of bouncing back to the UI thread?
-            // TODO: Respect mRedrawClip - for now just full inval
-            attachInfo.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    attachInfo.mViewRootImpl.invalidate();
-                }
-            });
-            mRedrawClip.setEmpty();
-        }
-
-        if ((status & DisplayList.STATUS_INVOKE) != 0 ||
-                attachInfo.mHandler.hasCallbacks(mDispatchFunctorsRunnable)) {
-            attachInfo.mHandler.removeCallbacks(mDispatchFunctorsRunnable);
-            mFunctorsRunnable.attachInfo = attachInfo;
-            attachInfo.mHandler.postDelayed(mDispatchFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
-        }
-    }
-
-    @Override
-    void detachFunctor(int functor) {
-        if (mCanvas != null) {
-            mCanvas.detachFunctor(functor);
-        }
-    }
-
-    @Override
-    boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
-        if (mCanvas != null) {
-            mCanvas.attachFunctor(functor);
-            mFunctorsRunnable.attachInfo = attachInfo;
-            attachInfo.mHandler.removeCallbacks(mDispatchFunctorsRunnable);
-            attachInfo.mHandler.postDelayed(mDispatchFunctorsRunnable,  0);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Ensures the current EGL context and surface are the ones we expect.
-     * This method throws an IllegalStateException if invoked from a thread
-     * that did not initialize EGL.
-     *
-     * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
-     *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
-     *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
-     *
-     * @see #checkRenderContextUnsafe()
-     */
-    int checkRenderContext() {
-        if (!makeCurrent(mNativeCanvasContext)) {
-            triggerSoftwareFallback();
-            return SURFACE_STATE_ERROR;
-        }
-        return mSurfaceUpdated ? SURFACE_STATE_UPDATED : SURFACE_STATE_SUCCESS;
-    }
-
-    private static int dpToPx(int dp, float density) {
-        return (int) (dp * density + 0.5f);
-    }
-
-    class DrawPerformanceDataProvider extends GraphDataProvider {
-        private final int mGraphType;
-
-        private int mVerticalUnit;
-        private int mHorizontalUnit;
-        private int mHorizontalMargin;
-        private int mThresholdStroke;
-
-        DrawPerformanceDataProvider(int graphType) {
-            mGraphType = graphType;
-        }
-
-        @Override
-        void prepare(DisplayMetrics metrics) {
-            final float density = metrics.density;
-
-            mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
-            mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
-            mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
-            mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
-        }
-
-        @Override
-        int getGraphType() {
-            return mGraphType;
-        }
-
-        @Override
-        int getVerticalUnitSize() {
-            return mVerticalUnit;
-        }
-
-        @Override
-        int getHorizontalUnitSize() {
-            return mHorizontalUnit;
-        }
-
-        @Override
-        int getHorizontaUnitMargin() {
-            return mHorizontalMargin;
-        }
-
-        @Override
-        float[] getData() {
-            return mProfileData;
-        }
-
-        @Override
-        float getThreshold() {
-            return 16;
-        }
-
-        @Override
-        int getFrameCount() {
-            return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
-        }
-
-        @Override
-        int getElementCount() {
-            return PROFILE_FRAME_DATA_COUNT;
-        }
-
-        @Override
-        int getCurrentFrame() {
-            return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
-        }
-
-        @Override
-        void setupGraphPaint(Paint paint, int elementIndex) {
-            paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
-            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-        }
-
-        @Override
-        void setupThresholdPaint(Paint paint) {
-            paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
-            paint.setStrokeWidth(mThresholdStroke);
-        }
-
-        @Override
-        void setupCurrentFramePaint(Paint paint) {
-            paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
-            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-        }
-    }
-
-    static native long createContext();
-    static native boolean usePBufferSurface();
-    static native boolean setSurface(long nativeCanvasContext, Surface surface);
-    static native boolean swapBuffers(long nativeCanvasContext);
-    static native boolean makeCurrent(long nativeCanvasContext);
-    static native void destroyContext(long nativeCanvasContext);
-}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2cd1b6e..567f862 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -18,25 +18,26 @@
 
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.os.Looper;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
 import java.io.PrintWriter;
-import java.lang.reflect.Method;
-import java.util.HashMap;
 
 /**
  * Hardware renderer that proxies the rendering to a render thread. Most calls
- * are synchronous, however a few such as draw() are posted async. The display list
- * is shared between the two threads and is guarded by a top level lock.
+ * are currently synchronous.
+ * TODO: Make draw() async.
+ * TODO: Figure out how to share the DisplayList between two threads (global lock?)
  *
  * The UI thread can block on the RenderThread, but RenderThread must never
  * block on the UI thread.
  *
+ * ThreadedRenderer creates an instance of RenderProxy. RenderProxy in turn creates
+ * and manages a CanvasContext on the RenderThread. The CanvasContext is fully managed
+ * by the lifecycle of the RenderProxy.
+ *
  * Note that although currently the EGL context & surfaces are created & managed
  * by the render thread, the goal is to move that into a shared structure that can
  * be managed by both threads. EGLSurface creation & deletion should ideally be
@@ -48,49 +49,29 @@
 public class ThreadedRenderer extends HardwareRenderer {
     private static final String LOGTAG = "ThreadedRenderer";
 
-    @SuppressWarnings("serial")
-    static HashMap<String, Method> sMethodLut = new HashMap<String, Method>() {{
-        Method[] methods = RemoteGLRenderer.class.getDeclaredMethods();
-        for (Method m : methods) {
-            m.setAccessible(true);
-            put(m.getName() + ":" + m.getParameterTypes().length, m);
-        }
-    }};
-    static boolean sNeedsInit = true;
+    private static final Rect NULL_RECT = new Rect(-1, -1, -1, -1);
 
-    private RemoteGLRenderer mRemoteRenderer;
     private int mWidth, mHeight;
-    private RTJob mPreviousDraw;
+    private long mNativeProxy;
 
     ThreadedRenderer(boolean translucent) {
-        mRemoteRenderer = new RemoteGLRenderer(this, translucent);
-        setEnabled(true);
-        if (sNeedsInit) {
-            sNeedsInit = false;
-            postToRenderThread(new Runnable() {
-                @Override
-                public void run() {
-                    // Hack to allow GLRenderer to create a handler to post the EGL
-                    // destruction to, although it'll never run
-                    Looper.prepare();
-                }
-            });
-        }
+        mNativeProxy = nCreateProxy(translucent);
+        setEnabled(mNativeProxy != 0);
     }
 
     @Override
     void destroy(boolean full) {
-        run("destroy", full);
+        nDestroyCanvas(mNativeProxy);
     }
 
     @Override
     boolean initialize(Surface surface) throws OutOfResourcesException {
-        return (Boolean) run("initialize", surface);
+        return nInitialize(mNativeProxy, surface);
     }
 
     @Override
     void updateSurface(Surface surface) throws OutOfResourcesException {
-        post("updateSurface", surface);
+        nUpdateSurface(mNativeProxy, surface);
     }
 
     @Override
@@ -100,12 +81,27 @@
 
     @Override
     void destroyHardwareResources(View view) {
-        run("destroyHardwareResources", view);
+        // TODO: canvas.clearLayerUpdates()
+        destroyResources(view);
+        // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+    }
+
+    private static void destroyResources(View view) {
+        view.destroyHardwareResources();
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+
+            int count = group.getChildCount();
+            for (int i = 0; i < count; i++) {
+                destroyResources(group.getChildAt(i));
+            }
+        }
     }
 
     @Override
     void invalidate(Surface surface) {
-        post("invalidate", surface);
+        updateSurface(surface);
     }
 
     @Override
@@ -116,14 +112,15 @@
 
     @Override
     boolean safelyRun(Runnable action) {
-        return (Boolean) run("safelyRun", action);
+        // TODO:
+        return false;
     }
 
     @Override
     void setup(int width, int height) {
         mWidth = width;
         mHeight = height;
-        post("setup", width, height);
+        nSetup(mNativeProxy, width, height);
     }
 
     @Override
@@ -149,7 +146,7 @@
 
     @Override
     boolean loadSystemProperties() {
-        return (Boolean) run("loadSystemProperties");
+        return false;
     }
 
     @Override
@@ -174,20 +171,10 @@
      *
      *  @hide */
     public void repeatLastDraw() {
-        if (mPreviousDraw == null) {
-            throw new IllegalStateException("There isn't a previous draw");
-        }
-        synchronized (mPreviousDraw) {
-            mPreviousDraw.completed = false;
-        }
-        mPreviousDraw.args[3] = null;
-        postToRenderThread(mPreviousDraw);
     }
 
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
-        requireCompletion(mPreviousDraw);
-
         attachInfo.mIgnoreDirtyState = true;
         attachInfo.mDrawingTime = SystemClock.uptimeMillis();
         view.mPrivateFlags |= View.PFLAG_DRAWN;
@@ -202,8 +189,11 @@
 
         view.mRecreateDisplayList = false;
 
-        mPreviousDraw = post("drawDisplayList", displayList, attachInfo,
-                callbacks, dirty);
+        if (dirty == null) {
+            dirty = NULL_RECT;
+        }
+        nDrawDisplayList(mNativeProxy, displayList.getNativeDisplayList(),
+                dirty.left, dirty.top, dirty.right, dirty.bottom);
     }
 
     @Override
@@ -228,85 +218,40 @@
 
     @Override
     void detachFunctor(int functor) {
-        run("detachFunctor", functor);
+        nDetachFunctor(mNativeProxy, functor);
     }
 
     @Override
-    boolean attachFunctor(AttachInfo attachInfo, int functor) {
-        return (Boolean) run("attachFunctor", attachInfo, functor);
+    void attachFunctor(AttachInfo attachInfo, int functor) {
+        nAttachFunctor(mNativeProxy, functor);
     }
 
     @Override
     void setName(String name) {
-        post("setName", name);
     }
 
-    private static void requireCompletion(RTJob job) {
-        if (job != null) {
-            synchronized (job) {
-                if (!job.completed) {
-                    try {
-                        job.wait();
-                    } catch (InterruptedException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-        }
-    }
-
-    private RTJob post(String method, Object... args) {
-        RTJob job = new RTJob();
-        job.method = sMethodLut.get(method + ":" + args.length);
-        job.args = args;
-        job.target = mRemoteRenderer;
-        if (job.method == null) {
-            throw new NullPointerException("Couldn't find method: " + method);
-        }
-        postToRenderThread(job);
-        return job;
-    }
-
-    private Object run(String method, Object... args) {
-        RTJob job = new RTJob();
-        job.method = sMethodLut.get(method + ":" + args.length);
-        job.args = args;
-        job.target = mRemoteRenderer;
-        if (job.method == null) {
-            throw new NullPointerException("Couldn't find method: " + method);
-        }
-        synchronized (job) {
-            postToRenderThread(job);
-            try {
-                job.wait();
-                return job.ret;
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    static class RTJob implements Runnable {
-        Method method;
-        Object[] args;
-        Object target;
-        Object ret;
-        boolean completed = false;
-
-        @Override
-        public void run() {
-            try {
-                ret = method.invoke(target, args);
-                synchronized (this) {
-                    completed = true;
-                    notify();
-                }
-            } catch (Exception e) {
-                Log.e(LOGTAG, "Failed to invoke: " + method.getName(), e);
-            }
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nDeleteProxy(mNativeProxy);
+        } finally {
+            super.finalize();
         }
     }
 
     /** @hide */
     public static native void postToRenderThread(Runnable runnable);
+
+    private static native long nCreateProxy(boolean translucent);
+    private static native void nDeleteProxy(long nativeProxy);
+
+    private static native boolean nInitialize(long nativeProxy, Surface window);
+    private static native void nUpdateSurface(long nativeProxy, Surface window);
+    private static native void nSetup(long nativeProxy, int width, int height);
+    private static native void nDrawDisplayList(long nativeProxy, long displayList,
+            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+    private static native void nDestroyCanvas(long nativeProxy);
+
+    private static native void nAttachFunctor(long nativeProxy, long functor);
+    private static native void nDetachFunctor(long nativeProxy, long functor);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 41b0c67..5aa46f3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -660,12 +660,11 @@
         mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
     }
 
-    public boolean attachFunctor(int functor) {
+    public void attachFunctor(int functor) {
         //noinspection SimplifiableIfStatement
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
+            mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
         }
-        return false;
     }
 
     public void detachFunctor(int functor) {
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index afe5804..eabe1a3 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -975,8 +975,10 @@
         private CharSequence mPrompt;
 
         public void dismiss() {
-            mPopup.dismiss();
-            mPopup = null;
+            if (mPopup != null) {
+                mPopup.dismiss();
+                mPopup = null;
+            }
         }
 
         public boolean isShowing() {
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 3798d62..31ca3de 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -371,23 +371,25 @@
         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             mAppearingPackages = pkgList;
-            mChangeType = PACKAGE_TEMPORARY_CHANGE;
+            mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
+                    ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
             mSomePackagesChanged = true;
             if (pkgList != null) {
                 onPackagesAvailable(pkgList);
                 for (int i=0; i<pkgList.length; i++) {
-                    onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+                    onPackageAppeared(pkgList[i], mChangeType);
                 }
             }
         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             mDisappearingPackages = pkgList;
-            mChangeType = PACKAGE_TEMPORARY_CHANGE;
+            mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
+                    ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
             mSomePackagesChanged = true;
             if (pkgList != null) {
                 onPackagesUnavailable(pkgList);
                 for (int i=0; i<pkgList.length; i++) {
-                    onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+                    onPackageDisappeared(pkgList[i], mChangeType);
                 }
             }
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 70ba4e3..7425445 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 70 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 71 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -209,6 +209,8 @@
 
     int mStartCount;
 
+    long mStartClockTime;
+
     long mBatteryUptime;
     long mBatteryLastUptime;
     long mBatteryRealtime;
@@ -2842,6 +2844,10 @@
         }
     }
 
+    @Override public long getStartClockTime() {
+        return mStartClockTime;
+    }
+
     @Override public boolean getIsOnBattery() {
         return mOnBattery;
     }
@@ -4959,6 +4965,7 @@
     }
 
     void initTimes() {
+        mStartClockTime = System.currentTimeMillis();
         mBatteryRealtime = mTrackBatteryPastUptime = 0;
         mBatteryUptime = mTrackBatteryPastRealtime = 0;
         mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
@@ -5832,6 +5839,7 @@
         mBatteryRealtime = in.readLong();
         mUptime = in.readLong();
         mRealtime = in.readLong();
+        mStartClockTime = in.readLong();
         mDischargeUnplugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
@@ -6040,9 +6048,7 @@
      * @param out the Parcel to be written to.
      */
     public void writeSummaryToParcel(Parcel out) {
-        // Need to update with current kernel wake lock counts.
-        updateKernelWakelocksLocked();
-        updateNetworkActivityLocked();
+        pullPendingStateUpdatesLocked();
 
         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
         final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
@@ -6058,6 +6064,7 @@
         out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
+        out.writeLong(mStartClockTime);
         out.writeInt(mDischargeUnplugLevel);
         out.writeInt(mDischargeCurrentLevel);
         out.writeInt(getLowDischargeAmountSinceCharge());
@@ -6293,6 +6300,7 @@
         mBatteryLastUptime = 0;
         mBatteryRealtime = in.readLong();
         mBatteryLastRealtime = 0;
+        mStartClockTime = in.readLong();
         mScreenOn = false;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -6408,6 +6416,7 @@
         out.writeInt(mStartCount);
         out.writeLong(mBatteryUptime);
         out.writeLong(mBatteryRealtime);
+        out.writeLong(mStartClockTime);
         mScreenOnTimer.writeToParcel(out, batteryRealtime);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d72b054..f8d96e3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -58,7 +58,6 @@
 	android_view_GLRenderer.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_ThreadedRenderer.cpp \
-	android_view_RemoteGLRenderer.cpp \
 	android_view_MotionEvent.cpp \
 	android_view_PointerIcon.cpp \
 	android_view_VelocityTracker.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 074d7ac1..7ed6641 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -124,7 +124,6 @@
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_GLRenderer(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
-extern int register_android_view_RemoteGLRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
@@ -1129,7 +1128,6 @@
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_GLRenderer),
     REG_JNI(register_android_view_ThreadedRenderer),
-    REG_JNI(register_android_view_RemoteGLRenderer),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index d0871ac5..4bd59e7 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -239,8 +239,8 @@
         SkASSERT(dstIndex >= 0);
         SkASSERT((unsigned)ptCount <= 4);
 
-        AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1));
-        AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1));
+        AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1), kRO_JNIAccess);
+        AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1), kRW_JNIAccess);
         float* src = autoSrc.ptr() + srcIndex;
         float* dst = autoDst.ptr() + dstIndex;
 
@@ -268,8 +268,8 @@
                               jfloatArray src, int srcIndex,
                               int ptCount, bool isPts) {
         SkASSERT(ptCount >= 0);
-        AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1));
-        AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1));
+        AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1), kRO_JNIAccess);
+        AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1), kRW_JNIAccess);
         float* srcArray = autoSrc.ptr() + srcIndex;
         float* dstArray = autoDst.ptr() + dstIndex;
         
@@ -318,7 +318,7 @@
     }
  
     static void getValues(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloatArray values) {
-        AutoJavaFloatArray autoValues(env, values, 9);
+        AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
         float* dst = autoValues.ptr();
 
 #ifdef SK_SCALAR_IS_FIXED
@@ -336,7 +336,7 @@
     }
  
     static void setValues(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloatArray values) {
-        AutoJavaFloatArray autoValues(env, values, 9);
+        AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
         const float* src = autoValues.ptr();
 
 #ifdef SK_SCALAR_IS_FIXED
diff --git a/core/jni/android_view_RemoteGLRenderer.cpp b/core/jni/android_view_RemoteGLRenderer.cpp
deleted file mode 100644
index 96a203b..0000000
--- a/core/jni/android_view_RemoteGLRenderer.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2014 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 "RemoteGLRenderer"
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-#include <utils/StrongPointer.h>
-#include <android_runtime/android_view_Surface.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <renderthread/CanvasContext.h>
-#include <system/window.h>
-
-namespace android {
-
-#ifdef USE_OPENGL_RENDERER
-
-#define CHECK_CONTEXT(c) if (!c) ALOGE("Null context passed to %s!", __func__ )
-
-namespace RT = android::uirenderer::renderthread;
-
-static jlong android_view_RemoteGLRenderer_createContext(JNIEnv* env, jobject clazz) {
-    RT::CanvasContext* context = new RT::CanvasContext();
-    return reinterpret_cast<jlong>(context);
-}
-
-static jboolean android_view_RemoteGLRenderer_usePBufferSurface(JNIEnv* env, jobject clazz) {
-    return RT::CanvasContext::useGlobalPBufferSurface();
-}
-
-static jboolean android_view_RemoteGLRenderer_setSurface(JNIEnv* env, jobject clazz,
-        jlong jcontextptr, jobject jsurface) {
-    RT::CanvasContext* context = reinterpret_cast<RT::CanvasContext*>(jcontextptr);
-    CHECK_CONTEXT(context);
-    sp<ANativeWindow> window;
-    if (jsurface) {
-        window = android_view_Surface_getNativeWindow(env, jsurface);
-    }
-    return context->setSurface(window.get());
-}
-
-static jboolean android_view_RemoteGLRenderer_swapBuffers(JNIEnv* env, jobject clazz,
-        jlong jcontextptr) {
-    RT::CanvasContext* context = reinterpret_cast<RT::CanvasContext*>(jcontextptr);
-    CHECK_CONTEXT(context);
-    return context->swapBuffers();
-}
-
-static jboolean android_view_RemoteGLRenderer_makeCurrent(JNIEnv* env, jobject clazz,
-        jlong jcontextptr) {
-    RT::CanvasContext* context = reinterpret_cast<RT::CanvasContext*>(jcontextptr);
-    CHECK_CONTEXT(context);
-    return context->makeCurrent();
-}
-
-static void android_view_RemoteGLRenderer_destroyContext(JNIEnv* env, jobject clazz,
-        jlong jcontextptr) {
-    RT::CanvasContext* context = reinterpret_cast<RT::CanvasContext*>(jcontextptr);
-    CHECK_CONTEXT(context);
-    delete context;
-}
-#endif
-
-// ----------------------------------------------------------------------------
-// JNI Glue
-// ----------------------------------------------------------------------------
-
-const char* const kClassPathName = "android/view/RemoteGLRenderer";
-
-static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
-    { "createContext", "()J",   (void*) android_view_RemoteGLRenderer_createContext },
-    { "usePBufferSurface", "()Z",   (void*) android_view_RemoteGLRenderer_usePBufferSurface },
-    { "setSurface", "(JLandroid/view/Surface;)Z",   (void*) android_view_RemoteGLRenderer_setSurface },
-    { "swapBuffers", "(J)Z",   (void*) android_view_RemoteGLRenderer_swapBuffers },
-    { "makeCurrent", "(J)Z",   (void*) android_view_RemoteGLRenderer_makeCurrent },
-    { "destroyContext", "(J)V",   (void*) android_view_RemoteGLRenderer_destroyContext },
-#endif
-};
-
-int register_android_view_RemoteGLRenderer(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 8d77e36..8e121de 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -20,6 +20,11 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <utils/StrongPointer.h>
+#include <android_runtime/android_view_Surface.h>
+#include <system/window.h>
+
+#include <renderthread/RenderProxy.h>
 #include <renderthread/RenderTask.h>
 #include <renderthread/RenderThread.h>
 
@@ -27,23 +32,22 @@
 
 #ifdef USE_OPENGL_RENDERER
 
-namespace RT = android::uirenderer::renderthread;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
 
 static jmethodID gRunnableMethod;
 
-class JavaTask : public RT::RenderTask {
+class JavaTask : public RenderTask {
 public:
     JavaTask(JNIEnv* env, jobject jrunnable) {
         env->GetJavaVM(&mVm);
         mRunnable = env->NewGlobalRef(jrunnable);
     }
 
-    virtual ~JavaTask() {
-        env()->DeleteGlobalRef(mRunnable);
-    }
-
     virtual void run() {
         env()->CallVoidMethod(mRunnable, gRunnableMethod);
+        env()->DeleteGlobalRef(mRunnable);
+        delete this;
     };
 
 private:
@@ -61,8 +65,70 @@
 
 static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,
         jobject jrunnable) {
-    RT::RenderTask* task = new JavaTask(env, jrunnable);
-    RT::RenderThread::getInstance().queue(task);
+    RenderTask* task = new JavaTask(env, jrunnable);
+    RenderThread::getInstance().queue(task);
+}
+
+static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
+        jboolean translucent) {
+    return (jlong) new RenderProxy(translucent);
+}
+
+static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    delete proxy;
+}
+
+static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jobject jsurface) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
+    return proxy->initialize(window.get());
+}
+
+static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jobject jsurface) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    sp<ANativeWindow> window;
+    if (jsurface) {
+        window = android_view_Surface_getNativeWindow(env, jsurface);
+    }
+    proxy->updateSurface(window.get());
+}
+
+static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jint width, jint height) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    proxy->setup(width, height);
+}
+
+static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
+        jint dirtyRight, jint dirtyBottom) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>( displayListPtr);
+    proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+}
+
+static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    proxy->destroyCanvas();
+}
+
+static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong functorPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
+    proxy->attachFunctor(functor);
+}
+
+static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong functorPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
+    proxy->detachFunctor(functor);
 }
 
 #endif
@@ -76,6 +142,15 @@
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
     { "postToRenderThread", "(Ljava/lang/Runnable;)V",   (void*) android_view_ThreadedRenderer_postToRenderThread },
+    { "nCreateProxy", "(Z)J", (void*) android_view_ThreadedRenderer_createProxy },
+    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
+    { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
+    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
+    { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList},
+    { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas},
+    { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
+    { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
 #endif
 };
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e902218..25c6f99 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ontsluit tans SIM-kaart…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Verkeerde PIN-kode."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Tik \'n PIN in wat 4 tot 8 syfers lank is."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-kode moet 8 of meer syfers wees."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Voer weer die korrekte PUK-kode in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodes stem nie ooreen nie"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 404a299..be8f713 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ሲም ካርዱን በመክፈት ላይ…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ትክክል ያልሆነ ፒን ኮድ።"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"የPUK ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bc91f44..a58d8b7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏جارٍ إلغاء تأمين بطاقة SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"‏رمز PIN غير صحيح."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"‏اكتب رمز PIN المكون من 4 إلى 8 أرقام."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"‏يجب أن يتضمن رمز PUK‏ 8 أرقام أو أكثر."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل بطاقة SIM نهائيًا."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏لا يتطابق رمزا رمز PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0d4977d..c28550c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картата се отключва…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправилен ПИН код."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Въведете ПИН код с четири до осем цифри."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кодът трябва да е с 8 или повече цифри."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1a68a5f..a1b4aed 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"S\'està desbloquejant la targeta SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codi PIN incorrecte."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escriu un PIN que tingui de 4 a 8 números."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El codi PUK ha de tenir 8 números o més."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 850141b..906d352 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokování SIM karty..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávný kód PIN."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadejte kód PIN o délce 4–8 číslic."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Minimální délka kódu PUK je 8 číslic."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index f520165..4ab3d71 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortet låses op…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Forkert pinkode."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Indtast en pinkode på mellem 4 og 8 tal."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på 8 tal eller mere."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 479e112..8e681f1 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-Karte wird entsperrt…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Falscher PIN-Code"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Geben Sie eine 4- bis 8-stellige PIN ein."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Der PUK-Code muss mindestens 8 Ziffern betragen."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index efc3c07..64d7233 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ξεκλείδωμα κάρτας SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Εσφαλμένος κωδικός PIN."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Πληκτρολογήστε έναν αριθμό PIN που να αποτελείται από 4 έως 8 αριθμούς."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Ο κωδικός PUK θα πρέπει να περιέχει τουλάχιστον 8 αριθμούς."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Δεν υπάρχει αντιστοιχία των κωδικών PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Πάρα πολλές προσπάθειες μοτίβου"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4cb4cdb..b75e169 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK code should be 8 numbers or more."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 4cb4cdb..b75e169 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK code should be 8 numbers or more."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ed66f38..bb03dea 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escribe un PIN que tenga de cuatro a ocho números."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El código PUK debe tener ocho números como mínimo."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2f71718..16768ce 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"El código PUK debe tener ocho números como mínimo."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 53832ce..f79c905 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodi pikkus peab olema vähemalt 8 numbrit."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 00bd48b..9c85499 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -704,7 +704,7 @@
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
-    <string name="policydesc_disableCamera" msgid="2306349042834754597">"‏از استفاده از تمام دوربین‎های دستگاه جلوگیری کنید."</string>
+    <string name="policydesc_disableCamera" msgid="2306349042834754597">"جلوگیری از استفاده از همه دوربین‌های دستگاه."</string>
     <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"غیرفعال کردن ویژگی‌‌ها در محافظ کلید"</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"از استفاده از برخی ویژگی‌ها در محافظ کلید جلوگیری شود."</string>
   <string-array name="phoneTypes">
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"بازگشایی قفل سیم کارت..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"پین کد اشتباه است."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"پین کد باید ۸ عدد یا بیشتر باشد."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاش‌های مکرر به‌طور دائم سیم کارت را غیرفعال خواهد کرد."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"‏تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index eefe2f4..3509198 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortin lukitusta poistetaan…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Virheellinen PIN-koodi."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Anna 4–8-numeroinen PIN-koodi."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodissa tulee olla vähintään 8 numeroa."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodit eivät täsmää"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 659ceca..46faca5 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"NIP erroné."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Saisissez un NIP comprenant entre quatre et huit chiffres"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 0fa3334..349d4b8 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Le code PIN est erroné."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Veuillez saisir un code PIN comprenant entre quatre et huit chiffres."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index bc68c82..feeac91 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM कार्ड अनलॉक कर रहा है…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"गलत PIN कोड."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ऐसा PIN लिखें, जो 4 से 8 अंकों का हो."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 84b27bf..383d0e1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netočan PIN kôd."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kôd treba imati 8 brojeva ili više."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi nisu jednaki"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a338c4d..712ffb1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kártya feloldása..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Helytelen PIN kód."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4–8 számjegyű PIN kódot írjon be."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"A PUK kód legalább  8 számjegyből kell, hogy álljon."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Adja meg újra a helyes PUK kódot. Az ismételt próbálkozással véglegesen letiltja a SIM kártyát."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"A PIN kódok nem egyeznek."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 78bdb2c..85efbf6 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ապակողպում է SIM քարտը ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Սխալ PIN ծածկագիր:"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK կոդը պետք է լինի 8 կամ ավելի թիվ:"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 9c41712..0c42580 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kartu SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kode PIN salah."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ketik PIN yang terdiri dari 4 sampai 8 angka."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kode PUK harus terdiri dari 8 angka atau lebih."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kode PIN tidak cocok"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 47ba24b..d48c88a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Sblocco scheda SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codice PIN errato."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Il PIN deve essere di 4-8 numeri."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Il codice PUK dovrebbe avere almeno otto numeri."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"I codici PIN non corrispondono"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 6ffb7ed..a4ed51c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏מבטל נעילה של כרטיס SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"‏קוד PIN שגוי."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"‏הקלד מספר PIN שאורכו 4 עד 8 ספרות."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"‏קוד PUK צריך להיות בן 8 ספרות או יותר."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"‏הזן מחדש את קוד PUK הנכון. ניסיונות חוזרים ישביתו לצמיתות את כרטיס ה-SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏קודי ה-PIN אינם תואמים"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ניסיונות רבים מדי לשרטוט קו ביטול נעילה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 31ef156..b0c1583 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIMカードのロック解除中…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PINコードが正しくありません。"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"PINは4~8桁の数字で入力してください。"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUKコードは8桁以上の番号です。"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"正しいPUKコードを再入力してください。誤入力を繰り返すと、SIMが永久に無効になるおそれがあります。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PINコードが一致しません"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"パターンの入力を所定の回数以上間違えました。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index c629eb5..49f5cde 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM ბარათის განბლოკვა…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"არასწორი PIN კოდი."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"აკრიფეთ PIN, რომელიც შედგება 4-დან 8 ციფრამდე."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK კოდი უნდა იყოს რვა ან მეტი ციფრისგან შემდგარი."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ხელახლა შეიყვანეთ სწორი PUK კოდი. რამდენიმე წარუმატებელი მცდელობა გამოიწვევს SIM ბარათის დაბლოკვას."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN კოდები არ ემთხვევა"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ნახატი ნიმუშის ძალიან ბევრი მცდელობა"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 59aaafd..cb032a2 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"កំពុង​ដោះ​សោ​​ស៊ីម​កាត..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"កូដ PIN មិន​ត្រឹមត្រូវ។"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"បញ្ចូល​កូដ PIN ដែល​មាន​ពី ៤ ដល់ ៨ លេខ។"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"កូដ PUK គួរ​តែ​មាន​​ ៨ លេខ ឬ​​ច្រើន​ជាង​នេះ។"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"បញ្ចូល​កូដ PUK ម្ដង​ទៀត។ ការ​ព្យាយាម​ដដែល​ច្រើន​ដឹង​នឹង​បិទ​ស៊ីម​កាត​ជា​អចិន្ត្រៃយ៍។"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"កូដ PIN មិន​ដូច​គ្នា"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 948f57c..7d1b7be 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM 카드 잠금해제 중..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 코드가 잘못되었습니다."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 코드는 8자리 이상의 숫자여야 합니다."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM을 영구적으로 사용할 수 없게 됩니다."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 코드가 일치하지 않음"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index db700b9..db595e8 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ປົດລັອກ SIM card..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ພິມລະຫັດ PIN ຄວາມຍາວ 4 ເຖິງ 8 ໂຕເລກ."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"ລະຫັດ PUK ຄວນມີຢ່າງໜ້ອຍ 8 ໂຕເລກ."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 412513e..2d92c17 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Atrakinama SIM kortelė…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netinkamas PIN kodas."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodas turėtų būti mažiausiai 8 skaitmenų."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0bca9e4..9fd25a5 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Notiek SIM kartes atbloķēšana..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN kods nav pareizs."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ievadiet PIN, kas sastāv no 4 līdz 8 cipariem."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodam ir jābūt vismaz 8 ciparus garam."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodi neatbilst."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 87dee58..59c87f7 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картны түгжээг гаргаж байна…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Буруу PIN код."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 тооноос бүтэх PIN-г бичнэ үү."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK код 8-с цөөнгүй тооноос бүтнэ."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Зөв PUK кодыг дахин оруулна уу. Давтан оролдвол SIM нь бүрмөсөн идэвхгүй болгоно."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодууд таарахгүй байна"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Хээ оруулах оролдлого хэт олон"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 8c323de..62cdcaf 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c44fe5c..26074f7 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1491,7 +1491,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Koble til enheten"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skjermen til enheten"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast skjermen til enheten"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søker etter enheter …"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Innstillinger"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Koble fra"</string>
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser opp SIM-kortet ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Feil PIN-kode."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden skal være på åtte eller flere siffer."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e8306cd..da0277e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Simkaart ontgrendelen..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Onjuiste pincode."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Voer een pincode van 4 tot 8 cijfers in."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"De PUK-code is minimaal acht nummers lang."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b3696a4..5838a0b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokowuję kartę SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nieprawidłowy PIN."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Wpisz PIN o długości od 4 do 8 cyfr."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK musi mieć co najmniej 8 cyfr."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponownie podaj poprawny kod PUK. Nieudane próby spowodują trwałe wyłączenie karty SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kody PIN nie pasują"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5457280..238f161 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"A desbloquear cartão SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduza um PIN entre 4 e 8 números."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"O código PUK deve ter 8 ou mais números."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não correspondem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 0baa66d..2969a3fb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"O código PUK deve ter 8 números ou mais."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 8b7ce31..87550879 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -2485,7 +2485,7 @@
     <skip />
     <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
     <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (7553388325654369575) -->
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
     <skip />
     <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5f6b3a4..4d6f459 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index aa77029..330b6d3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -279,9 +279,9 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Приложение сможет получать и обрабатывать WAP-сообщения. Это значит, что оно сможет отслеживать и удалять отправленные на ваше устройство сообщения, не показывая их."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Получение данных о запущенных приложениях"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Приложение сможет получать информацию о недавно запущенных и выполняемых задачах, а следовательно, и о приложениях, используемых на устройстве."</string>
-    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"разрешить взаимодействие со всеми аккаунтами"</string>
+    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Взаимодействие с аккаунтами всех пользователей"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Приложение сможет выполнять действия во всех аккаунтах на этом устройстве. При этом защита от вредоносных приложений может быть недостаточной."</string>
-    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Полное взаимодействие со всеми аккаунтами"</string>
+    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Полное взаимодействие с аккаунтами всех пользователей"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Приложение сможет выполнять любые действия во всех аккаунтах на этом устройстве."</string>
     <string name="permlab_manageUsers" msgid="1676150911672282428">"Управлять аккаунтами"</string>
     <string name="permdesc_manageUsers" msgid="8409306667645355638">"Приложения смогут управлять аккаунтами на этом устройстве (выполнять поиск, создавать и удалять их)"</string>
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблокировка SIM-карты…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неверный PIN-код."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введите PIN-код (от 4 до 8 цифр)."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код должен содержать не менее 8 символов."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не совпадают"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index eed516e..1137fbf 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Prebieha odomykanie karty SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávny kód PIN."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kód PUK musí obsahovať 8 alebo viac číslic."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znova zadajte správny kód PUK. Opakované pokusy zakážu kartu SIM natrvalo."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 2427de5..4064d28 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odklepanje kartice SIM ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Napačna koda PIN."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Vnesite PIN, ki vsebuje od štiri do osem številk."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Koda PUK mora vsebovati 8 ali več števk."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodi PIN se ne ujemata"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 9fd8d8e..3ec4982 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Откључавање SIM картице…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN кôд је нетачан."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Унесите PIN који има од 4 до 8 бројева."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK кôд треба да има 8 или више бројева."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Поново унесите исправни PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d1d9d61..33a9a18 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser upp SIM-kort …"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Fel PIN-kod."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ange en PIN-kod med 4 till 8 siffror."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koden ska vara minst åtta siffror."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koderna stämmer inte överens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0758a38..45a36f2 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -843,7 +843,7 @@
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Jaribu tena"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Majaribio ya Juu ya Kufungua Uso yamezidishwa"</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Inachaji <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Imechajiwa"</string>
+    <string name="lockscreen_charged" msgid="321635745684060624">"Betri imejaa"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Unganisha chaja yako"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Hakuna SIM kadi"</string>
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua SIM kadi..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN iliyo na tarakimu kati ya 4 na 8."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Msimbo wa PUK unafaa kuwa na nambari 8 au zaidi."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index fbc8c75..05cddc5 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"กำลังปลดล็อกซิมการ์ด…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"รหัส PIN ไม่ถูกต้อง"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"พิมพ์ PIN ซึ่งเป็นเลข 4 ถึง 8 หลัก"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"รหัส PUK ต้องเป็นตัวเลขอย่างน้อย 8 หลัก"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 632aa1b..1cb0336 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ina-unlock ang SIM card…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Hindi tamang PIN code."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Mag-type ng PIN na 4 hanggang 8 numero."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Dapat ay 8 numero o higit pa ang PUK code."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Muling ilagay ang tamang PUK code. Permanenteng hindi pagaganahin ang SIM ng mga paulit-ulit na pagtatangka."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Hindi tumutugma ang mga PIN code"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index f052646..7ccf960 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kart kilidi açılıyor…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Yanlış PIN kodu."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 rakamdan oluşan bir PIN girin."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kodu 8 veya daha çok basamaklı bir sayı olmalıdır."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları eşleşmiyor"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 03c30a3..a707a03 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Розблокування SIM-карти…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправильний PIN-код."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введіть PIN-код із 4–8 цифр."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-код має складатися зі щонайменше 8 цифр."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коди не збігаються"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Забагато спроб намалювати ключ"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d08d0ed..d3295a2 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Đang mở khóa thẻ SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Mã PIN không chính xác."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Nhập mã PIN có từ 4 đến 8 số."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Mã PUK phải có từ 8 số trở lên."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Mã PIN không khớp"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7fea933..a9900ec 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 码有误。"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 码应至少包含 8 位数字。"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的 PUK 码。如果尝试错误次数过多,SIM 卡将永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 2f49a8e..eb5c05b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解開上鎖的 SIM 卡..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入一個 4 至 8 位數的 PIN 碼。"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 碼應由 8 個或以上數字組成。"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"請重新輸入正確的 PUK 碼。如果嘗試輸入的次數過多,SIM 卡將永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖案嘗試次數過多"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 116e8f1..00254e2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解除 SIM 卡鎖定..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入 4 到 8 碼的 PIN。"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 碼至少必須為 8 碼。"</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖形嘗試次數過多"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1330ec2..4218dd5 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1526,7 +1526,8 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ivula ikhadi le-SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Iphinikhodi engalungile."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Thayipha iphinikhodi enezinombolo ezingu-4 kuya kwezingu-8."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Ikhodi ye-PUK kufanele ibe yizinombolo ezingu-8 noma eziningi."</string>
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Iphinikhodi ayifani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini"</string>
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index cfb1983..2ec4284 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -156,7 +156,7 @@
      * @param canvas The canvas to draw into
      */
     public void draw(Canvas canvas) {
-        if (canvas != null && canvas.isHardwareAccelerated()) {
+        if (canvas != null && canvas.isHardwareAccelerated() && false) { // temporarily disabled
             final HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
             final DisplayList displayList = getDisplayList(hardwareCanvas);
             if (displayList != null) {
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 88f11db..e4648f6 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -52,6 +52,7 @@
 	# RenderThread stuff
 	LOCAL_SRC_FILES += \
 		renderthread/CanvasContext.cpp \
+		renderthread/RenderProxy.cpp \
 		renderthread/RenderTask.cpp \
 		renderthread/RenderThread.cpp
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index e3d4e2d..5024880 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1589,7 +1589,9 @@
             mWidth(width), mHeight(height) {}
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawShadow(mCasterTransform, mCasterAlpha, mWidth, mHeight);
+        SkPath casterOutline; // TODO: drive with path from view
+        casterOutline.addRect(0, 0, mWidth, mHeight);
+        return renderer.drawShadow(mCasterTransform, mCasterAlpha, &casterOutline);
     }
 
     virtual void output(int level, uint32_t logFlags) const {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 741e953..41f34e5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -3185,28 +3185,43 @@
 }
 
 status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
-        float width, float height) {
+        const SkPath* casterOutline) {
     if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
 
-    // For now, always and scissor
-    // TODO: use quickReject
+    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
     mCaches.enableScissor();
 
     SkPaint paint;
-    paint.setColor(mCaches.propertyShadowStrength << 24);
+    paint.setARGB(mCaches.propertyShadowStrength, 0, 0, 0);
     paint.setAntiAlias(true); // want to use AlphaVertex
 
+    // tessellate caster outline into a 2d polygon
+    Vector<Vertex> casterVertices2d;
+    const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
+    PathTessellator::approximatePathOutlineVertices(*casterOutline,
+            casterRefinementThresholdSquared, casterVertices2d);
+
+    // map 2d caster poly into 3d
+    const int casterVertexCount = casterVertices2d.size();
+    Vector3 casterPolygon[casterVertexCount];
+    for (int i = 0; i < casterVertexCount; i++) {
+        const Vertex& point2d = casterVertices2d[i];
+        casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
+        casterTransform.mapPoint3d(casterPolygon[i]);
+    }
+
+    // draw caster's shadows
     VertexBuffer ambientShadowVertexBuffer;
-    ShadowTessellator::tessellateAmbientShadow(width, height, casterTransform,
+    ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
             ambientShadowVertexBuffer);
     drawVertexBuffer(ambientShadowVertexBuffer, &paint);
 
     VertexBuffer spotShadowVertexBuffer;
     Vector3 lightPosScale(mCaches.propertyLightPosXScale,
             mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
-    ShadowTessellator::tessellateSpotShadow(width, height, lightPosScale,
-            *currentTransform(), getWidth(), getHeight(),
-            casterTransform, spotShadowVertexBuffer);
+    ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
+            lightPosScale, *currentTransform(), getWidth(), getHeight(),
+            spotShadowVertexBuffer);
 
     drawVertexBuffer(spotShadowVertexBuffer, &paint);
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index fb780ce..c8ecdda 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -170,7 +170,7 @@
     int saveLayerDeferred(float left, float top, float right, float bottom,
             int alpha, SkXfermode::Mode mode, int flags);
 
-    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);
+    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags = 1);
     virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
             const SkPaint* paint);
@@ -214,7 +214,7 @@
     virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
 
     status_t drawShadow(const mat4& casterTransform, float casterAlpha,
-            float width, float height);
+            const SkPath* casterOutline);
 
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index c6ce67c..cc56333 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -53,7 +53,7 @@
 namespace android {
 namespace uirenderer {
 
-#define THRESHOLD 0.5f
+#define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f)
 #define ROUND_CAP_THRESH 0.25f
 #define PI 3.1415926535897932f
 
@@ -739,7 +739,8 @@
     // force close if we're filling the path, since fill path expects closed perimeter.
     bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
     bool wasClosed = approximatePathOutlineVertices(path, forceClose,
-            threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, tempVertices);
+            threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY,
+            OUTLINE_REFINE_THRESHOLD_SQUARED, tempVertices);
 
     if (!tempVertices.size()) {
         // path was empty, return without allocating vertex buffer
@@ -824,7 +825,8 @@
     Vector<Vertex> outlineVertices;
     approximatePathOutlineVertices(path, true,
             paintInfo.inverseScaleX * paintInfo.inverseScaleX,
-            paintInfo.inverseScaleY * paintInfo.inverseScaleY, outlineVertices);
+            paintInfo.inverseScaleY * paintInfo.inverseScaleY,
+            OUTLINE_REFINE_THRESHOLD_SQUARED, outlineVertices);
 
     if (!outlineVertices.size()) return;
 
@@ -897,6 +899,11 @@
 // Simple path line approximation
 ///////////////////////////////////////////////////////////////////////////////
 
+bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float thresholdSquared,
+        Vector<Vertex>& outputVertices) {
+    return approximatePathOutlineVertices(path, true, 1.0f, 1.0f, thresholdSquared, outputVertices);
+}
+
 void pushToVector(Vector<Vertex>& vertices, float x, float y) {
     // TODO: make this not yuck
     vertices.push();
@@ -905,7 +912,8 @@
 }
 
 bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
-        float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) {
+        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
+        Vector<Vertex>& outputVertices) {
     ATRACE_CALL();
 
     // TODO: to support joins other than sharp miter, join vertices should be labelled in the
@@ -932,7 +940,7 @@
                         pts[0].x(), pts[0].y(),
                         pts[2].x(), pts[2].y(),
                         pts[1].x(), pts[1].y(),
-                        sqrInvScaleX, sqrInvScaleY, outputVertices);
+                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                 break;
             case SkPath::kCubic_Verb:
                 ALOGV("kCubic_Verb");
@@ -941,7 +949,7 @@
                         pts[1].x(), pts[1].y(),
                         pts[3].x(), pts[3].y(),
                         pts[2].x(), pts[2].y(),
-                        sqrInvScaleX, sqrInvScaleY, outputVertices);
+                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                 break;
             default:
                 break;
@@ -964,7 +972,8 @@
 void PathTessellator::recursiveCubicBezierVertices(
         float p1x, float p1y, float c1x, float c1y,
         float p2x, float p2y, float c2x, float c2y,
-        float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) {
+        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
+        Vector<Vertex>& outputVertices) {
     float dx = p2x - p1x;
     float dy = p2y - p1y;
     float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -973,7 +982,7 @@
 
     // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
 
-    if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
         // below thresh, draw line by adding endpoint
         pushToVector(outputVertices, p2x, p2y);
     } else {
@@ -997,11 +1006,11 @@
         recursiveCubicBezierVertices(
                 p1x, p1y, p1c1x, p1c1y,
                 mx, my, p1c1c2x, p1c1c2y,
-                sqrInvScaleX, sqrInvScaleY, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
         recursiveCubicBezierVertices(
                 mx, my, p2c1c2x, p2c1c2y,
                 p2x, p2y, p2c2x, p2c2y,
-                sqrInvScaleX, sqrInvScaleY, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
     }
 }
 
@@ -1009,12 +1018,13 @@
         float ax, float ay,
         float bx, float by,
         float cx, float cy,
-        float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) {
+        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
+        Vector<Vertex>& outputVertices) {
     float dx = bx - ax;
     float dy = by - ay;
     float d = (cx - bx) * dy - (cy - by) * dx;
 
-    if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
         // below thresh, draw line by adding endpoint
         pushToVector(outputVertices, bx, by);
     } else {
@@ -1028,9 +1038,9 @@
         float my = (acy + bcy) * 0.5f;
 
         recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
-                sqrInvScaleX, sqrInvScaleY, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
         recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
-                sqrInvScaleX, sqrInvScaleY, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
     }
 }
 
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index e43b101..a215b7a 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -31,18 +31,64 @@
 public:
     static void expandBoundsForStroke(SkRect& bounds, const SkPaint* paint);
 
+    /**
+     * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
+     * triangle strip. Note: joins are not currently supported.
+     *
+     * @param path The path to be approximated
+     * @param paint The paint the path will be drawn with, indicating AA, painting style
+     *        (stroke vs fill), stroke width, stroke cap & join style, etc.
+     * @param transform The transform the path is to be drawn with, used to drive stretch-aware path
+     *        vertex approximation, and correct AA ramp offsetting.
+     * @param vertexBuffer The output buffer
+     */
     static void tessellatePath(const SkPath& path, const SkPaint* paint,
             const mat4& transform, VertexBuffer& vertexBuffer);
 
+    /**
+     * Populates a VertexBuffer with a tessellated approximation of points as a single triangle
+     * strip (with degenerate tris separating), respecting the shape defined by the paint cap.
+     *
+     * @param points The center vertices of the points to be drawn
+     * @param count The number of floats making up the point vertices
+     * @param paint The paint the points will be drawn with indicating AA, stroke width & cap
+     * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+     *        vertex approximation, and correct AA ramp offsetting
+     * @param bounds An output rectangle, which returns the total area covered by the output buffer
+     * @param vertexBuffer The output buffer
+     */
     static void tessellatePoints(const float* points, int count, const SkPaint* paint,
             const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer);
 
+    /**
+     * Populates a VertexBuffer with a tessellated approximation of lines as a single triangle
+     * strip (with degenerate tris separating).
+     *
+     * @param points Pairs of endpoints defining the lines to be drawn
+     * @param count The number of floats making up the line vertices
+     * @param paint The paint the lines will be drawn with indicating AA, stroke width & cap
+     * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+     *        vertex approximation, and correct AA ramp offsetting
+     * @param bounds An output rectangle, which returns the total area covered by the output buffer
+     * @param vertexBuffer The output buffer
+     */
     static void tessellateLines(const float* points, int count, const SkPaint* paint,
             const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer);
 
+    /**
+     * Approximates a convex, CW outline into a Vector of 2d vertices.
+     *
+     * @param path The outline to be approximated
+     * @param thresholdSquared The threshold of acceptable error (in pixels) when approximating
+     * @param outputVertices An empty Vector which will be populated with the output
+     */
+    static bool approximatePathOutlineVertices(const SkPath &path, float thresholdSquared,
+            Vector<Vertex> &outputVertices);
+
 private:
     static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
-        float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex> &outputVertices);
+            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
+            Vector<Vertex> &outputVertices);
 
 /*
   endpoints a & b,
@@ -52,7 +98,7 @@
             float ax, float ay,
             float bx, float by,
             float cx, float cy,
-            float sqrInvScaleX, float sqrInvScaleY,
+            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
             Vector<Vertex> &outputVertices);
 
 /*
@@ -64,7 +110,7 @@
             float c1x, float c1y,
             float p2x, float p2y,
             float c2x, float c2y,
-            float sqrInvScaleX, float sqrInvScaleY,
+            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
             Vector<Vertex> &outputVertices);
 };
 
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 9d4e83e..4799b32 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -247,8 +247,6 @@
 
     // TODO: rename for consistency
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty) = 0;
-
-private:
 }; // class Renderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 6dfd925..7700ea0 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -31,46 +31,8 @@
     return a > b ? a : b;
 }
 
-// TODO: Support path as the input of the polygon instead of the rect's width
-// and height. And the z values need to be computed according to the
-// transformation for each vertex.
-/**
- * Generate the polygon for the caster.
- *
- * @param width the width of the caster
- * @param height the height of the caster
- * @param casterTransform transformation info of the caster
- * @param polygon return the caster's polygon
- *
- */
-void ShadowTessellator::generateCasterPolygon(float width, float height,
-        const mat4& casterTransform, int vertexCount, Vector3* polygon) {
-    Rect blockRect(0, 0, width, height);
-    polygon[0].x = blockRect.left;
-    polygon[0].y = blockRect.top;
-    polygon[0].z = 0;
-    polygon[1].x = blockRect.right;
-    polygon[1].y = blockRect.top;
-    polygon[1].z = 0;
-    polygon[2].x = blockRect.right;
-    polygon[2].y = blockRect.bottom;
-    polygon[2].z = 0;
-    polygon[3].x = blockRect.left;
-    polygon[3].y = blockRect.bottom;
-    polygon[3].z = 0;
-    casterTransform.mapPoint3d(polygon[0]);
-    casterTransform.mapPoint3d(polygon[1]);
-    casterTransform.mapPoint3d(polygon[2]);
-    casterTransform.mapPoint3d(polygon[3]);
-}
-
-void ShadowTessellator::tessellateAmbientShadow(float width, float height,
-        const mat4& casterTransform, VertexBuffer& shadowVertexBuffer) {
-
-    const int vertexCount = 4;
-    Vector3 polygon[vertexCount];
-    generateCasterPolygon(width, height, casterTransform, vertexCount, polygon);
-
+void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
+        VertexBuffer& shadowVertexBuffer) {
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
     const int rays = 128;
@@ -79,19 +41,14 @@
     const float heightFactor = 128;
     const float geomFactor = 64;
 
-    AmbientShadow::createAmbientShadow(polygon, vertexCount, rays, layers, strength,
+    AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount, rays, layers, strength,
             heightFactor, geomFactor, shadowVertexBuffer);
 
 }
 
-void ShadowTessellator::tessellateSpotShadow(float width, float height,
+void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
         const Vector3& lightPosScale, const mat4& receiverTransform,
-        int screenWidth, int screenHeight, const mat4& casterTransform,
-        VertexBuffer& shadowVertexBuffer) {
-    const int vertexCount = 4;
-    Vector3 polygon[vertexCount];
-    generateCasterPolygon(width, height, casterTransform, vertexCount, polygon);
-
+        int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
     const int rays = 256;
@@ -113,7 +70,7 @@
     const float lightSize = maximal / 4;
     const int lightVertexCount = 16;
 
-    SpotShadow::createSpotShadow(polygon, vertexCount, lightCenter, lightSize,
+    SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter, lightSize,
             lightVertexCount, rays, layers, strength, shadowVertexBuffer);
 
 }
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 2399f8f..ef95609 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -26,18 +26,12 @@
 
 class ShadowTessellator {
 public:
-    static void tessellateAmbientShadow(float width, float height,
-            const mat4& casterTransform, VertexBuffer& shadowVertexBuffer);
-
-    static void tessellateSpotShadow(float width, float height,
-            const Vector3& lightPosScale, const mat4& receiverTransform,
-            int screenWidth, int screenHeight, const mat4& casterTransform,
+    static void tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
             VertexBuffer& shadowVertexBuffer);
 
-private:
-    static void generateCasterPolygon(float width, float height,
-            const mat4& casterTransform, int vertexCount, Vector3* polygon);
-
+    static void tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
+            const Vector3& lightPosScale, const mat4& receiverTransform,
+            int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
 }; // ShadowTessellator
 
 }; // namespace uirenderer
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ffb8a32..a848c8f 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -19,14 +19,22 @@
 #include "CanvasContext.h"
 
 #include <cutils/properties.h>
+#include <private/hwui/DrawGlInfo.h>
 #include <strings.h>
 
+#include "RenderThread.h"
 #include "../Caches.h"
+#include "../OpenGLRenderer.h"
 #include "../Stencil.h"
 
 #define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
 #define GLES_VERSION 2
 
+#ifdef USE_OPENGL_RENDERER
+// Android-specific addition that is used to show when frames began in systrace
+EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+#endif
+
 namespace android {
 namespace uirenderer {
 namespace renderthread {
@@ -69,19 +77,19 @@
 public:
     static GlobalContext* get();
 
-    // Returns true if EGL was initialized,
-    // false if it was already initialized
-    bool initialize();
+    // Returns true on success, false on failure
+    void initialize();
 
-    bool usePBufferSurface();
+    void usePBufferSurface();
     EGLSurface createSurface(EGLNativeWindowType window);
     void destroySurface(EGLSurface surface);
 
     void destroy();
 
     bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
-    bool makeCurrent(EGLSurface surface);
-    bool swapBuffers(EGLSurface surface);
+    void makeCurrent(EGLSurface surface);
+    void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
+    void swapBuffers(EGLSurface surface);
 
     bool enableDirtyRegions(EGLSurface surface);
 
@@ -90,8 +98,9 @@
     // GlobalContext is never destroyed, method is purposely not implemented
     ~GlobalContext();
 
-    bool loadConfig();
-    bool createContext();
+    void loadConfig();
+    void createContext();
+    void initAtlas();
 
     static GlobalContext* sContext;
 
@@ -126,33 +135,27 @@
     ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
 }
 
-bool GlobalContext::initialize() {
-    if (mEglDisplay != EGL_NO_DISPLAY) return false;
+void GlobalContext::initialize() {
+    if (mEglDisplay != EGL_NO_DISPLAY) return;
 
     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (mEglDisplay == EGL_NO_DISPLAY) {
-        ALOGE("Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
-        return false;
-    }
+    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
+            "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
 
     EGLint major, minor;
-    if (eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE) {
-        ALOGE("Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
-        return false;
-    }
+    LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
+            "Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
+
     ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
 
-    if (!loadConfig()) {
-        return false;
-    }
-    if (!createContext()) {
-        return false;
-    }
-
-    return true;
+    loadConfig();
+    createContext();
+    usePBufferSurface();
+    Caches::getInstance().init();
+    initAtlas();
 }
 
-bool GlobalContext::loadConfig() {
+void GlobalContext::loadConfig() {
     EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
     EGLint attribs[] = {
             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -177,31 +180,32 @@
             mCanSetDirtyRegions = false;
             loadConfig();
         } else {
-            ALOGE("Failed to choose config, error = %s", egl_error_str());
-            return false;
+            LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
         }
     }
-    return true;
 }
 
-bool GlobalContext::createContext() {
+void GlobalContext::createContext() {
     EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
     mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
-    if (mEglContext == EGL_NO_CONTEXT) {
-        ALOGE("Failed to create context, error = %s", egl_error_str());
-        return false;
-    }
-    return true;
+    LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
+        "Failed to create context, error = %s", egl_error_str());
 }
 
-bool GlobalContext::usePBufferSurface() {
-    if (mEglDisplay == EGL_NO_DISPLAY) return false;
+void GlobalContext::initAtlas() {
+    // TODO implement
+    // For now just run without an atlas
+}
+
+void GlobalContext::usePBufferSurface() {
+    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
+            "usePBufferSurface() called on uninitialized GlobalContext!");
 
     if (mPBufferSurface == EGL_NO_SURFACE) {
         EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
         mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
     }
-    return makeCurrent(mPBufferSurface);
+    makeCurrent(mPBufferSurface);
 }
 
 EGLSurface GlobalContext::createSurface(EGLNativeWindowType window) {
@@ -238,8 +242,8 @@
     mCurrentSurface = EGL_NO_SURFACE;
 }
 
-bool GlobalContext::makeCurrent(EGLSurface surface) {
-    if (isCurrent(surface)) return true;
+void GlobalContext::makeCurrent(EGLSurface surface) {
+    if (isCurrent(surface)) return;
 
     if (surface == EGL_NO_SURFACE) {
         // If we are setting EGL_NO_SURFACE we don't care about any of the potential
@@ -247,19 +251,31 @@
         // destroyed in which case the current context is already NO_CONTEXT
         eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
-        ALOGE("Failed to make current on surface %p, error=%s", (void*)surface, egl_error_str());
-        return false;
+        LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
+                (void*)surface, egl_error_str());
     }
     mCurrentSurface = surface;
-    return true;
 }
 
-bool GlobalContext::swapBuffers(EGLSurface surface) {
-    if (!eglSwapBuffers(mEglDisplay, surface)) {
-        ALOGW("eglSwapBuffers failed on surface %p, error=%s", (void*)surface, egl_error_str());
-        return false;
+void GlobalContext::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
+    LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
+            "Tried to beginFrame on EGL_NO_SURFACE!");
+    makeCurrent(surface);
+    if (width) {
+        eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
     }
-    return true;
+    if (height) {
+        eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
+    }
+    eglBeginFrame(mEglDisplay, surface);
+}
+
+void GlobalContext::swapBuffers(EGLSurface surface) {
+    eglSwapBuffers(mEglDisplay, surface);
+    EGLint err = eglGetError();
+    // TODO: Check whether we need to special case EGL_CONTEXT_LOST
+    LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
+            "Encountered EGL error %d %s during rendering", err, egl_error_str(err));
 }
 
 bool GlobalContext::enableDirtyRegions(EGLSurface surface) {
@@ -283,17 +299,32 @@
     return value == EGL_BUFFER_PRESERVED;
 }
 
-CanvasContext::CanvasContext()
-        : mEglSurface(EGL_NO_SURFACE)
-        , mDirtyRegionsEnabled(false) {
+CanvasContext::CanvasContext(bool translucent)
+        : mRenderThread(RenderThread::getInstance())
+        , mEglSurface(EGL_NO_SURFACE)
+        , mDirtyRegionsEnabled(false)
+        , mOpaque(!translucent)
+        , mCanvas(0)
+        , mHaveNewSurface(false)
+        , mInvokeFunctorsPending(false)
+        , mInvokeFunctorsTask(this) {
     mGlobalContext = GlobalContext::get();
 }
 
 CanvasContext::~CanvasContext() {
+    removeFunctorsTask();
+    destroyCanvas();
+}
+
+void CanvasContext::destroyCanvas() {
+    if (mCanvas) {
+        delete mCanvas;
+        mCanvas = 0;
+    }
     setSurface(NULL);
 }
 
-bool CanvasContext::setSurface(EGLNativeWindowType window) {
+void CanvasContext::setSurface(EGLNativeWindowType window) {
     if (mEglSurface != EGL_NO_SURFACE) {
         mGlobalContext->destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -301,24 +332,134 @@
 
     if (window) {
         mEglSurface = mGlobalContext->createSurface(window);
+        LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+                "Failed to create EGLSurface for window %p, eglErr = %s",
+                (void*) window, egl_error_str());
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
         mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+        mHaveNewSurface = true;
     }
-    return !window || mEglSurface != EGL_NO_SURFACE;
 }
 
-bool CanvasContext::swapBuffers() {
-    return mGlobalContext->swapBuffers(mEglSurface);
+void CanvasContext::swapBuffers() {
+    mGlobalContext->swapBuffers(mEglSurface);
+    mHaveNewSurface = false;
 }
 
-bool CanvasContext::makeCurrent() {
-    return mGlobalContext->makeCurrent(mEglSurface);
+void CanvasContext::makeCurrent() {
+    mGlobalContext->makeCurrent(mEglSurface);
 }
 
-bool CanvasContext::useGlobalPBufferSurface() {
-    return GlobalContext::get()->usePBufferSurface();
+bool CanvasContext::initialize(EGLNativeWindowType window) {
+    if (mCanvas) return false;
+    setSurface(window);
+    makeCurrent();
+    mCanvas = new OpenGLRenderer();
+    mCanvas->initProperties();
+    return true;
+}
+
+void CanvasContext::updateSurface(EGLNativeWindowType window) {
+    setSurface(window);
+    makeCurrent();
+}
+
+void CanvasContext::setup(int width, int height) {
+    if (!mCanvas) return;
+    mCanvas->setViewport(width, height);
+}
+
+void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) {
+    LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
+            "drawDisplayList called on a context with no canvas or surface!");
+
+    EGLint width, height;
+    mGlobalContext->beginFrame(mEglSurface, &width, &height);
+    if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
+        mCanvas->setViewport(width, height);
+        dirty = NULL;
+    } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
+        dirty = NULL;
+    }
+
+    status_t status;
+    if (dirty) {
+        status = mCanvas->prepareDirty(dirty->left, dirty->top,
+                dirty->right, dirty->bottom, mOpaque);
+    } else {
+        status = mCanvas->prepare(mOpaque);
+    }
+
+    Rect outBounds;
+    status |= mCanvas->drawDisplayList(displayList, outBounds);
+    handleFunctorStatus(status, outBounds);
+
+    // TODO: Draw debug info
+    // TODO: Performance tracking
+
+    mCanvas->finish();
+
+    if (status & DrawGlInfo::kStatusDrew) {
+        swapBuffers();
+    }
+}
+
+void InvokeFunctorsTask::run() {
+    mContext->invokeFunctors();
+}
+
+void CanvasContext::attachFunctor(Functor* functor) {
+    if (!mCanvas) return;
+
+    mCanvas->attachFunctor(functor);
+    removeFunctorsTask();
+    queueFunctorsTask(0);
+}
+
+void CanvasContext::detachFunctor(Functor* functor) {
+    if (!mCanvas) return;
+
+    mCanvas->detachFunctor(functor);
+}
+
+void CanvasContext::invokeFunctors() {
+    mInvokeFunctorsPending = false;
+
+    if (!mCanvas) return;
+
+    makeCurrent();
+    Rect dirty;
+    int status = mCanvas->invokeFunctors(dirty);
+    handleFunctorStatus(status, dirty);
+}
+
+void CanvasContext::handleFunctorStatus(int status, const Rect& redrawClip) {
+    if (status & DrawGlInfo::kStatusDraw) {
+        // TODO: Invalidate the redrawClip
+        // Do we need to post to ViewRootImpl like the current renderer?
+        // Can we just enqueue ourselves to re-invoke the same display list?
+        // Something else entirely? Does ChromiumView still want this in a
+        // RenderThread world?
+    }
+
+    if (status & DrawGlInfo::kStatusInvoke) {
+        queueFunctorsTask();
+    }
+}
+
+void CanvasContext::removeFunctorsTask() {
+    if (!mInvokeFunctorsPending) return;
+
+    mRenderThread.remove(&mInvokeFunctorsTask);
+}
+
+void CanvasContext::queueFunctorsTask(int delayMs) {
+    if (mInvokeFunctorsPending) return;
+
+    mInvokeFunctorsPending = true;
+    mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 77ae737..2daa905 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -19,31 +19,75 @@
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
+#include <utils/Functor.h>
+
+#include "RenderTask.h"
+
+#define FUNCTOR_PROCESS_DELAY 4
 
 namespace android {
 namespace uirenderer {
+
+class DisplayList;
+class OpenGLRenderer;
+class Rect;
+
 namespace renderthread {
 
 class GlobalContext;
+class CanvasContext;
+class RenderThread;
+
+class InvokeFunctorsTask : public RenderTask {
+public:
+    InvokeFunctorsTask(CanvasContext* context)
+        : mContext(context) {}
+
+    virtual void run();
+
+private:
+    CanvasContext* mContext;
+};
 
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 class CanvasContext {
 public:
-    ANDROID_API CanvasContext();
-    ANDROID_API ~CanvasContext();
+    CanvasContext(bool translucent);
+    ~CanvasContext();
 
-    ANDROID_API bool setSurface(EGLNativeWindowType window);
-    ANDROID_API bool swapBuffers();
-    ANDROID_API bool makeCurrent();
+    bool initialize(EGLNativeWindowType window);
+    void updateSurface(EGLNativeWindowType window);
+    void setup(int width, int height);
+    void drawDisplayList(DisplayList* displayList, Rect* dirty);
+    void destroyCanvas();
 
-    ANDROID_API static bool useGlobalPBufferSurface();
+    void attachFunctor(Functor* functor);
+    void detachFunctor(Functor* functor);
 
 private:
+    void setSurface(EGLNativeWindowType window);
+    void swapBuffers();
+    void makeCurrent();
+
+    friend class InvokeFunctorsTask;
+    void invokeFunctors();
+    void handleFunctorStatus(int status, const Rect& redrawClip);
+    void removeFunctorsTask();
+    void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
 
     GlobalContext* mGlobalContext;
+    RenderThread& mRenderThread;
     EGLSurface mEglSurface;
     bool mDirtyRegionsEnabled;
+
+    bool mOpaque;
+    OpenGLRenderer* mCanvas;
+    bool mHaveNewSurface;
+
+    bool mInvokeFunctorsPending;
+    InvokeFunctorsTask mInvokeFunctorsTask;
+
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
new file mode 100644
index 0000000..25badac
--- /dev/null
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2013 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 "RenderProxy"
+
+#include "RenderProxy.h"
+
+#include "CanvasContext.h"
+#include "RenderTask.h"
+#include "RenderThread.h"
+
+#include "../DisplayList.h"
+#include "../Rect.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+#define ARGS(method) method ## Args
+
+#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
+#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
+#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
+#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
+#define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
+    typedef struct { \
+        a1; a2; a3; a4; a5; a6; a7; a8; \
+    } ARGS(name); \
+    static void* Bridge_ ## name(ARGS(name)* args)
+
+#define SETUP_TASK(method) \
+    LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
+        "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
+                METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
+    MethodInvokeRenderTask* task = createTask((RunnableMethod) Bridge_ ## method); \
+    ARGS(method) *args = (ARGS(method) *) task->payload()
+
+CREATE_BRIDGE1(createContext, bool translucent) {
+    return new CanvasContext(args->translucent);
+}
+
+RenderProxy::RenderProxy(bool translucent)
+        : mRenderThread(RenderThread::getInstance())
+        , mContext(0) {
+    SETUP_TASK(createContext);
+    args->translucent = translucent;
+    mContext = (CanvasContext*) postAndWait(task);
+}
+
+RenderProxy::~RenderProxy() {
+    destroyContext();
+}
+
+CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
+    delete args->context;
+    return NULL;
+}
+
+void RenderProxy::destroyContext() {
+    if (mContext) {
+        SETUP_TASK(destroyContext);
+        args->context = mContext;
+        mContext = 0;
+        post(task);
+    }
+}
+
+CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
+    return (void*) args->context->initialize(args->window);
+}
+
+bool RenderProxy::initialize(EGLNativeWindowType window) {
+    SETUP_TASK(initialize);
+    args->context = mContext;
+    args->window = window;
+    return (bool) postAndWait(task);
+}
+
+CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window) {
+    args->context->updateSurface(args->window);
+    return NULL;
+}
+
+void RenderProxy::updateSurface(EGLNativeWindowType window) {
+    SETUP_TASK(updateSurface);
+    args->context = mContext;
+    args->window = window;
+    post(task);
+}
+
+CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
+    args->context->setup(args->width, args->height);
+    return NULL;
+}
+
+void RenderProxy::setup(int width, int height) {
+    SETUP_TASK(setup);
+    args->context = mContext;
+    args->width = width;
+    args->height = height;
+    post(task);
+}
+
+CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
+        Rect dirty) {
+    Rect* dirty = &args->dirty;
+    if (dirty->bottom == -1 && dirty->left == -1 &&
+            dirty->top == -1 && dirty->right == -1) {
+        dirty = 0;
+    }
+    args->context->drawDisplayList(args->displayList, dirty);
+    return NULL;
+}
+
+void RenderProxy::drawDisplayList(DisplayList* displayList,
+        int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
+    SETUP_TASK(drawDisplayList);
+    args->context = mContext;
+    args->displayList = displayList;
+    args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+    // TODO: Switch to post() once some form of thread safety strategy is in place
+    postAndWait(task);
+}
+
+CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) {
+    args->context->destroyCanvas();
+    return NULL;
+}
+
+void RenderProxy::destroyCanvas() {
+    SETUP_TASK(destroyCanvas);
+    args->context = mContext;
+    post(task);
+}
+
+CREATE_BRIDGE2(attachFunctor, CanvasContext* context, Functor* functor) {
+    args->context->attachFunctor(args->functor);
+    return NULL;
+}
+
+void RenderProxy::attachFunctor(Functor* functor) {
+    SETUP_TASK(attachFunctor);
+    args->context = mContext;
+    args->functor = functor;
+    post(task);
+}
+
+CREATE_BRIDGE2(detachFunctor, CanvasContext* context, Functor* functor) {
+    args->context->detachFunctor(args->functor);
+    return NULL;
+}
+
+void RenderProxy::detachFunctor(Functor* functor) {
+    SETUP_TASK(detachFunctor);
+    args->context = mContext;
+    args->functor = functor;
+    post(task);
+}
+
+MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
+    // TODO: Consider having a small pool of these to avoid alloc churn
+    return new MethodInvokeRenderTask(method);
+}
+
+void RenderProxy::post(RenderTask* task) {
+    mRenderThread.queue(task);
+}
+
+void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
+    void* retval;
+    task->setReturnPtr(&retval);
+    SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition);
+    AutoMutex _lock(mSyncMutex);
+    mRenderThread.queue(&syncTask);
+    mSyncCondition.wait(mSyncMutex);
+    return retval;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
new file mode 100644
index 0000000..113c5a8
--- /dev/null
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 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 RENDERPROXY_H_
+#define RENDERPROXY_H_
+
+#include "RenderTask.h"
+
+#include <cutils/compiler.h>
+#include <EGL/egl.h>
+#include <utils/Condition.h>
+#include <utils/Functor.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace uirenderer {
+
+class DisplayList;
+class Rect;
+
+namespace renderthread {
+
+class CanvasContext;
+class ErrorChannel;
+class RenderThread;
+class RenderProxyBridge;
+
+/*
+ * RenderProxy is strictly single threaded. All methods must be invoked on the owning
+ * thread. It is important to note that RenderProxy may be deleted while it has
+ * tasks post()'d as a result. Therefore any RenderTask that is post()'d must not
+ * reference RenderProxy or any of its fields. The exception here is that postAndWait()
+ * references RenderProxy fields. This is safe as RenderProxy cannot
+ * be deleted if it is blocked inside a call.
+ */
+class ANDROID_API RenderProxy {
+public:
+    ANDROID_API RenderProxy(bool translucent);
+    ANDROID_API virtual ~RenderProxy();
+
+    ANDROID_API bool initialize(EGLNativeWindowType window);
+    ANDROID_API void updateSurface(EGLNativeWindowType window);
+    ANDROID_API void setup(int width, int height);
+    ANDROID_API void drawDisplayList(DisplayList* displayList,
+            int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+    ANDROID_API void destroyCanvas();
+
+    ANDROID_API void attachFunctor(Functor* functor);
+    ANDROID_API void detachFunctor(Functor* functor);
+
+private:
+    RenderThread& mRenderThread;
+    CanvasContext* mContext;
+
+    Mutex mSyncMutex;
+    Condition mSyncCondition;
+
+    void destroyContext();
+
+    MethodInvokeRenderTask* createTask(RunnableMethod method);
+    void post(RenderTask* task);
+    void* postAndWait(MethodInvokeRenderTask* task);
+
+    // Friend class to help with bridging
+    friend class RenderProxyBridge;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+#endif /* RENDERPROXY_H_ */
diff --git a/libs/hwui/renderthread/RenderTask.cpp b/libs/hwui/renderthread/RenderTask.cpp
index 2da91c5..7ca61e4 100644
--- a/libs/hwui/renderthread/RenderTask.cpp
+++ b/libs/hwui/renderthread/RenderTask.cpp
@@ -19,15 +19,18 @@
 #include "RenderTask.h"
 
 #include <utils/Log.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
 
 namespace android {
 namespace uirenderer {
 namespace renderthread {
 
-RenderTask::RenderTask() : mNext(0) {
-}
-
-RenderTask::~RenderTask() {
+void SignalingRenderTask::run() {
+    mTask->run();
+    mLock->lock();
+    mSignal->signal();
+    mLock->unlock();
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index 865b1e6..9fe7573 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -18,19 +18,79 @@
 #define RENDERTASK_H_
 
 #include <cutils/compiler.h>
+#include <utils/Timers.h>
 
 namespace android {
+class Mutex;
+class Condition;
 namespace uirenderer {
 namespace renderthread {
 
+#define METHOD_INVOKE_PAYLOAD_SIZE (8 * sizeof(void*))
+
+/*
+ * Notes about memory management
+ *
+ * RenderThread will only invoke RenderTask::run(). It is the responsibility
+ * of the RenderTask to know if it needs to suicide at the end of run() or
+ * if some other lifecycle is being used. As such, it is not valid to reference
+ * anything on RenderTask after the first call to run().
+ *
+ * For example SignalingRenderTask
+ * is expected to be stack allocated by the calling thread, so it does not
+ * suicide in run() but instead relies on the caller to destroy it.
+ *
+ * MethodInvokeRenderTask however is currently allocated with new, so it will
+ * suicide at the end of run(). TODO: Replace this with a small pool to avoid
+ * malloc/free churn of small objects?
+ */
+
 class ANDROID_API RenderTask {
 public:
-    ANDROID_API RenderTask();
-    ANDROID_API virtual ~RenderTask();
+    ANDROID_API RenderTask() : mNext(0), mRunAt(0) {}
+    ANDROID_API virtual ~RenderTask() {}
 
     ANDROID_API virtual void run() = 0;
 
     RenderTask* mNext;
+    nsecs_t mRunAt;
+};
+
+class SignalingRenderTask : public RenderTask {
+public:
+    // Takes ownership of task, caller owns lock and signal
+    SignalingRenderTask(RenderTask* task, Mutex* lock, Condition* signal)
+            : mTask(task), mLock(lock), mSignal(signal) {}
+    virtual void run();
+
+private:
+    RenderTask* mTask;
+    Mutex* mLock;
+    Condition* mSignal;
+};
+
+typedef void* (*RunnableMethod)(void* data);
+
+class MethodInvokeRenderTask : public RenderTask {
+public:
+    MethodInvokeRenderTask(RunnableMethod method)
+        : mMethod(method), mReturnPtr(0) {}
+
+    void* payload() { return mData; }
+    void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
+
+    virtual void run() {
+        void* retval = mMethod(mData);
+        if (mReturnPtr) {
+            *mReturnPtr = retval;
+        }
+        // Commit suicide
+        delete this;
+    }
+private:
+    RunnableMethod mMethod;
+    char mData[METHOD_INVOKE_PAYLOAD_SIZE];
+    void** mReturnPtr;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index bccd6e6..e4ec164 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -18,6 +18,8 @@
 
 #include "RenderThread.h"
 
+#include "CanvasContext.h"
+#include "RenderProxy.h"
 #include <utils/Log.h>
 
 namespace android {
@@ -27,8 +29,82 @@
 namespace uirenderer {
 namespace renderthread {
 
+TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
+
+RenderTask* TaskQueue::next() {
+    RenderTask* ret = mHead;
+    if (ret) {
+        mHead = ret->mNext;
+        if (!mHead) {
+            mTail = 0;
+        }
+        ret->mNext = 0;
+    }
+    return ret;
+}
+
+RenderTask* TaskQueue::peek() {
+    return mHead;
+}
+
+void TaskQueue::queue(RenderTask* task) {
+    // Since the RenderTask itself forms the linked list it is not allowed
+    // to have the same task queued twice
+    LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
+    if (mTail) {
+        // Fast path if we can just append
+        if (mTail->mRunAt <= task->mRunAt) {
+            mTail->mNext = task;
+            mTail = task;
+        } else {
+            // Need to find the proper insertion point
+            RenderTask* previous = 0;
+            RenderTask* next = mHead;
+            while (next && next->mRunAt <= task->mRunAt) {
+                previous = next;
+                next = next->mNext;
+            }
+            if (!previous) {
+                task->mNext = mHead;
+                mHead = task;
+            } else {
+                previous->mNext = task;
+                if (next) {
+                    task->mNext = next;
+                } else {
+                    mTail = task;
+                }
+            }
+        }
+    } else {
+        mTail = mHead = task;
+    }
+}
+
+void TaskQueue::remove(RenderTask* task) {
+    // TaskQueue is strict here to enforce that users are keeping track of
+    // their RenderTasks due to how their memory is managed
+    LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
+            "Cannot remove a task that isn't in the queue!");
+
+    // If task is the head we can just call next() to pop it off
+    // Otherwise we need to scan through to find the task before it
+    if (peek() == task) {
+        next();
+    } else {
+        RenderTask* previous = mHead;
+        while (previous->mNext != task) {
+            previous = previous->mNext;
+        }
+        previous->mNext = task->mNext;
+        if (mTail == task) {
+            mTail = previous;
+        }
+    }
+}
+
 RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
-        , mQueueHead(0), mQueueTail(0) {
+        , mNextWakeup(LLONG_MAX) {
     mLooper = new Looper(false);
     run("RenderThread");
 }
@@ -37,16 +113,25 @@
 }
 
 bool RenderThread::threadLoop() {
+    int timeoutMillis = -1;
     for (;;) {
-        int result = mLooper->pollAll(-1);
-        if (result == Looper::POLL_ERROR) {
-            // TODO Something?
-            break;
-        }
+        int result = mLooper->pollAll(timeoutMillis);
+        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
+                "RenderThread Looper POLL_ERROR!");
+
+        nsecs_t nextWakeup;
         // Process our queue, if we have anything
-        while (RenderTask* task = nextTask()) {
+        while (RenderTask* task = nextTask(&nextWakeup)) {
             task->run();
-            delete task;
+            // task may have deleted itself, do not reference it again
+        }
+        if (nextWakeup == LLONG_MAX) {
+            timeoutMillis = -1;
+        } else {
+            timeoutMillis = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
+            if (timeoutMillis < 0) {
+                timeoutMillis = 0;
+            }
         }
     }
 
@@ -55,30 +140,40 @@
 
 void RenderThread::queue(RenderTask* task) {
     AutoMutex _lock(mLock);
-    if (mQueueTail) {
-        mQueueTail->mNext = task;
-    } else {
-        mQueueHead = task;
-    }
-    mQueueTail = task;
-    if (mQueueHead == task) {
-        // Only wake if this is the first task
+    mQueue.queue(task);
+    if (mNextWakeup && task->mRunAt < mNextWakeup) {
+        mNextWakeup = 0;
         mLooper->wake();
     }
 }
 
-RenderTask* RenderThread::nextTask() {
+void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    task->mRunAt = now + delayMs;
+    queue(task);
+}
+
+void RenderThread::remove(RenderTask* task) {
     AutoMutex _lock(mLock);
-    RenderTask* ret = mQueueHead;
-    if (ret) {
-        if (mQueueTail == mQueueHead) {
-            mQueueTail = mQueueHead = 0;
-        } else {
-            mQueueHead = ret->mNext;
+    mQueue.remove(task);
+}
+
+RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
+    AutoMutex _lock(mLock);
+    RenderTask* next = mQueue.peek();
+    if (!next) {
+        mNextWakeup = LLONG_MAX;
+    } else {
+        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
+        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
+            next = mQueue.next();
         }
-        ret->mNext = 0;
+        mNextWakeup = next->mRunAt;
     }
-    return ret;
+    if (nextWakeup) {
+        *nextWakeup = mNextWakeup;
+    }
+    return next;
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 4edd575..e444aa0 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -28,11 +28,27 @@
 namespace uirenderer {
 namespace renderthread {
 
+class TaskQueue {
+public:
+    TaskQueue();
+
+    RenderTask* next();
+    void queue(RenderTask* task);
+    RenderTask* peek();
+    void remove(RenderTask* task);
+
+private:
+    RenderTask* mHead;
+    RenderTask* mTail;
+};
+
 class ANDROID_API RenderThread : public Thread, public Singleton<RenderThread> {
 public:
     // RenderThread takes complete ownership of tasks that are queued
     // and will delete them after they are run
     ANDROID_API void queue(RenderTask* task);
+    void queueDelayed(RenderTask* task, int delayMs);
+    void remove(RenderTask* task);
 
 protected:
     virtual bool threadLoop();
@@ -43,13 +59,16 @@
     RenderThread();
     virtual ~RenderThread();
 
-    RenderTask* nextTask();
+    // Returns the next task to be run. If this returns NULL nextWakeup is set
+    // to the time to requery for the nextTask to run. mNextWakeup is also
+    // set to this time
+    RenderTask* nextTask(nsecs_t* nextWakeup);
 
     sp<Looper> mLooper;
     Mutex mLock;
 
-    RenderTask* mQueueHead;
-    RenderTask* mQueueTail;
+    nsecs_t mNextWakeup;
+    TaskQueue mQueue;
 };
 
 } /* namespace renderthread */
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0fa9d4c..12deaef 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -198,7 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke tilkoblet"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ingen nettverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Send skjermen"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast skjermen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus for fargeinvertering"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1a6e06f..9ed493c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -174,7 +174,7 @@
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hali ya ndege"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Inachaji, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Imechajiwa"</string>
+    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Betri imejaa"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (Vifaa <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Imezimwa"</string>
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index adc60dd..bf8c9da 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -868,7 +868,7 @@
                                     int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
                                     ArrayList<String> pkgList = new ArrayList<String>(1);
                                     pkgList.add(res.pkg.applicationInfo.packageName);
-                                    sendResourcesChangedBroadcast(true, false,
+                                    sendResourcesChangedBroadcast(true, true,
                                             pkgList,uidArray, null);
                                 }
                             }
@@ -11116,7 +11116,7 @@
             if (uidArr != null) {
                 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
             }
-            if (replacing && !mediaStatus) {
+            if (replacing) {
                 extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
             }
             String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE