Merge "Enable networks on screen on"
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 685b7ba..9eecdc1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1002,10 +1002,20 @@
         }
     }
 
-    private static void setupProxyListener(Context context) {
+    /*
+     * A variable to track if there is a receiver added for PROXY_CHANGE_ACTION
+     */
+    private static boolean sProxyReceiverAdded;
+
+    private static synchronized void setupProxyListener(Context context) {
+        if (sProxyReceiverAdded) {
+            return;
+        }
         IntentFilter filter = new IntentFilter();
         filter.addAction(Proxy.PROXY_CHANGE_ACTION);
-        Intent currentProxy = context.getApplicationContext().registerReceiver(new ProxyReceiver(), filter);
+        Intent currentProxy = context.getApplicationContext().registerReceiver(
+                new ProxyReceiver(), filter);
+        sProxyReceiverAdded = true;
         if (currentProxy != null) {
             handleProxyBroadcast(currentProxy);
         }
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 1bb2a57..6a471ad 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -57,7 +57,7 @@
  * Base class for Instrumented tests for the Download Manager.
  */
 public class DownloadManagerBaseTest extends InstrumentationTestCase {
-
+    private static final String TAG = "DownloadManagerBaseTest";
     protected DownloadManager mDownloadManager = null;
     protected MockWebServer mServer = null;
     protected String mFileType = "text/plain";
@@ -616,19 +616,22 @@
         int nextChunkSize = CHUNK_SIZE;
         byte[] randomData = null;
         Random rng = new LoggingRng();
+        byte[] chunkSizeData = generateData(nextChunkSize, type, rng);
 
         try {
             while (remaining > 0) {
                 if (remaining < CHUNK_SIZE) {
                     nextChunkSize = (int)remaining;
                     remaining = 0;
+                    randomData = generateData(nextChunkSize, type, rng);
                 }
                 else {
                     remaining -= CHUNK_SIZE;
+                    randomData = chunkSizeData;
                 }
-
-                randomData = generateData(nextChunkSize, type, rng);
                 output.write(randomData);
+                Log.i(TAG, "while creating " + fileSize + " file, " +
+                        "remaining bytes to be written: " + remaining);
             }
         } catch (IOException e) {
             Log.e(LOG_TAG, "Error writing to file " + file.getAbsolutePath());
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index 06f3ba4..afe7f55 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -20,20 +20,14 @@
 
 import android.app.DownloadManager.Query;
 import android.app.DownloadManager.Request;
-import android.app.DownloadManagerBaseTest.DataType;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.os.StatFs;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.util.Iterator;
-import java.util.Random;
 import java.util.Set;
 
 /**
@@ -152,55 +146,6 @@
     }
 
     /**
-     * Attempts to download several files simultaneously
-     */
-    @LargeTest
-    public void testMultipleDownloads() throws Exception {
-        // need to be sure all current downloads have stopped first
-        removeAllCurrentDownloads();
-        int NUM_FILES = 10;
-        int MAX_FILE_SIZE = 10 * 1024; // 10 kb
-
-        Random r = new LoggingRng();
-        for (int i=0; i<NUM_FILES; ++i) {
-            int size = r.nextInt(MAX_FILE_SIZE);
-            byte[] blobData = generateData(size, DataType.TEXT);
-
-            Uri uri = getServerUri(DEFAULT_FILENAME + i);
-            Request request = new Request(uri);
-            request.setTitle(String.format("%s--%d", DEFAULT_FILENAME + i, i));
-
-            // Prepare the mock server with a standard response
-            enqueueResponse(HTTP_OK, blobData);
-
-            long requestID = mDownloadManager.enqueue(request);
-        }
-
-        waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
-        Cursor cursor = mDownloadManager.query(new Query());
-        try {
-            assertEquals(NUM_FILES, cursor.getCount());
-
-            if (cursor.moveToFirst()) {
-                do {
-                    int status = cursor.getInt(cursor.getColumnIndex(
-                            DownloadManager.COLUMN_STATUS));
-                    String filename = cursor.getString(cursor.getColumnIndex(
-                            DownloadManager.COLUMN_URI));
-                    String errorString = String.format(
-                            "File %s failed to download successfully. Status code: %d",
-                            filename, status);
-                    assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
-                } while (cursor.moveToNext());
-            }
-
-            assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted());
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
      * Tests trying to download to SD card when the file with same name already exists.
      */
     @LargeTest
@@ -478,103 +423,4 @@
         // Even tho the server drops the connection, we should still get a completed notification
         assertEquals(1, mReceiver.numDownloadsCompleted());
     }
-
-    /**
-     * Tests downloading a file to system cache when there isn't enough space in the system cache 
-     * to hold the entire file. DownloadManager deletes enough files to make space for the
-     * new download.
-     */
-    @LargeTest
-    public void testDownloadToCacheWithAlmostFullCache() throws Exception {
-        int DOWNLOAD_FILE_SIZE = 1024 * 1024; // 1MB
-
-        StatFs fs = new StatFs(CACHE_DIR);
-        int blockSize = fs.getBlockSize();
-        int availableBlocks = fs.getAvailableBlocks();
-        int availableBytes = blockSize * availableBlocks;
-        Log.i(TAG, "INITIAL stage, available space in /cache: " + availableBytes);
-        File outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR));
-        byte[] buffer = new byte[blockSize];
-
-        try {
-            // fill cache to ensure we don't have enough space - take half the size of the
-            // download size, and leave that much freespace left on the cache partition
-            if (DOWNLOAD_FILE_SIZE <= availableBytes) {
-                int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2);
-
-                int writeSizeBlocks = writeSizeBytes / blockSize;
-                int remainderSizeBlocks = availableBlocks - writeSizeBlocks;
-
-                FileOutputStream fo = null;
-                try {
-                    fo = new FileOutputStream(outFile);
-                    while (fs.getAvailableBlocks() >= remainderSizeBlocks) {
-                        fo.write(buffer);
-                        fs.restat(CACHE_DIR);
-                    }
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, "error filling file: ", e);
-                    throw e;
-                } finally {
-                    if (fo != null) {
-                        fo.close();
-                    }
-                }
-            }
-
-            // /cache should now be almost full. 
-            long spaceAvailable = fs.getAvailableBlocks() * blockSize;
-            Log.i(TAG, "BEFORE download, available space in /cache: " + spaceAvailable);
-            assertTrue(DOWNLOAD_FILE_SIZE > spaceAvailable);
-
-            // try to download 1MB file into /cache - and it should succeed
-            byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
-            long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
-            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
-        } finally {
-            if (outFile != null) {
-                outFile.delete();
-            }
-        }
-    }
-
-    /**
-     * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've
-     * run out of space.
-     */
-    @LargeTest
-    public void testDownloadToCacheNonPurgeableWithFullCache() throws Exception {
-        int fileSize = 1024 * 1024; // 1MB
-        byte[] blobData = generateData(fileSize, DataType.BINARY);
-        long dlRequest = -1;
-
-        // Fill up the cache partition with DOWNLOAD_CACHE_NON_PURGEABLE downloads
-        // until 500KB is left.
-        boolean spaceAvailable = true;
-        while (spaceAvailable) {
-            // since this tests package has android.permission.DOWNLOAD_CACHE_NON_PURGEABLE
-            // permission, downloads are automatically set to be DOWNLOAD_CACHE_NON_PURGEABLE
-            dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
-            waitForDownloadOrTimeout(dlRequest);
-
-            // Check if we've filled up the cache yet
-            StatFs fs = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
-            int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks();
-            Log.i(TAG, "available space in /cache: " + availableBytes);
-            spaceAvailable = (availableBytes > fileSize) ? true : false;
-        }
-
-        // Now add one more 1MB download (should not fit in the space left over)
-        dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
-        waitForDownloadOrTimeout(dlRequest);
-
-        // For the last download we should have failed b/c there is not enough space left in cache
-        Cursor cursor = getCursor(dlRequest);
-        try {
-            verifyInt(cursor, DownloadManager.COLUMN_REASON,
-                    DownloadManager.ERROR_INSUFFICIENT_SPACE);
-        } finally {
-            cursor.close();
-        }
-    }
 }
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 18b279f..bdeb554 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -16,21 +16,28 @@
 
 package android.app;
 
-
 import android.app.DownloadManager.Query;
 import android.app.DownloadManager.Request;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.StatFs;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.Random;
 
-
+/**
+ * Integration tests of the DownloadManager API.
+ */
 public class DownloadManagerStressTest extends DownloadManagerBaseTest {
+    private static final String TAG = "DownloadManagerStressTest";
+    private final static String CACHE_DIR =
+            Environment.getDownloadCacheDirectory().getAbsolutePath();
 
     /**
      * {@inheritDoc}
@@ -38,8 +45,8 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mServer.play(0);
         setWiFiStateOn(true);
+        mServer.play();
         removeAllCurrentDownloads();
     }
 
@@ -59,76 +66,62 @@
     }
 
     /**
-     * Attempts to downloading thousands of files simultaneously
-     * don't run this test - downloadmanager needs to allow only a few simultaneous downloads.
+     * Attempts to download several files simultaneously
      */
-    @Suppress
-    public void testDownloadThousands() throws Exception {
-        int NUM_FILES = 1500;
-        int MAX_FILE_SIZE = 3000;
-        long[] reqs = new long[NUM_FILES];
-
+    @LargeTest
+    public void testMultipleDownloads() throws Exception {
         // need to be sure all current downloads have stopped first
-        MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
-        Cursor cursor = null;
+        removeAllCurrentDownloads();
+        int NUM_FILES = 10;
+        int MAX_FILE_SIZE = 10 * 1024; // 10 kb
+
+        Random r = new LoggingRng();
+        for (int i=0; i<NUM_FILES; ++i) {
+            int size = r.nextInt(MAX_FILE_SIZE);
+            byte[] blobData = generateData(size, DataType.TEXT);
+
+            Uri uri = getServerUri(DEFAULT_FILENAME + i);
+            Request request = new Request(uri);
+            request.setTitle(String.format("%s--%d", DEFAULT_FILENAME + i, i));
+
+            // Prepare the mock server with a standard response
+            enqueueResponse(HTTP_OK, blobData);
+
+            long requestID = mDownloadManager.enqueue(request);
+        }
+
+        waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
+        Cursor cursor = mDownloadManager.query(new Query());
         try {
-            Random r = new LoggingRng();
-            for (int i = 0; i < NUM_FILES; ++i) {
-                int size = r.nextInt(MAX_FILE_SIZE);
-                byte[] blobData = generateData(size, DataType.TEXT);
-
-                Uri uri = getServerUri(DEFAULT_FILENAME);
-                Request request = new Request(uri);
-                request.setTitle(String.format("%s--%d", DEFAULT_FILENAME, i));
-
-                // Prepare the mock server with a standard response
-                enqueueResponse(HTTP_OK, blobData);
-
-                Log.i(LOG_TAG, "issuing request: " + i);
-                long reqId = mDownloadManager.enqueue(request);
-                reqs[i] = reqId;
-            }
-
-            // wait for the download to complete or timeout
-            waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME,
-                    MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME);
-            cursor = mDownloadManager.query(new Query());
             assertEquals(NUM_FILES, cursor.getCount());
-            Log.i(LOG_TAG, "Verified number of downloads in download manager is what we expect.");
-            while (cursor.moveToNext()) {
-                int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
-                String filename = cursor.getString(cursor.getColumnIndex(
-                        DownloadManager.COLUMN_URI));
-                String errorString = String.format("File %s failed to download successfully. " +
-                        "Status code: %d", filename, status);
-                assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
-            }
-            Log.i(LOG_TAG, "Verified each download was successful.");
-            assertEquals(NUM_FILES, receiver.numDownloadsCompleted());
-            Log.i(LOG_TAG, "Verified number of completed downloads in our receiver.");
 
-            // Verify that for each request, we can open the downloaded file
-            for (int i = 0; i < NUM_FILES; ++i) {
-                ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(reqs[i]);
-                pfd.close();
+            if (cursor.moveToFirst()) {
+                do {
+                    int status = cursor.getInt(cursor.getColumnIndex(
+                            DownloadManager.COLUMN_STATUS));
+                    String filename = cursor.getString(cursor.getColumnIndex(
+                            DownloadManager.COLUMN_URI));
+                    String errorString = String.format(
+                            "File %s failed to download successfully. Status code: %d",
+                            filename, status);
+                    assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
+                } while (cursor.moveToNext());
             }
-            Log.i(LOG_TAG, "Verified we can open each file.");
+
+            assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted());
         } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-            mContext.unregisterReceiver(receiver);
-            removeAllCurrentDownloads();
+            cursor.close();
         }
     }
-
     /**
      * Tests trying to download a large file (50M bytes).
      */
     @LargeTest
     public void testDownloadLargeFile() throws Exception {
         long fileSize = 50000000L;  // note: kept relatively small to not exceed /cache dir size
+        Log.i(TAG, "creating a file of size: " + fileSize);
         File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null);
+        Log.i(TAG, "DONE creating a file of size: " + fileSize);
         MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
 
         try {
@@ -149,4 +142,64 @@
             largeFile.delete();
         }
     }
+
+
+    /**
+     * Tests downloading a file to system cache when there isn't enough space in the system cache 
+     * to hold the entire file. DownloadManager deletes enough files to make space for the
+     * new download.
+     */
+    @LargeTest
+    public void testDownloadToCacheWithAlmostFullCache() throws Exception {
+        int DOWNLOAD_FILE_SIZE = 1024 * 1024; // 1MB
+
+        StatFs fs = new StatFs(CACHE_DIR);
+        int blockSize = fs.getBlockSize();
+        int availableBlocks = fs.getAvailableBlocks();
+        int availableBytes = blockSize * availableBlocks;
+        Log.i(TAG, "INITIAL stage, available space in /cache: " + availableBytes);
+        File outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR));
+        byte[] buffer = new byte[blockSize];
+
+        try {
+            // fill cache to ensure we don't have enough space - take half the size of the
+            // download size, and leave that much freespace left on the cache partition
+            if (DOWNLOAD_FILE_SIZE <= availableBytes) {
+                int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2);
+
+                int writeSizeBlocks = writeSizeBytes / blockSize;
+                int remainderSizeBlocks = availableBlocks - writeSizeBlocks;
+
+                FileOutputStream fo = null;
+                try {
+                    fo = new FileOutputStream(outFile);
+                    while (fs.getAvailableBlocks() >= remainderSizeBlocks) {
+                        fo.write(buffer);
+                        fs.restat(CACHE_DIR);
+                    }
+                } catch (IOException e) {
+                    Log.e(LOG_TAG, "error filling file: ", e);
+                    throw e;
+                } finally {
+                    if (fo != null) {
+                        fo.close();
+                    }
+                }
+            }
+
+            // /cache should now be almost full. 
+            long spaceAvailable = fs.getAvailableBlocks() * blockSize;
+            Log.i(TAG, "BEFORE download, available space in /cache: " + spaceAvailable);
+            assertTrue(DOWNLOAD_FILE_SIZE > spaceAvailable);
+
+            // try to download 1MB file into /cache - and it should succeed
+            byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
+            long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+        } finally {
+            if (outFile != null) {
+                outFile.delete();
+            }
+        }
+    }
 }
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 7acce02..386cc5d 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -895,7 +895,7 @@
     dp->refs--;
     dp->numTotalConfigs = 0;
     delete [] dp->configs;
-    clearTLS();
+
     return res;
 }
 
@@ -1231,6 +1231,27 @@
     return result;
 }
 
+static void loseCurrent(egl_context_t * cur_c)
+{
+    if (cur_c) {
+        egl_surface_t * cur_r = get_surface(cur_c->read);
+        egl_surface_t * cur_d = get_surface(cur_c->draw);
+
+        // by construction, these are either 0 or valid (possibly terminated)
+        // it should be impossible for these to be invalid
+        ContextRef _cur_c(cur_c);
+        SurfaceRef _cur_r(cur_r);
+        SurfaceRef _cur_d(cur_d);
+
+        cur_c->read = NULL;
+        cur_c->draw = NULL;
+
+        _cur_c.release();
+        _cur_r.release();
+        _cur_d.release();
+    }
+}
+
 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                             EGLSurface read, EGLContext ctx)
 {
@@ -1259,13 +1280,9 @@
 
     // these are the current objects structs
     egl_context_t * cur_c = get_context(getContext());
-    egl_surface_t * cur_r = NULL;
-    egl_surface_t * cur_d = NULL;
     
     if (ctx != EGL_NO_CONTEXT) {
         c = get_context(ctx);
-        cur_r = get_surface(c->read);
-        cur_d = get_surface(c->draw);
         impl_ctx = c->context;
     } else {
         // no context given, use the implementation of the current context
@@ -1311,30 +1328,21 @@
     }
 
     if (result == EGL_TRUE) {
-        // by construction, these are either 0 or valid (possibly terminated)
-        // it should be impossible for these to be invalid
-        ContextRef _cur_c(cur_c);
-        SurfaceRef _cur_r(cur_r);
-        SurfaceRef _cur_d(cur_d);
 
-        // cur_c has to be valid here (but could be terminated)
+        loseCurrent(cur_c);
+
         if (ctx != EGL_NO_CONTEXT) {
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             setContext(ctx);
             _c.acquire();
+            _r.acquire();
+            _d.acquire();
+            c->read = read;
+            c->draw = draw;
         } else {
             setGLHooksThreadSpecific(&gHooksNoContext);
             setContext(EGL_NO_CONTEXT);
         }
-        _cur_c.release();
-
-        _r.acquire();
-        _cur_r.release();
-        if (c) c->read = read;
-
-        _d.acquire();
-        _cur_d.release();
-        if (c) c->draw = draw;
     }
     return result;
 }
@@ -1721,6 +1729,9 @@
 
 EGLBoolean eglReleaseThread(void)
 {
+    // If there is context bound to the thread, release it
+    loseCurrent(get_context(getContext()));
+
     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index e7e4302..feb7b63 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1574,11 +1574,18 @@
         }
     }
 
-    private void writePidDns(Collection <InetAddress> dnses, int pid) {
+    // return true if results in a change
+    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
         int j = 1;
+        boolean changed = false;
         for (InetAddress dns : dnses) {
-            SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
+            String dnsString = dns.getHostAddress();
+            if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
+                changed = true;
+                SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
+            }
         }
+        return changed;
     }
 
     private void bumpDns() {
@@ -1609,26 +1616,40 @@
             LinkProperties p = nt.getLinkProperties();
             if (p == null) return;
             Collection<InetAddress> dnses = p.getDnses();
+            boolean changed = false;
             if (mNetAttributes[netType].isDefault()) {
                 int j = 1;
                 if (dnses.size() == 0 && mDefaultDns != null) {
-                    if (DBG) {
-                        log("no dns provided - using " + mDefaultDns.getHostAddress());
+                    String dnsString = mDefaultDns.getHostAddress();
+                    if (!dnsString.equals(SystemProperties.get("net.dns1"))) {
+                        if (DBG) {
+                            log("no dns provided - using " + dnsString);
+                        }
+                        changed = true;
+                        SystemProperties.set("net.dns1", dnsString);
                     }
-                    SystemProperties.set("net.dns1", mDefaultDns.getHostAddress());
                     j++;
                 } else {
                     for (InetAddress dns : dnses) {
+                        String dnsString = dns.getHostAddress();
+                        if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) {
+                            j++;
+                            continue;
+                        }
                         if (DBG) {
                             log("adding dns " + dns + " for " +
                                     nt.getNetworkInfo().getTypeName());
                         }
-                        SystemProperties.set("net.dns" + j++, dns.getHostAddress());
+                        changed = true;
+                        SystemProperties.set("net.dns" + j++, dnsString);
                     }
                 }
                 for (int k=j ; k<mNumDnsEntries; k++) {
-                    if (DBG) log("erasing net.dns" + k);
-                    SystemProperties.set("net.dns" + k, "");
+                    if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) {
+                        if (DBG) log("erasing net.dns" + k);
+                        changed = true;
+                        SystemProperties.set("net.dns" + k, "");
+                    }
                 }
                 mNumDnsEntries = j;
             } else {
@@ -1636,10 +1657,10 @@
                 List pids = mNetRequestersPids[netType];
                 for (int y=0; y< pids.size(); y++) {
                     Integer pid = (Integer)pids.get(y);
-                    writePidDns(dnses, pid.intValue());
+                    changed = writePidDns(dnses, pid.intValue());
                 }
             }
-            bumpDns();
+            if (changed) bumpDns();
         }
     }
 
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index a93d596..a562e1f 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -68,7 +68,7 @@
 
     private Context mContext;
     private final static String TAG = "Tethering";
-    private final static boolean DEBUG = false;
+    private final static boolean DEBUG = true;
 
     private boolean mBooted = false;
     //used to remember if we got connected before boot finished
@@ -942,7 +942,12 @@
                         String newUpstreamIfaceName = (String)(message.obj);
                         b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
                         service = INetworkManagementService.Stub.asInterface(b);
-
+                        if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
+                                (mMyUpstreamIfaceName != null &&
+                                mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
+                            if (DEBUG) Log.d(TAG, "Connection changed noop - dropping");
+                            break;
+                        }
                         if (mMyUpstreamIfaceName != null) {
                             try {
                                 service.disableNat(mIfaceName, mMyUpstreamIfaceName);
@@ -1085,7 +1090,8 @@
 
         private ArrayList mNotifyList;
 
-        private boolean mConnectionRequested = false;
+        private int mCurrentConnectionSequence;
+        private boolean mMobileReserved = false;
 
         private String mUpstreamIfaceName = null;
 
@@ -1124,32 +1130,36 @@
             public boolean processMessage(Message m) {
                 return false;
             }
-            protected int turnOnMobileConnection() {
+            protected boolean turnOnMobileConnection() {
+                boolean retValue = true;
+                if (mMobileReserved) return retValue;
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
-                int retValue = Phone.APN_REQUEST_FAILED;
+                int result = Phone.APN_REQUEST_FAILED;
                 try {
-                    retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+                    result = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                             (mDunRequired ? Phone.FEATURE_ENABLE_DUN : Phone.FEATURE_ENABLE_HIPRI),
                             new Binder());
                 } catch (Exception e) {
                 }
-                switch (retValue) {
+                switch (result) {
                 case Phone.APN_ALREADY_ACTIVE:
                 case Phone.APN_REQUEST_STARTED:
-                    sendMessageDelayed(CMD_CELL_CONNECTION_RENEW, CELL_CONNECTION_RENEW_MS);
-                    mConnectionRequested = true;
+                    mMobileReserved = true;
+                    Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
+                    m.arg1 = ++mCurrentConnectionSequence;
+                    sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
                     break;
                 case Phone.APN_REQUEST_FAILED:
                 default:
-                    mConnectionRequested = false;
+                    retValue = false;
                     break;
                 }
 
                 return retValue;
             }
             protected boolean turnOffMobileConnection() {
-                if (mConnectionRequested) {
+                if (mMobileReserved) {
                     IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                     IConnectivityManager service =
                             IConnectivityManager.Stub.asInterface(b);
@@ -1160,7 +1170,7 @@
                     } catch (Exception e) {
                         return false;
                     }
-                    mConnectionRequested = false;
+                    mMobileReserved = false;
                 }
                 return true;
             }
@@ -1240,13 +1250,14 @@
                 }
                 return null;
             }
+
             protected void chooseUpstreamType(boolean tryCell) {
                 // decide if the current upstream is good or not and if not
                 // do something about it (start up DUN if required or HiPri if not)
                 String iface = findActiveUpstreamIface();
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-                mConnectionRequested = false;
+                mMobileReserved = false;
                 if (DEBUG) {
                     Log.d(TAG, "chooseUpstreamType(" + tryCell + "),  dunRequired ="
                             + mDunRequired + ", iface=" + iface);
@@ -1287,11 +1298,14 @@
                 }
                 // may have been set to null in the if above
                 if (iface == null ) {
+                    boolean success = false;
                     if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
-                        turnOnMobileConnection();
+                        success = turnOnMobileConnection();
                     }
-                    // wait for things to settle and retry
-                    sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
+                    if (!success) {
+                        // wait for things to settle and retry
+                        sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
+                    }
                 }
                 notifyTetheredOfNewUpstreamIface(iface);
             }
@@ -1309,7 +1323,7 @@
         class InitialState extends TetherMasterUtilState {
             @Override
             public void enter() {
-                mConnectionRequested = false;
+                mMobileReserved = false;
             }
             @Override
             public boolean processMessage(Message message) {
@@ -1382,11 +1396,12 @@
                     case CMD_CELL_CONNECTION_RENEW:
                         // make sure we're still using a requested connection - may have found
                         // wifi or something since then.
-                        if (mConnectionRequested) {
+                        if (mCurrentConnectionSequence == message.arg1) {
                             if (DEBUG) {
                                 Log.d(TAG, "renewing mobile connection - requeuing for another " +
                                         CELL_CONNECTION_RENEW_MS + "ms");
                             }
+                            mMobileReserved = false; // need to renew it
                             turnOnMobileConnection();
                         }
                         break;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index d9b67ea..9ccb3ee 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -86,6 +86,7 @@
                 }
                 return;
             } else if (msg.what == MSG_WEBKIT_DATA) {
+                mHandler.removeMessages(MSG_DUMP_TIMEOUT);
                 TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
                 return;
             } else if (msg.what == MSG_DUMP_TIMEOUT) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index b660ae6..75b8f99 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -65,7 +65,6 @@
     /*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
             int shaderTileModeY) {
         Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
-        assert bitmap != null;
         if (bitmap == null) {
             return 0;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 2ce6a36..dd57bd1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -139,7 +139,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
         if (delegate == null) {
-            assert false;
             return null;
         }
 
@@ -215,7 +214,6 @@
     /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
         Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
         if (srcBmpDelegate == null) {
-            assert false;
             return null;
         }
 
@@ -258,7 +256,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -278,7 +275,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -289,7 +285,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -300,7 +295,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -311,7 +305,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -322,7 +315,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return true;
         }
 
@@ -333,7 +325,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -344,7 +335,6 @@
             int stride, int x, int y, int width, int height) {
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -355,7 +345,6 @@
     /*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -366,7 +355,6 @@
             int stride, int x, int y, int width, int height) {
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -386,7 +374,6 @@
     /*package*/ static int nativeGenerationId(int nativeBitmap) {
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -397,7 +384,7 @@
         // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
         // used during aidl call so really this should not be called.
         Bridge.getLog().error(null,
-                "AIDL is not suppored, and therefore bitmap cannot be created from parcels");
+                "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.");
         return null;
     }
 
@@ -406,7 +393,7 @@
         // This is only called when sending a bitmap through aidl, so really this should not
         // be called.
         Bridge.getLog().error(null,
-                "AIDL is not suppored, and therefore bitmap cannot be written to parcels");
+                "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.");
         return false;
     }
 
@@ -414,20 +401,13 @@
             int[] offsetXY) {
         Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
         if (bitmap == null) {
-            assert false;
             return null;
         }
 
-        Paint_Delegate paint = null;
-        if (nativePaint > 0) {
-            paint = Paint_Delegate.getDelegate(nativePaint);
-            if (paint == null) {
-                assert false;
-                return null;
-            }
-        }
+        // get the paint which can be null if nativePaint is 0.
+        Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
 
-        if (paint != null && paint.getMaskFilter() != 0) {
+        if (paint != null && paint.getMaskFilter() != null) {
             Bridge.getLog().fidelityWarning(null,
                     "MaskFilter not supported in Bitmap.extractAlpha",
                     null);
@@ -452,7 +432,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -462,13 +441,11 @@
     /*package*/ static boolean nativeSameAs(int nb0, int nb1) {
         Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
         if (delegate1 == null) {
-            assert false;
             return false;
         }
 
         Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
         if (delegate2 == null) {
-            assert false;
             return false;
         }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
new file mode 100644
index 0000000..34824b4
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BlurMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of BlurMaskFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original BlurMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class BlurMaskFilter_Delegate extends MaskFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "Blur Mask Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeConstructor(float radius, int style) {
+        BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 88ec88eb..def0f02 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -61,6 +61,8 @@
     private Bitmap_Delegate mBitmap;
     private GcSnapshot mSnapshot;
 
+    private int mDrawFilter = 0;
+
     // ---- Public Helper methods ----
 
     /**
@@ -84,6 +86,15 @@
         return mSnapshot;
     }
 
+    /**
+     * Returns the {@link DrawFilter} delegate or null if none have been set.
+     *
+     * @return the delegate or null.
+     */
+    public DrawFilter_Delegate getDrawFilter() {
+        return DrawFilter_Delegate.getDelegate(mDrawFilter);
+    }
+
     // ---- native methods ----
 
     /*package*/ static boolean isOpaque(Canvas thisCanvas) {
@@ -95,7 +106,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -106,7 +116,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -117,7 +126,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -128,7 +136,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -139,7 +146,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -150,7 +156,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -184,7 +189,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return false;
         }
 
@@ -205,7 +209,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -216,7 +219,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -227,7 +229,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -238,7 +239,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -271,8 +271,7 @@
     }
 
     /*package*/ static void freeCaches() {
-        // FIXME
-        throw new UnsupportedOperationException();
+        // nothing to be done here.
     }
 
     /*package*/ static int initRaster(int nativeBitmapOrZero) {
@@ -296,14 +295,12 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
         // get the delegate from the native int.
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (bitmapDelegate == null) {
-            assert false;
             return;
         }
 
@@ -315,13 +312,11 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
         Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
         if (paintDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -334,13 +329,11 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
         Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
         if (paintDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -354,7 +347,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -367,7 +359,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -379,13 +370,11 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
         if (matrixDelegate == null) {
-            assert false;
             return;
         }
 
@@ -408,12 +397,12 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
+            return;
         }
 
         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
         if (matrixDelegate == null) {
-            assert false;
+            return;
         }
 
         // get the current top graphics2D object.
@@ -441,7 +430,7 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
+            return false;
         }
 
         return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
@@ -450,21 +439,55 @@
     /*package*/ static boolean native_clipPath(int nativeCanvas,
                                                   int nativePath,
                                                   int regionOp) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return true;
+        }
+
+        Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
+        if (pathDelegate == null) {
+            return true;
+        }
+
+        return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
     }
 
     /*package*/ static boolean native_clipRegion(int nativeCanvas,
                                                     int nativeRegion,
                                                     int regionOp) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return true;
+        }
+
+        Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
+        if (region == null) {
+            return true;
+        }
+
+        return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
     }
 
     /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
                                                    int nativeFilter) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        canvasDelegate.mDrawFilter = nativeFilter;
+
+        // get the delegate only because we don't support them at all for the moment, so
+        // we can display the message now.
+
+        DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        if (filterDelegate.isSupported() == false) {
+            Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
+        }
     }
 
     /*package*/ static boolean native_getClipBounds(int nativeCanvas,
@@ -472,7 +495,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return false;
         }
 
@@ -533,7 +555,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -676,7 +697,6 @@
                                                int paint) {
         final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -708,7 +728,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (bitmapDelegate == null) {
-            assert false;
             return;
         }
 
@@ -729,7 +748,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (bitmapDelegate == null) {
-            assert false;
             return;
         }
 
@@ -754,7 +772,6 @@
         // get the delegate from the native int.
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (bitmapDelegate == null) {
-            assert false;
             return;
         }
 
@@ -800,24 +817,15 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
-        // get the delegate from the native int.
-        Paint_Delegate paintDelegate = null;
-        if (nPaint > 0) {
-            paintDelegate = Paint_Delegate.getDelegate(nPaint);
-            if (paintDelegate == null) {
-                assert false;
-                return;
-            }
-        }
+        // get the delegate from the native int, which can be null
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
 
         // get the delegate from the native int.
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
         if (bitmapDelegate == null) {
-            assert false;
             return;
         }
 
@@ -825,7 +833,6 @@
 
         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
         if (matrixDelegate == null) {
-            assert false;
             return;
         }
 
@@ -1029,7 +1036,6 @@
         // get the delegate from the native int so that it can be disposed.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -1051,19 +1057,11 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
-        // paint could be 0 meaning no paint
-        Paint_Delegate paintDelegate = null;
-        if (nPaint > 0) {
-            paintDelegate = Paint_Delegate.getDelegate(nPaint);
-            if (paintDelegate == null) {
-                assert false;
-                return;
-            }
-        }
+        // get the paint which can be null if nPaint is 0;
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
 
         canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
     }
@@ -1078,7 +1076,6 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
@@ -1161,19 +1158,11 @@
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
-            assert false;
             return;
         }
 
-        // get the delegate from the native int.
-        Paint_Delegate paintDelegate = null;
-        if (nativePaintOrZero > 0) {
-            paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
-            if (paintDelegate == null) {
-                assert false;
-                return;
-            }
-        }
+        // get the paint, which could be null if the int is 0
+        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
 
         final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
 
@@ -1221,16 +1210,13 @@
             // - Create a different bitmap to draw in which all the alpha channel values is set
             //   to 0xFF.
             if (paint != null) {
-                int xfermode = paint.getXfermode();
-                if (xfermode > 0) {
-                    Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(xfermode);
-                    if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
-                        PorterDuff.Mode mode =
-                            ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
+                Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
+                if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
+                    PorterDuff.Mode mode =
+                        ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
 
-                        forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
-                                mode == PorterDuff.Mode.SRC;
-                    }
+                    forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
+                            mode == PorterDuff.Mode.SRC;
                 }
             }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
new file mode 100644
index 0000000..3df170f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ColorFilter class.
+ *
+ * This also serve as a base class for all ColorFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class ColorFilter_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<ColorFilter_Delegate> sManager =
+            new DelegateManager<ColorFilter_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    public static ColorFilter_Delegate getDelegate(int nativeShader) {
+        return sManager.getDelegate(nativeShader);
+    }
+
+    public abstract boolean isSupported();
+    public abstract String getSupportMessage();
+
+    // ---- native methods ----
+
+    /*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
+        sManager.removeDelegate(native_instance);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
new file mode 100644
index 0000000..42843279
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorMatrixColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ColorMatrixColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "ColorMatrix Color Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeColorMatrixFilter(float[] array) {
+        ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int nColorMatrixFilter(int nativeFilter, float[] array) {
+        // pass
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
new file mode 100644
index 0000000..ddf20b6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of DrawFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original DrawFilter class.
+ *
+ * This also serve as a base class for all DrawFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class DrawFilter_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<DrawFilter_Delegate> sManager =
+            new DelegateManager<DrawFilter_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    public static DrawFilter_Delegate getDelegate(int nativeDrawFilter) {
+        return sManager.getDelegate(nativeDrawFilter);
+    }
+
+    public abstract boolean isSupported();
+    public abstract String getSupportMessage();
+
+    // ---- native methods ----
+
+    /*package*/ static void nativeDestructor(int nativeDrawFilter) {
+        sManager.removeDelegate(nativeDrawFilter);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
new file mode 100644
index 0000000..82f1da3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.EmbossMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of EmbossMaskFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original EmbossMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "Emboss Mask Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeConstructor(float[] direction, float ambient,
+            float specular, float blurRadius) {
+        EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
new file mode 100644
index 0000000..132004f9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LayerRasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of LayerRasterizer have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original LayerRasterizer class.
+ *
+ * Because this extends {@link Rasterizer_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link Rasterizer_Delegate}.
+ *
+ * @see Rasterizer_Delegate
+ *
+ */
+public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "Layer Rasterizers are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeConstructor() {
+        LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static void nativeAddLayer(int native_layer, int native_paint, float dx, float dy) {
+
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
new file mode 100644
index 0000000..ba2cfad
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LightingColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of LightingColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original LightingColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "Lighting Color Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int native_CreateLightingFilter(int mul, int add) {
+        LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int nCreateLightingFilter(int nativeFilter, int mul, int add) {
+        // pass
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
new file mode 100644
index 0000000..c582a91
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.MaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of MaskFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original MaskFilter class.
+ *
+ * This also serve as a base class for all MaskFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class MaskFilter_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<MaskFilter_Delegate> sManager =
+            new DelegateManager<MaskFilter_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    public static MaskFilter_Delegate getDelegate(int nativeShader) {
+        return sManager.getDelegate(nativeShader);
+    }
+
+    public abstract boolean isSupported();
+    public abstract String getSupportMessage();
+
+    // ---- native methods ----
+
+    /*package*/ static void nativeDestructor(int native_filter) {
+        sManager.removeDelegate(native_filter);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 463f4e9..94beef3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -60,7 +60,6 @@
     public static AffineTransform getAffineTransform(Matrix m) {
         Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
         if (delegate == null) {
-            assert false;
             return null;
         }
 
@@ -70,7 +69,6 @@
     public static boolean hasPerspective(Matrix m) {
         Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
         if (delegate == null) {
-            assert false;
             return false;
         }
 
@@ -181,7 +179,6 @@
     /*package*/ static boolean native_isIdentity(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -191,7 +188,6 @@
     /*package*/ static boolean native_rectStaysRect(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return true;
         }
 
@@ -201,7 +197,6 @@
     /*package*/ static void native_reset(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -211,13 +206,11 @@
     /*package*/ static void native_set(int native_object, int other) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
         Matrix_Delegate src = sManager.getDelegate(other);
         if (src == null) {
-            assert false;
             return;
         }
 
@@ -227,7 +220,6 @@
     /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -238,7 +230,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -248,7 +239,6 @@
     /*package*/ static void native_setScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -266,7 +256,6 @@
     /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -276,7 +265,6 @@
     /*package*/ static void native_setRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -287,7 +275,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -305,7 +292,6 @@
     /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -316,7 +302,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -326,7 +311,6 @@
     /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -350,19 +334,16 @@
 
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate a_mtx = sManager.getDelegate(a);
         if (a_mtx == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate b_mtx = sManager.getDelegate(b);
         if (b_mtx == null) {
-            assert false;
             return false;
         }
 
@@ -374,7 +355,6 @@
     /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -386,7 +366,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -397,7 +376,6 @@
     /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -409,7 +387,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -420,7 +397,6 @@
     /*package*/ static boolean native_preRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -436,7 +412,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -447,7 +422,6 @@
     /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -458,13 +432,11 @@
     /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -475,7 +447,6 @@
     /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -487,7 +458,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -498,7 +468,6 @@
     /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -510,7 +479,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -521,7 +489,6 @@
     /*package*/ static boolean native_postRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -533,7 +500,6 @@
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -544,7 +510,6 @@
     /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -555,13 +520,11 @@
     /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -573,7 +536,6 @@
             RectF dst, int stf) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -643,17 +605,14 @@
     /*package*/ static boolean native_invert(int native_object, int inverse) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
         if (inv_mtx == null) {
-            assert false;
             return false;
         }
 
-
         try {
             AffineTransform affineTransform = d.getAffineTransform();
             AffineTransform inverseTransform = affineTransform.createInverse();
@@ -674,7 +633,6 @@
             float[] src, int srcIndex, int ptCount, boolean isPts) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -690,7 +648,6 @@
     /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return false;
         }
 
@@ -705,7 +662,6 @@
     /*package*/ static void native_getValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -715,7 +671,6 @@
     /*package*/ static void native_setValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
-            assert false;
             return;
         }
 
@@ -725,13 +680,11 @@
     /*package*/ static boolean native_equals(int native_a, int native_b) {
         Matrix_Delegate a = sManager.getDelegate(native_a);
         if (a == null) {
-            assert false;
             return false;
         }
 
         Matrix_Delegate b = sManager.getDelegate(native_b);
         if (b == null) {
-            assert false;
             return false;
         }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 25e0795..e9fb30a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -130,7 +130,6 @@
        // get the delegate from the native int.
        final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
        if (bitmap_delegate == null) {
-           assert false;
            return;
        }
 
@@ -152,7 +151,6 @@
 
        Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
        if (canvas_delegate == null) {
-           assert false;
            return;
        }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
new file mode 100644
index 0000000..ec92507
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PaintFlagsDrawFilter have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PaintFlagsDrawFilter class.
+ *
+ * Because this extends {@link DrawFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the DrawFilter classes will be added to the manager owned by
+ * {@link DrawFilter_Delegate}.
+ *
+ * @see DrawFilter_Delegate
+ *
+ */
+public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "Paint Flags Draw Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeConstructor(int clearBits, int setBits) {
+        PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7cb30dd..9d4970f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 
 import android.graphics.Paint.FontMetrics;
@@ -24,6 +25,8 @@
 
 import java.awt.BasicStroke;
 import java.awt.Font;
+import java.awt.Shape;
+import java.awt.Stroke;
 import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
@@ -82,6 +85,7 @@
     private int mShader;
     private int mPathEffect;
     private int mMaskFilter;
+    private int mRasterizer;
 
 
     // ---- Public Helper methods ----
@@ -165,24 +169,73 @@
         }
     }
 
-    public int getXfermode() {
-        return mXfermode;
+    public Stroke getJavaStroke() {
+        PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
+        if (effectDelegate != null) {
+            if (effectDelegate.isSupported()) {
+                Stroke stroke = effectDelegate.getStroke(this);
+                assert stroke != null;
+                if (stroke != null) {
+                    return stroke;
+                }
+            } else {
+                Bridge.getLog().fidelityWarning(null,
+                        effectDelegate.getSupportMessage(),
+                        null);
+            }
+        }
+
+        // if no custom stroke as been set, set the default one.
+        return new BasicStroke(
+                    getStrokeWidth(),
+                    getJavaCap(),
+                    getJavaJoin(),
+                    getJavaStrokeMiter());
     }
 
-    public int getColorFilter() {
-        return mColorFilter;
+    /**
+     * Returns the {@link Xfermode} delegate or null if none have been set
+     *
+     * @return the delegate or null.
+     */
+    public Xfermode_Delegate getXfermode() {
+        return  Xfermode_Delegate.getDelegate(mXfermode);
     }
 
-    public int getShader() {
-        return mShader;
+    /**
+     * Returns the {@link ColorFilter} delegate or null if none have been set
+     *
+     * @return the delegate or null.
+     */
+    public ColorFilter_Delegate getColorFilter() {
+        return ColorFilter_Delegate.getDelegate(mColorFilter);
     }
 
-    public int getPathEffect() {
-        return mPathEffect;
+    /**
+     * Returns the {@link Shader} delegate or null if none have been set
+     *
+     * @return the delegate or null.
+     */
+    public Shader_Delegate getShader() {
+        return Shader_Delegate.getDelegate(mShader);
     }
 
-    public int getMaskFilter() {
-        return mMaskFilter;
+    /**
+     * Returns the {@link MaskFilter} delegate or null if none have been set
+     *
+     * @return the delegate or null.
+     */
+    public MaskFilter_Delegate getMaskFilter() {
+        return MaskFilter_Delegate.getDelegate(mMaskFilter);
+    }
+
+    /**
+     * Returns the {@link Rasterizer} delegate or null if none have been set
+     *
+     * @return the delegate or null.
+     */
+    public Rasterizer_Delegate getRasterizer() {
+        return Rasterizer_Delegate.getDelegate(mRasterizer);
     }
 
     // ---- native methods ----
@@ -191,7 +244,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -202,7 +254,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -245,7 +296,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -256,7 +306,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -267,7 +316,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -278,7 +326,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -289,7 +336,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 1.f;
         }
 
@@ -300,7 +346,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -311,7 +356,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 1.f;
         }
 
@@ -322,7 +366,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -339,7 +382,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 1.f;
         }
 
@@ -350,7 +392,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -362,7 +403,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 1.f;
         }
 
@@ -373,7 +413,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -385,7 +424,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 1.f;
         }
 
@@ -396,7 +434,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -408,7 +445,6 @@
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -425,7 +461,6 @@
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -442,7 +477,6 @@
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -453,7 +487,6 @@
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -482,7 +515,6 @@
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -519,7 +551,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(paint);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -531,7 +562,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -542,14 +572,12 @@
         // get the delegate from the native int.
         Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
         if (delegate_dst == null) {
-            assert false;
             return;
         }
 
         // get the delegate from the native int.
         Paint_Delegate delegate_src = sManager.getDelegate(native_src);
         if (delegate_src == null) {
-            assert false;
             return;
         }
 
@@ -560,7 +588,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -571,7 +598,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -582,7 +608,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -593,7 +618,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -604,7 +628,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -615,7 +638,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -623,15 +645,34 @@
     }
 
     /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        Paint_Delegate paint = sManager.getDelegate(native_object);
+        if (paint == null) {
+            return false;
+        }
+
+        Path_Delegate srcPath = Path_Delegate.getDelegate(src);
+        if (srcPath == null) {
+            return true;
+        }
+
+        Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
+        if (dstPath == null) {
+            return true;
+        }
+
+        Stroke stroke = paint.getJavaStroke();
+        Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
+
+        dstPath.setJavaShape(strokeShape);
+
+        // FIXME figure out the return value?
+        return true;
     }
 
     /*package*/ static int native_setShader(int native_object, int shader) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return shader;
         }
 
@@ -642,18 +683,24 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return filter;
         }
 
-        return delegate.mColorFilter = filter;
+        delegate.mColorFilter = filter;
+
+        // since none of those are supported, display a fidelity warning right away
+        ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
+        if (filterDelegate != null && filterDelegate.isSupported() == false) {
+            Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
+        }
+
+        return filter;
     }
 
     /*package*/ static int native_setXfermode(int native_object, int xfermode) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return xfermode;
         }
 
@@ -664,7 +711,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return effect;
         }
 
@@ -675,18 +721,24 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return maskfilter;
         }
 
-        return delegate.mMaskFilter = maskfilter;
+        delegate.mMaskFilter = maskfilter;
+
+        // since none of those are supported, display a fidelity warning right away
+        MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
+        if (filterDelegate != null && filterDelegate.isSupported() == false) {
+            Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
+        }
+
+        return maskfilter;
     }
 
     /*package*/ static int native_setTypeface(int native_object, int typeface) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -696,15 +748,27 @@
     }
 
     /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
-        // FIXME
-        throw new UnsupportedOperationException();
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            return rasterizer;
+        }
+
+        delegate.mRasterizer = rasterizer;
+
+        // since none of those are supported, display a fidelity warning right away
+        Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
+        if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
+            Bridge.getLog().fidelityWarning(null, rasterizerDelegate.getSupportMessage(), null);
+        }
+
+        return rasterizer;
     }
 
     /*package*/ static int native_getTextAlign(int native_object) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -715,7 +779,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return;
         }
 
@@ -726,7 +789,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_paint);
         if (delegate == null) {
-            assert false;
             return 0.f;
         }
 
@@ -751,7 +813,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
-            assert false;
             return 0.f;
         }
 
@@ -869,6 +930,7 @@
         mShader = paint.mShader;
         mPathEffect = paint.mPathEffect;
         mMaskFilter = paint.mMaskFilter;
+        mRasterizer = paint.mRasterizer;
         updateFontObject();
     }
 
@@ -890,12 +952,14 @@
         mShader = 0;
         mPathEffect = 0;
         mMaskFilter = 0;
+        mRasterizer = 0;
         updateFontObject();
     }
 
     /**
      * Update the {@link Font} object from the typeface, text size and scaling
      */
+    @SuppressWarnings("deprecation")
     private void updateFontObject() {
         if (mTypeface != 0) {
             // Get the fonts from the TypeFace object.
@@ -998,7 +1062,6 @@
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
-            assert false;
             return;
         }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 811f0f6..66ab29c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -67,6 +67,20 @@
         return mPath;
     }
 
+    public void setJavaShape(Shape shape) {
+        mPath.reset();
+        mPath.append(shape, false /*connect*/);
+    }
+
+    public void reset() {
+        mPath.reset();
+    }
+
+    public void setPathIterator(PathIterator iterator) {
+        mPath.reset();
+        mPath.append(iterator, false /*connect*/);
+    }
+
     // ---- native methods ----
 
     /*package*/ static int init1() {
@@ -80,14 +94,9 @@
         // create the delegate
         Path_Delegate newDelegate = new Path_Delegate();
 
-        // get the delegate to copy
-        if (nPath > 0) {
-            Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-            if (pathDelegate == null) {
-                assert false;
-                return 0;
-            }
-
+        // get the delegate to copy, which could be null if nPath is 0
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate != null) {
             newDelegate.set(pathDelegate);
         }
 
@@ -97,7 +106,6 @@
     /*package*/ static void native_reset(int nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -113,13 +121,11 @@
     /*package*/ static void native_set(int native_dst, int native_src) {
         Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
         if (pathDstDelegate == null) {
-            assert false;
             return;
         }
 
         Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
         if (pathSrcDelegate == null) {
-            assert false;
             return;
         }
 
@@ -129,7 +135,6 @@
     /*package*/ static int native_getFillType(int nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return 0;
         }
 
@@ -139,7 +144,6 @@
     /*package*/ static void native_setFillType(int nPath, int ft) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -149,7 +153,6 @@
     /*package*/ static boolean native_isEmpty(int nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return true;
         }
 
@@ -159,7 +162,6 @@
     /*package*/ static boolean native_isRect(int nPath, RectF rect) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return false;
         }
 
@@ -179,7 +181,6 @@
     /*package*/ static void native_computeBounds(int nPath, RectF bounds) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -194,7 +195,6 @@
     /*package*/ static void native_moveTo(int nPath, float x, float y) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -204,7 +204,6 @@
     /*package*/ static void native_rMoveTo(int nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -214,7 +213,6 @@
     /*package*/ static void native_lineTo(int nPath, float x, float y) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -224,7 +222,6 @@
     /*package*/ static void native_rLineTo(int nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -234,7 +231,6 @@
     /*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -245,7 +241,6 @@
                                               float dx2, float dy2) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -256,7 +251,6 @@
                 float x2, float y2, float x3, float y3) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -267,7 +261,6 @@
                 float x2, float y2, float x3, float y3) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -278,7 +271,6 @@
                     float startAngle, float sweepAngle, boolean forceMoveTo) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -288,7 +280,6 @@
     /*package*/ static void native_close(int nPath) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -298,7 +289,6 @@
     /*package*/ static void native_addRect(int nPath, RectF rect, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -309,7 +299,6 @@
                                             float right, float bottom, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -365,18 +354,11 @@
                                              int dst_path) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
-        Path_Delegate dstDelegate = null;
-        if (dst_path > 0) {
-            dstDelegate = sManager.getDelegate(dst_path);
-            if (dstDelegate == null) {
-                assert false;
-                return;
-            }
-        }
+        // could be null if the int is 0;
+        Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
 
         pathDelegate.offset(dx, dy, dstDelegate);
     }
@@ -388,7 +370,6 @@
     /*package*/ static void native_setLastPoint(int nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
@@ -400,24 +381,16 @@
                                                 int dst_path) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
-            assert false;
             return;
         }
 
         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
         if (matrixDelegate == null) {
-            assert false;
             return;
         }
 
-        Path_Delegate dstDelegate = null;
-        if (dst_path > 0) {
-            dstDelegate = sManager.getDelegate(dst_path);
-            if (dstDelegate == null) {
-                assert false;
-                return;
-            }
-        }
+        // this can be null if dst_path is 0
+        Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
 
         pathDelegate.transform(matrixDelegate, dstDelegate);
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
new file mode 100644
index 0000000..9038636
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PorterDuffColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    @Override
+    public boolean isSupported() {
+        return false;
+    }
+
+    @Override
+    public String getSupportMessage() {
+        return "PorterDuff Color Filters are not supported.";
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
+        PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
+            int porterDuffMode) {
+        // pass
+        return 0;
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
new file mode 100644
index 0000000..9fd67be
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Rasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of Rasterizer have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Rasterizer class.
+ *
+ * This also serve as a base class for all Rasterizer delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Rasterizer_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<Rasterizer_Delegate> sManager =
+            new DelegateManager<Rasterizer_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+
+    // ---- Public Helper methods ----
+
+    public static Rasterizer_Delegate getDelegate(int nativeShader) {
+        return sManager.getDelegate(nativeShader);
+    }
+
+    public abstract boolean isSupported();
+    public abstract String getSupportMessage();
+
+    // ---- native methods ----
+
+    /*package*/ static void finalizer(int native_instance) {
+        sManager.removeDelegate(native_instance);
+    }
+
+    // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
new file mode 100644
index 0000000..684bb90
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+import android.os.Parcel;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Region
+ *
+ * Through the layoutlib_create tool, the original native methods of Region have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Region class.
+ *
+ * This also serve as a base class for all Region delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Region_Delegate {
+
+    // ---- delegate manager ----
+    protected static final DelegateManager<Region_Delegate> sManager =
+            new DelegateManager<Region_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+    private Area mArea = new Area();
+
+    // ---- Public Helper methods ----
+
+    public static Region_Delegate getDelegate(int nativeShader) {
+        return sManager.getDelegate(nativeShader);
+    }
+
+    public Area getJavaArea() {
+        return mArea;
+    }
+
+    /**
+     * Combines two {@link Shape} into another one (actually an {@link Area}), according
+     * to the given {@link Region.Op}.
+     *
+     * If the Op is not one that combines two shapes, then this return null
+     *
+     * @param shape1 the firt shape to combine
+     * @param shape2 the 2nd shape to combine
+     * @param regionOp the operande for the combine
+     * @return a new area or null.
+     */
+    public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) {
+        if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
+            // result is always a new area.
+            Area result = new Area(shape1);
+            result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+            return result;
+
+        } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
+            // result is always a new area.
+            Area result = new Area(shape1);
+            result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+            return result;
+
+        } else if (regionOp == Region.Op.UNION.nativeInt) {
+            // result is always a new area.
+            Area result = new Area(shape1);
+            result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+            return result;
+
+        } else if (regionOp == Region.Op.XOR.nativeInt) {
+            // result is always a new area.
+            Area result = new Area(shape1);
+            result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+
+        } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
+            // result is always a new area.
+            Area result = new Area(shape2);
+            result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
+            return result;
+        }
+
+        return null;
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static int nativeConstructor() {
+        Region_Delegate newDelegate = new Region_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static void nativeDestructor(int native_region) {
+        sManager.removeDelegate(native_region);
+    }
+
+    /*package*/ static boolean nativeSetRegion(int native_dst, int native_src) {
+        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+        if (dstRegion == null) {
+            return true;
+        }
+
+        Region_Delegate srcRegion = sManager.getDelegate(native_src);
+        if (srcRegion == null) {
+            return true;
+        }
+
+        dstRegion.mArea.reset();
+        dstRegion.mArea.add(srcRegion.mArea);
+
+        return true;
+    }
+
+    /*package*/ static boolean nativeSetRect(int native_dst,
+            int left, int top, int right, int bottom) {
+        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+        if (dstRegion == null) {
+            return true;
+        }
+
+        dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top));
+        return dstRegion.mArea.getBounds().isEmpty() == false;
+    }
+
+    /*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) {
+        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+        if (dstRegion == null) {
+            return true;
+        }
+
+        Path_Delegate path = Path_Delegate.getDelegate(native_path);
+        if (path == null) {
+            return true;
+        }
+
+        dstRegion.mArea = new Area(path.getJavaShape());
+
+        Region_Delegate clip = sManager.getDelegate(native_clip);
+        if (clip != null) {
+            dstRegion.mArea.subtract(clip.getJavaArea());
+        }
+
+        return dstRegion.mArea.getBounds().isEmpty() == false;
+    }
+
+    /*package*/ static boolean nativeGetBounds(int native_region, Rect rect) {
+        Region_Delegate region = sManager.getDelegate(native_region);
+        if (region == null) {
+            return true;
+        }
+
+        Rectangle bounds = region.mArea.getBounds();
+        if (bounds.isEmpty()) {
+            rect.left = rect.top = rect.right = rect.bottom = 0;
+            return false;
+        }
+
+        rect.left = bounds.x;
+        rect.top = bounds.y;
+        rect.right = bounds.x + bounds.width;
+        rect.bottom = bounds.y + bounds.height;
+        return true;
+    }
+
+    /*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) {
+        Region_Delegate region = sManager.getDelegate(native_region);
+        if (region == null) {
+            return false;
+        }
+
+        Path_Delegate path = Path_Delegate.getDelegate(native_path);
+        if (path == null) {
+            return false;
+        }
+
+        if (region.mArea.isEmpty()) {
+            path.reset();
+            return false;
+        }
+
+        path.setPathIterator(region.mArea.getPathIterator(new AffineTransform()));
+        return true;
+    }
+
+    /*package*/ static boolean nativeOp(int native_dst,
+            int left, int top, int right, int bottom, int op) {
+        Region_Delegate region = sManager.getDelegate(native_dst);
+        if (region == null) {
+            return false;
+        }
+
+        region.mArea = combineShapes(region.mArea,
+                new Rectangle2D.Float(left, top, right - left, bottom - top), op);
+
+        assert region.mArea != null;
+        if (region.mArea != null) {
+            region.mArea = new Area();
+        }
+
+        return region.mArea.getBounds().isEmpty() == false;
+    }
+
+    /*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) {
+        Region_Delegate region = sManager.getDelegate(native_dst);
+        if (region == null) {
+            return false;
+        }
+
+        region.mArea = combineShapes(region.mArea,
+                new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op);
+
+        assert region.mArea != null;
+        if (region.mArea != null) {
+            region.mArea = new Area();
+        }
+
+        return region.mArea.getBounds().isEmpty() == false;
+    }
+
+    /*package*/ static boolean nativeOp(int native_dst,
+            int native_region1, int native_region2, int op) {
+        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+        if (dstRegion == null) {
+            return true;
+        }
+
+        Region_Delegate region1 = sManager.getDelegate(native_region1);
+        if (region1 == null) {
+            return false;
+        }
+
+        Region_Delegate region2 = sManager.getDelegate(native_region2);
+        if (region2 == null) {
+            return false;
+        }
+
+        dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op);
+
+        assert dstRegion.mArea != null;
+        if (dstRegion.mArea != null) {
+            dstRegion.mArea = new Area();
+        }
+
+        return dstRegion.mArea.getBounds().isEmpty() == false;
+
+    }
+
+    /*package*/ static int nativeCreateFromParcel(Parcel p) {
+        // This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
+        // used during aidl call so really this should not be called.
+        Bridge.getLog().error(null,
+                "AIDL is not suppored, and therefore Regions cannot be created from parcels.");
+        return 0;
+    }
+
+    /*package*/ static boolean nativeWriteToParcel(int native_region,
+                                                      Parcel p) {
+        // This is only called when sending a region through aidl, so really this should not
+        // be called.
+        Bridge.getLog().error(null,
+                "AIDL is not suppored, and therefore Regions cannot be written to parcels.");
+        return false;
+    }
+
+    /*package*/ static boolean nativeEquals(int native_r1, int native_r2) {
+        Region_Delegate region1 = sManager.getDelegate(native_r1);
+        if (region1 == null) {
+            return false;
+        }
+
+        Region_Delegate region2 = sManager.getDelegate(native_r2);
+        if (region2 == null) {
+            return false;
+        }
+
+        return region1.mArea.equals(region2.mArea);
+    }
+
+    // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index 3759b26..7903ac9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -82,27 +82,16 @@
         // get the delegate from the native int.
         Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
         if (shaderDelegate == null) {
-            assert false;
             return false;
         }
 
-        Matrix_Delegate localMatrixDelegate = null;
-        if (shaderDelegate.mLocalMatrix > 0) {
-            localMatrixDelegate = Matrix_Delegate.getDelegate(shaderDelegate.mLocalMatrix);
-            if (localMatrixDelegate == null) {
-                assert false;
-                return false;
-            }
-        }
+        // can be null if shader has no matrix (int is 0)
+        Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(
+                shaderDelegate.mLocalMatrix);
 
-        Matrix_Delegate destMatrixDelegate = null;
-        if (matrix_instance > 0) {
-            destMatrixDelegate = Matrix_Delegate.getDelegate(shaderDelegate.mLocalMatrix);
-            if (destMatrixDelegate == null) {
-                assert false;
-                return false;
-            }
-
+        // can be null if the int is 0.
+        Matrix_Delegate destMatrixDelegate = Matrix_Delegate.getDelegate(matrix_instance);
+        if (destMatrixDelegate != null) {
             if (localMatrixDelegate != null) {
                 destMatrixDelegate.set(localMatrixDelegate);
             } else {
@@ -120,7 +109,6 @@
         // get the delegate from the native int.
         Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
         if (shaderDelegate == null) {
-            assert false;
             return;
         }
 
@@ -130,14 +118,8 @@
     // ---- Private delegate/helper methods ----
 
     protected java.awt.geom.AffineTransform getLocalMatrix() {
-        Matrix_Delegate localMatrixDelegate = null;
-        if (mLocalMatrix > 0) {
-            localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix);
-            if (localMatrixDelegate == null) {
-                assert false;
-                return new java.awt.geom.AffineTransform();
-            }
-
+        Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix);
+        if (localMatrixDelegate != null) {
             return localMatrixDelegate.getAffineTransform();
         }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 0b54a0e..c7362c0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -78,7 +78,6 @@
     public static List<Font> getFonts(int native_int) {
         Typeface_Delegate delegate = sManager.getDelegate(native_int);
         if (delegate == null) {
-            assert false;
             return null;
         }
 
@@ -109,7 +108,6 @@
     /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
@@ -143,7 +141,6 @@
     /*package*/ static int nativeGetStyle(int native_instance) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
-            assert false;
             return 0;
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index b272963..05a258d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -55,11 +55,21 @@
 
     /**
      * Returns the delegate from the given native int.
+     * <p>
+     * If the int is zero, then this will always return null.
+     * <p>
+     * If the int is non zero and the delegate is not found, this will throw an assert.
+     *
      * @param native_object the native int.
      * @return the delegate or null if not found.
      */
     public T getDelegate(int native_object) {
-        return mDelegates.get(native_object);
+        if (native_object > 0) {
+            T delegate =  mDelegates.get(native_object);
+            assert delegate != null;
+            return delegate;
+        }
+        return null;
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 27268fc..a2fcb3b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -22,21 +22,19 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint_Delegate;
-import android.graphics.PathEffect_Delegate;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.graphics.Region_Delegate;
 import android.graphics.Shader_Delegate;
 import android.graphics.Xfermode_Delegate;
 
 import java.awt.AlphaComposite;
-import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Composite;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.Shape;
-import java.awt.Stroke;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Area;
 import java.awt.geom.Rectangle2D;
@@ -52,13 +50,17 @@
  * This allows for drawing through {@link #draw(Drawable, Paint_Delegate)} and
  * {@link #draw(Drawable, Paint_Delegate)}
  *
+ * Handling of layers (created with {@link Canvas#saveLayer(RectF, Paint, int)}) is handled through
+ * a list of Graphics2D for each layers. The class actually maintains a list of {@link Layer}
+ * for each layer. Doing a save() will duplicate this list so that each graphics2D object
+ * ({@link Layer#getGraphics()}) is configured only for the new snapshot.
  */
 public class GcSnapshot {
 
     private final GcSnapshot mPrevious;
     private final int mFlags;
 
-    /** list of layers. */
+    /** list of layers. The first item in the list is always the  */
     private final ArrayList<Layer> mLayers = new ArrayList<Layer>();
 
     /** temp transform in case transformation are set before a Graphics2D exists */
@@ -67,25 +69,39 @@
     private Area mClip = null;
 
     // local layer data
+    /** a local layer created with {@link Canvas#saveLayer(RectF, Paint, int)}.
+     * If this is null, this does not mean there's no layer, just that the snapshot is not the
+     * one that created the layer.
+     * @see #getLayerSnapshot()
+     */
     private final Layer mLocalLayer;
     private final Paint_Delegate mLocalLayerPaint;
-    private Rect mLocalLayerRegion;
+    private final Rect mLayerBounds;
 
     public interface Drawable {
         void draw(Graphics2D graphics, Paint_Delegate paint);
     }
 
     /**
-     * class containing information about a layer.
+     * Class containing information about a layer.
+     *
+     * This contains graphics, bitmap and layer information.
      */
     private static class Layer {
         private final Graphics2D mGraphics;
         private final Bitmap_Delegate mBitmap;
         private final BufferedImage mImage;
+        /** the flags that were used to configure the layer. This is never changed, and passed
+         * as is when {@link #makeCopy()} is called */
+        private final int mFlags;
+        /** the original content of the layer when the next object was created. This is not
+         * passed in {@link #makeCopy()} and instead is recreated when a new layer is added
+         * (depending on its flags) */
         private BufferedImage mOriginalCopy;
 
         /**
-         * Creates a layer with a graphics and a bitmap.
+         * Creates a layer with a graphics and a bitmap. This is only used to create
+         * the base layer.
          *
          * @param graphics the graphics
          * @param bitmap the bitmap
@@ -94,20 +110,23 @@
             mGraphics = graphics;
             mBitmap = bitmap;
             mImage = mBitmap.getImage();
+            mFlags = 0;
         }
 
         /**
          * Creates a layer with a graphics and an image. If the image belongs to a
-         * {@link Bitmap_Delegate}, then {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should
-         * be used.
+         * {@link Bitmap_Delegate} (case of the base layer), then
+         * {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should be used.
          *
-         * @param graphics the graphics
-         * @param image the image
+         * @param graphics the graphics the new graphics for this layer
+         * @param image the image the image from which the graphics came
+         * @param flags the flags that were used to save this layer
          */
-        Layer(Graphics2D graphics, BufferedImage image) {
+        Layer(Graphics2D graphics, BufferedImage image, int flags) {
             mGraphics = graphics;
             mBitmap = null;
             mImage = image;
+            mFlags = flags;
         }
 
         /** The Graphics2D, guaranteed to be non null */
@@ -120,12 +139,21 @@
             return mImage;
         }
 
+        /** Returns the layer save flags. This is only valid for additional layers.
+         * For the base layer this will always return 0;
+         * For a given layer, all further copies of this {@link Layer} object in new snapshots
+         * will always return the same value.
+         */
+        int getFlags() {
+            return mFlags;
+        }
+
         Layer makeCopy() {
             if (mBitmap != null) {
                 return new Layer((Graphics2D) mGraphics.create(), mBitmap);
             }
 
-            return new Layer((Graphics2D) mGraphics.create(), mImage);
+            return new Layer((Graphics2D) mGraphics.create(), mImage, mFlags);
         }
 
         /** sets an optional copy of the original content to be used during restore */
@@ -203,6 +231,7 @@
         mFlags = 0;
         mLocalLayer = null;
         mLocalLayerPaint = null;
+        mLayerBounds = null;
     }
 
     /**
@@ -233,11 +262,11 @@
             // get the current transform
             AffineTransform matrix = mLayers.get(0).getGraphics().getTransform();
 
-            // transform the layerBounds and puts it into a int rect
+            // transform the layerBounds with the current transform and stores it into a int rect
             RectF rect2 = new RectF();
             mapRect(matrix, rect2, layerBounds);
-            mLocalLayerRegion = new Rect();
-            rect2.round(mLocalLayerRegion);
+            mLayerBounds = new Rect();
+            rect2.round(mLayerBounds);
 
             // get the base layer (always at index 0)
             Layer baseLayer = mLayers.get(0);
@@ -246,7 +275,9 @@
             BufferedImage layerImage = new BufferedImage(
                     baseLayer.getImage().getWidth(),
                     baseLayer.getImage().getHeight(),
-                    BufferedImage.TYPE_INT_ARGB);
+                    (mFlags & Canvas.HAS_ALPHA_LAYER_SAVE_FLAG) != 0 ?
+                            BufferedImage.TYPE_INT_ARGB :
+                                BufferedImage.TYPE_INT_RGB);
 
             // create a graphics for it so that drawing can be done.
             Graphics2D layerGraphics = layerImage.createGraphics();
@@ -260,7 +291,7 @@
             layerGraphics.setClip(currentClip);
 
             // create a new layer for this new layer and add it to the list at the end.
-            mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage));
+            mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage, flags));
 
             // if the drawing is not clipped to the local layer only, we save the current content
             // of all other layers. We are only interested in the part that will actually
@@ -268,16 +299,16 @@
             // This is so that we can erase the drawing that goes in the layers below that will
             // be coming from the layer itself.
             if ((mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0) {
-                int w = mLocalLayerRegion.width();
-                int h = mLocalLayerRegion.height();
+                int w = mLayerBounds.width();
+                int h = mLayerBounds.height();
                 for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
                     Layer layer = mLayers.get(i);
                     BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                     Graphics2D graphics = image.createGraphics();
                     graphics.drawImage(layer.getImage(),
                             0, 0, w, h,
-                            mLocalLayerRegion.left, mLocalLayerRegion.top,
-                                    mLocalLayerRegion.right, mLocalLayerRegion.bottom,
+                            mLayerBounds.left, mLayerBounds.top,
+                                    mLayerBounds.right, mLayerBounds.bottom,
                             null);
                     graphics.dispose();
                     layer.setOriginalCopy(image);
@@ -285,6 +316,7 @@
             }
         } else {
             mLocalLayer = null;
+            mLayerBounds = null;
         }
 
         mLocalLayerPaint  = paint;
@@ -414,72 +446,39 @@
         }
     }
 
-    public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
+    public boolean clip(Shape shape, int regionOp) {
+        Area area = null;
+        if (regionOp == Region.Op.REPLACE.nativeInt) {
+            area = new Area(shape);
+        } else {
+            area = Region_Delegate.combineShapes(getClip(), shape, regionOp);
+        }
+
+        assert area != null;
+
         if (mLayers.size() > 0) {
-            Shape clip = null;
-            if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
-                Area newClip = new Area(getClip());
-                newClip.subtract(new Area(
-                        new Rectangle2D.Float(left, top, right - left, bottom - top)));
-                clip = newClip;
-
-            } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
+            if (area != null) {
                 for (Layer layer : mLayers) {
-                    layer.getGraphics().clipRect(
-                            (int) left, (int) top, (int) (right - left), (int) (bottom - top));
-                }
-
-            } else if (regionOp == Region.Op.UNION.nativeInt) {
-                Area newClip = new Area(getClip());
-                newClip.add(new Area(
-                        new Rectangle2D.Float(left, top, right - left, bottom - top)));
-                clip = newClip;
-
-            } else if (regionOp == Region.Op.XOR.nativeInt) {
-                Area newClip = new Area(getClip());
-                newClip.exclusiveOr(new Area(
-                        new Rectangle2D.Float(left, top, right - left, bottom - top)));
-                clip = newClip;
-
-            } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
-                Area newClip = new Area(
-                        new Rectangle2D.Float(left, top, right - left, bottom - top));
-                newClip.subtract(new Area(getClip()));
-                clip = newClip;
-
-            } else if (regionOp == Region.Op.REPLACE.nativeInt) {
-                for (Layer layer : mLayers) {
-                    layer.getGraphics().setClip(
-                            (int) left, (int) top, (int) (right - left), (int) (bottom - top));
-                }
-            }
-
-            if (clip != null) {
-                for (Layer layer : mLayers) {
-                    layer.getGraphics().setClip(clip);
+                    layer.getGraphics().setClip(area);
                 }
             }
 
             return getClip().getBounds().isEmpty() == false;
         } else {
-            if (mClip == null) {
+            if (area != null) {
+                mClip = area;
+            } else {
                 mClip = new Area();
             }
 
-            if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
-                //FIXME
-            } else if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
-            } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
-            } else if (regionOp == Region.Op.UNION.nativeInt) {
-            } else if (regionOp == Region.Op.XOR.nativeInt) {
-            } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
-            } else if (regionOp == Region.Op.REPLACE.nativeInt) {
-            }
-
             return mClip.getBounds().isEmpty() == false;
         }
     }
 
+    public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
+        return clip(new Rectangle2D.Float(left, top, right - left, bottom - top), regionOp);
+    }
+
     public Shape getClip() {
         if (mLayers.size() > 0) {
             // they all have the same clip
@@ -529,14 +528,28 @@
      */
     public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly,
             boolean forceSrcMode) {
-        // if we clip to the layer, then we only draw in the layer
-        if (mLocalLayer != null && (mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) != 0) {
-            drawInLayer(mLocalLayer, drawable, paint, compositeOnly, forceSrcMode);
+        // the current snapshot may not have a mLocalLayer (ie it was created on save() instead
+        // of saveLayer(), but that doesn't mean there's no layer.
+        // mLayers however saves all the information we need (flags).
+        if (mLayers.size() == 1) {
+            // no layer, only base layer. easy case.
+            drawInLayer(mLayers.get(0), drawable, paint, compositeOnly, forceSrcMode);
         } else {
-            // draw in all the layers
-            for (Layer layer : mLayers) {
+            // draw in all the layers until the layer save flags tells us to stop (ie drawing
+            // in that layer is limited to the layer itself.
+            int flags;
+            int i = mLayers.size() - 1;
+
+            do {
+                Layer layer = mLayers.get(i);
+
                 drawInLayer(layer, drawable, paint, compositeOnly, forceSrcMode);
-            }
+
+                // then go to previous layer, only if there are any left, and its flags
+                // doesn't restrict drawing to the layer itself.
+                i--;
+                flags = layer.getFlags();
+            } while (i >= 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
         }
     }
 
@@ -560,56 +573,26 @@
 
     private GcSnapshot doRestore() {
         if (mPrevious != null) {
-            boolean forceAllSave = false;
             if (mLocalLayer != null) {
-                forceAllSave = true; // layers always save both clip and transform
+                // prepare to blit the layers in which we have draw, in the layer beneath
+                // them, starting with the top one (which is the current local layer).
+                int i = mLayers.size() - 1;
+                int flags;
+                do {
+                    Layer dstLayer = mLayers.get(i - 1);
 
-                // prepare to draw the current layer in the previous layers, ie all layers but
-                // the last one, since the last one is the local layer
-                for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
-                    Layer layer = mLayers.get(i);
+                    restoreLayer(dstLayer);
 
-                    Graphics2D baseGfx = layer.getImage().createGraphics();
-
-                    // if the layer contains an original copy this means the flags
-                    // didn't restrict drawing to the local layer and we need to make sure the
-                    // layer bounds in the layer beneath didn't receive any drawing.
-                    // so we use the originalCopy to erase the new drawings in there.
-                    BufferedImage originalCopy = layer.getOriginalCopy();
-                    if (originalCopy != null) {
-                        Graphics2D g = (Graphics2D) baseGfx.create();
-                        g.setComposite(AlphaComposite.Src);
-
-                        g.drawImage(originalCopy,
-                                mLocalLayerRegion.left, mLocalLayerRegion.top,
-                                        mLocalLayerRegion.right, mLocalLayerRegion.bottom,
-                                0, 0, mLocalLayerRegion.width(), mLocalLayerRegion.height(),
-                                null);
-                        g.dispose();
-                    }
-
-                    // now draw put the content of the local layer onto the layer, using the paint
-                    // information
-                    Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
-                            true /*alphaOnly*/, false /*forceSrcMode*/);
-
-                    g.drawImage(mLocalLayer.getImage(),
-                            mLocalLayerRegion.left, mLocalLayerRegion.top,
-                                    mLocalLayerRegion.right, mLocalLayerRegion.bottom,
-                            mLocalLayerRegion.left, mLocalLayerRegion.top,
-                                    mLocalLayerRegion.right, mLocalLayerRegion.bottom,
-                            null);
-                    g.dispose();
-
-                    baseGfx.dispose();
-                }
+                    flags = dstLayer.getFlags();
+                    i--;
+                } while (i > 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
             }
 
             // if this snapshot does not save everything, then set the previous snapshot
             // to this snapshot content
 
             // didn't save the matrix? set the current matrix on the previous snapshot
-            if (forceAllSave == false && (mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
+            if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
                 AffineTransform mtx = getTransform();
                 for (Layer layer : mPrevious.mLayers) {
                     layer.getGraphics().setTransform(mtx);
@@ -617,7 +600,7 @@
             }
 
             // didn't save the clip? set the current clip on the previous snapshot
-            if (forceAllSave == false && (mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
+            if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
                 Shape clip = getClip();
                 for (Layer layer : mPrevious.mLayers) {
                     layer.getGraphics().setClip(clip);
@@ -632,6 +615,40 @@
         return mPrevious;
     }
 
+    private void restoreLayer(Layer dstLayer) {
+
+        Graphics2D baseGfx = dstLayer.getImage().createGraphics();
+
+        // if the layer contains an original copy this means the flags
+        // didn't restrict drawing to the local layer and we need to make sure the
+        // layer bounds in the layer beneath didn't receive any drawing.
+        // so we use the originalCopy to erase the new drawings in there.
+        BufferedImage originalCopy = dstLayer.getOriginalCopy();
+        if (originalCopy != null) {
+            Graphics2D g = (Graphics2D) baseGfx.create();
+            g.setComposite(AlphaComposite.Src);
+
+            g.drawImage(originalCopy,
+                    mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+                    0, 0, mLayerBounds.width(), mLayerBounds.height(),
+                    null);
+            g.dispose();
+        }
+
+        // now draw put the content of the local layer onto the layer,
+        // using the paint information
+        Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
+                true /*alphaOnly*/, false /*forceSrcMode*/);
+
+        g.drawImage(mLocalLayer.getImage(),
+                mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+                mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+                null);
+        g.dispose();
+
+        baseGfx.dispose();
+    }
+
     /**
      * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
      * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
@@ -654,23 +671,19 @@
 
         // get the shader first, as it'll replace the color if it can be used it.
         if (compositeOnly == false) {
-            int nativeShader = paint.getShader();
-            if (nativeShader > 0) {
-                Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(nativeShader);
-                assert shaderDelegate != null;
-                if (shaderDelegate != null) {
-                    if (shaderDelegate.isSupported()) {
-                        java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
-                        assert shaderPaint != null;
-                        if (shaderPaint != null) {
-                            g.setPaint(shaderPaint);
-                            customShader = true;
-                        }
-                    } else {
-                        Bridge.getLog().fidelityWarning(null,
-                                shaderDelegate.getSupportMessage(),
-                                null);
+            Shader_Delegate shaderDelegate = paint.getShader();
+            if (shaderDelegate != null) {
+                if (shaderDelegate.isSupported()) {
+                    java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
+                    assert shaderPaint != null;
+                    if (shaderPaint != null) {
+                        g.setPaint(shaderPaint);
+                        customShader = true;
                     }
+                } else {
+                    Bridge.getLog().fidelityWarning(null,
+                            shaderDelegate.getSupportMessage(),
+                            null);
                 }
             }
 
@@ -679,35 +692,8 @@
                 g.setColor(new Color(paint.getColor(), true /*hasAlpha*/));
             }
 
-            boolean customStroke = false;
-            int pathEffect = paint.getPathEffect();
-            if (pathEffect > 0) {
-                PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(pathEffect);
-                assert effectDelegate != null;
-                if (effectDelegate != null) {
-                    if (effectDelegate.isSupported()) {
-                        Stroke stroke = effectDelegate.getStroke(paint);
-                        assert stroke != null;
-                        if (stroke != null) {
-                            g.setStroke(stroke);
-                            customStroke = true;
-                        }
-                    } else {
-                        Bridge.getLog().fidelityWarning(null,
-                                effectDelegate.getSupportMessage(),
-                                null);
-                    }
-                }
-            }
-
-            // if no custom stroke as been set, set the default one.
-            if (customStroke == false) {
-                g.setStroke(new BasicStroke(
-                        paint.getStrokeWidth(),
-                        paint.getJavaCap(),
-                        paint.getJavaJoin(),
-                        paint.getJavaStrokeMiter()));
-            }
+            // set the stroke
+            g.setStroke(paint.getJavaStroke());
         }
 
         // the alpha for the composite. Always opaque if the normal paint color is used since
@@ -719,23 +705,19 @@
                     AlphaComposite.SRC, (float) alpha / 255.f));
         } else {
             boolean customXfermode = false;
-            int xfermode = paint.getXfermode();
-            if (xfermode > 0) {
-                Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(xfermode);
-                assert xfermodeDelegate != null;
-                if (xfermodeDelegate != null) {
-                    if (xfermodeDelegate.isSupported()) {
-                        Composite composite = xfermodeDelegate.getComposite(alpha);
-                        assert composite != null;
-                        if (composite != null) {
-                            g.setComposite(composite);
-                            customXfermode = true;
-                        }
-                    } else {
-                        Bridge.getLog().fidelityWarning(null,
-                                xfermodeDelegate.getSupportMessage(),
-                                null);
+            Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
+            if (xfermodeDelegate != null) {
+                if (xfermodeDelegate.isSupported()) {
+                    Composite composite = xfermodeDelegate.getComposite(alpha);
+                    assert composite != null;
+                    if (composite != null) {
+                        g.setComposite(composite);
+                        customXfermode = true;
                     }
+                } else {
+                    Bridge.getLog().fidelityWarning(null,
+                            xfermodeDelegate.getSupportMessage(),
+                            null);
                 }
             }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index baa4f06..6b589d7 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -109,22 +109,34 @@
         "android.graphics.AvoidXfermode",
         "android.graphics.Bitmap",
         "android.graphics.BitmapShader",
+        "android.graphics.BlurMaskFilter",
         "android.graphics.Canvas",
+        "android.graphics.ColorFilter",
+        "android.graphics.ColorMatrixColorFilter",
         "android.graphics.ComposePathEffect",
         "android.graphics.ComposeShader",
         "android.graphics.CornerPathEffect",
         "android.graphics.DashPathEffect",
         "android.graphics.DiscretePathEffect",
+        "android.graphics.DrawFilter",
+        "android.graphics.EmbossMaskFilter",
+        "android.graphics.LayerRasterizer",
+        "android.graphics.LightingColorFilter",
         "android.graphics.LinearGradient",
+        "android.graphics.MaskFilter",
         "android.graphics.Matrix",
         "android.graphics.NinePatch",
         "android.graphics.Paint",
+        "android.graphics.PaintFlagsDrawFilter",
         "android.graphics.Path",
         "android.graphics.PathDashPathEffect",
         "android.graphics.PathEffect",
         "android.graphics.PixelXorXfermode",
+        "android.graphics.PorterDuffColorFilter",
         "android.graphics.PorterDuffXfermode",
         "android.graphics.RadialGradient",
+        "android.graphics.Rasterizer",
+        "android.graphics.Region",
         "android.graphics.Shader",
         "android.graphics.SumPathEffect",
         "android.graphics.SweepGradient",