Merge "Dejank: also animate window moves due to requested size changes."
diff --git a/api/current.txt b/api/current.txt
index 1b04830..29f093a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8035,6 +8035,9 @@
     ctor public Camera();
     method public void applyToCanvas(android.graphics.Canvas);
     method public float dotWithNormal(float, float, float);
+    method public float getLocationX();
+    method public float getLocationY();
+    method public float getLocationZ();
     method public void getMatrix(android.graphics.Matrix);
     method public void restore();
     method public void rotate(float, float, float);
@@ -21639,6 +21642,10 @@
     method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException;
   }
 
+  public class LocaleUtil {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale);
+  }
+
   public final class Log {
     method public static int d(java.lang.String, java.lang.String);
     method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
@@ -23196,6 +23203,7 @@
     method public final int getBottom();
     method protected float getBottomFadingEdgeStrength();
     method protected int getBottomPaddingOffset();
+    method public float getCameraDistance();
     method public java.lang.CharSequence getContentDescription();
     method public final android.content.Context getContext();
     method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 901f7c7..da38df1 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -61,6 +61,8 @@
     private boolean mWaitOption = false;
     private boolean mStopOption = false;
 
+    private boolean mOpenglTraceOption = false;
+
     private int mRepeat = 0;
 
     private String mProfileFile;
@@ -151,6 +153,7 @@
         mDebugOption = false;
         mWaitOption = false;
         mStopOption = false;
+        mOpenglTraceOption = false;
         mRepeat = 0;
         mProfileFile = null;
         Uri data = null;
@@ -307,6 +310,8 @@
                 mRepeat = Integer.parseInt(nextArgRequired());
             } else if (opt.equals("-S")) {
                 mStopOption = true;
+            } else if (opt.equals("--opengl-trace")) {
+                mOpenglTraceOption = true;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
@@ -440,17 +445,19 @@
                     return;
                 }
             }
-    
+
             IActivityManager.WaitResult result = null;
             int res;
             if (mWaitOption) {
                 result = mAm.startActivityAndWait(null, intent, mimeType,
-                            null, 0, null, null, 0, false, mDebugOption,
+                            null, 0, null, null, 0, false,
+                            mDebugOption, mOpenglTraceOption,
                             mProfileFile, fd, mProfileAutoStop);
                 res = result.result;
             } else {
                 res = mAm.startActivity(null, intent, mimeType,
-                        null, 0, null, null, 0, false, mDebugOption,
+                        null, 0, null, null, 0, false,
+                        mDebugOption, mOpenglTraceOption,
                         mProfileFile, fd, mProfileAutoStop);
             }
             PrintStream out = mWaitOption ? System.out : System.err;
@@ -1277,7 +1284,7 @@
         System.err.println(
                 "usage: am [subcommand] [options]\n" +
                 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
-                "               [--R COUNT] [-S] <INTENT>\n" +
+                "               [--R COUNT] [-S] [--opengl-trace] <INTENT>\n" +
                 "       am startservice <INTENT>\n" +
                 "       am force-stop <PACKAGE>\n" +
                 "       am kill <PACKAGE>\n" +
@@ -1304,6 +1311,7 @@
                 "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
                 "        the top activity will be finished.\n" +
                 "    -S: force stop the target app before starting the activity\n" +
+                "    --opengl-trace: enable tracing of OpenGL functions\n" +
                 "\n" +
                 "am startservice: start a Service.\n" +
                 "\n" +
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 599487dc..0f2aa46 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3388,17 +3388,16 @@
                 intent.setAllowFds(false);
                 result = ActivityManagerNative.getDefault()
                     .startActivity(mMainThread.getApplicationThread(),
-                            intent, intent.resolveTypeIfNeeded(
-                                    getContentResolver()),
+                            intent, intent.resolveTypeIfNeeded(getContentResolver()),
                             null, 0,
-                            mToken, mEmbeddedID, requestCode, true, false,
-                            null, null, false);
+                            mToken, mEmbeddedID, requestCode, true /* onlyIfNeeded */,
+                            false, false, null, null, false);
             } catch (RemoteException e) {
                 // Empty
             }
-            
+
             Instrumentation.checkStartActivityResult(result, intent);
-            
+
             if (requestCode >= 0) {
                 // If this start is requesting a result, we can avoid making
                 // the activity visible until the result is received.  Setting
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b952649..7daaf7d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -120,17 +120,19 @@
             Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
             int grantedMode = data.readInt();
             IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();    
+            String resultWho = data.readString();
             int requestCode = data.readInt();
             boolean onlyIfNeeded = data.readInt() != 0;
             boolean debug = data.readInt() != 0;
+            boolean openglTrace = data.readInt() != 0;
             String profileFile = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
                     ? data.readFileDescriptor() : null;
             boolean autoStopProfiler = data.readInt() != 0;
             int result = startActivity(app, intent, resolvedType,
                     grantedUriPermissions, grantedMode, resultTo, resultWho,
-                    requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
+                    requestCode, onlyIfNeeded, debug, openglTrace,
+                    profileFile, profileFd, autoStopProfiler);
             reply.writeNoException();
             reply.writeInt(result);
             return true;
@@ -146,17 +148,19 @@
             Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
             int grantedMode = data.readInt();
             IBinder resultTo = data.readStrongBinder();
-            String resultWho = data.readString();    
+            String resultWho = data.readString();
             int requestCode = data.readInt();
             boolean onlyIfNeeded = data.readInt() != 0;
             boolean debug = data.readInt() != 0;
+            boolean openglTrace = data.readInt() != 0;
             String profileFile = data.readString();
             ParcelFileDescriptor profileFd = data.readInt() != 0
                     ? data.readFileDescriptor() : null;
             boolean autoStopProfiler = data.readInt() != 0;
             WaitResult result = startActivityAndWait(app, intent, resolvedType,
                     grantedUriPermissions, grantedMode, resultTo, resultWho,
-                    requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
+                    requestCode, onlyIfNeeded, debug, openglTrace,
+                    profileFile, profileFd, autoStopProfiler);
             reply.writeNoException();
             result.writeToParcel(reply, 0);
             return true;
@@ -1607,17 +1611,17 @@
     {
         mRemote = remote;
     }
-    
+
     public IBinder asBinder()
     {
         return mRemote;
     }
-    
+
     public int startActivity(IApplicationThread caller, Intent intent,
             String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
             IBinder resultTo, String resultWho,
             int requestCode, boolean onlyIfNeeded,
-            boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+            boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
             boolean autoStopProfiler) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -1632,6 +1636,7 @@
         data.writeInt(requestCode);
         data.writeInt(onlyIfNeeded ? 1 : 0);
         data.writeInt(debug ? 1 : 0);
+        data.writeInt(openglTrace ? 1 : 0);
         data.writeString(profileFile);
         if (profileFd != null) {
             data.writeInt(1);
@@ -1651,7 +1656,7 @@
             String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
             IBinder resultTo, String resultWho,
             int requestCode, boolean onlyIfNeeded,
-            boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+            boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
             boolean autoStopProfiler) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -1666,6 +1671,7 @@
         data.writeInt(requestCode);
         data.writeInt(onlyIfNeeded ? 1 : 0);
         data.writeInt(debug ? 1 : 0);
+        data.writeInt(openglTrace ? 1 : 0);
         data.writeString(profileFile);
         if (profileFd != null) {
             data.writeInt(1);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index aa15f39..2610d87 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -376,6 +376,7 @@
         Bundle instrumentationArgs;
         IInstrumentationWatcher instrumentationWatcher;
         int debugMode;
+        boolean enableOpenGlTrace;
         boolean restrictedBackupMode;
         boolean persistent;
         Configuration config;
@@ -676,8 +677,8 @@
                 ComponentName instrumentationName, String profileFile,
                 ParcelFileDescriptor profileFd, boolean autoStopProfiler,
                 Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
-                int debugMode, boolean isRestrictedBackupMode, boolean persistent,
-                Configuration config, CompatibilityInfo compatInfo,
+                int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode,
+                boolean persistent, Configuration config, CompatibilityInfo compatInfo,
                 Map<String, IBinder> services, Bundle coreSettings) {
 
             if (services != null) {
@@ -695,6 +696,7 @@
             data.instrumentationArgs = instrumentationArgs;
             data.instrumentationWatcher = instrumentationWatcher;
             data.debugMode = debugMode;
+            data.enableOpenGlTrace = enableOpenGlTrace;
             data.restrictedBackupMode = isRestrictedBackupMode;
             data.persistent = persistent;
             data.config = config;
@@ -3912,6 +3914,11 @@
             }
         }
 
+        // Enable OpenGL tracing if required
+        if (data.enableOpenGlTrace) {
+            GLUtils.enableTracing();
+        }
+
         /**
          * Initialize the default http proxy in this process for the reasons we set the time zone.
          */
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index e75d7b4..437362b 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -267,6 +267,7 @@
             IBinder binder = data.readStrongBinder();
             IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
             int testMode = data.readInt();
+            boolean openGlTrace = data.readInt() != 0;
             boolean restrictedBackupMode = (data.readInt() != 0);
             boolean persistent = (data.readInt() != 0);
             Configuration config = Configuration.CREATOR.createFromParcel(data);
@@ -275,11 +276,11 @@
             Bundle coreSettings = data.readBundle();
             bindApplication(packageName, info,
                             providers, testName, profileName, profileFd, autoStopProfiler,
-                            testArgs, testWatcher, testMode, restrictedBackupMode, persistent,
-                            config, compatInfo, services, coreSettings);
+                            testArgs, testWatcher, testMode, openGlTrace, restrictedBackupMode,
+                            persistent, config, compatInfo, services, coreSettings);
             return true;
         }
-        
+
         case SCHEDULE_EXIT_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -849,8 +850,9 @@
     public final void bindApplication(String packageName, ApplicationInfo info,
             List<ProviderInfo> providers, ComponentName testName, String profileName,
             ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle testArgs,
-            IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode,
-            boolean persistent, Configuration config, CompatibilityInfo compatInfo,
+            IInstrumentationWatcher testWatcher, int debugMode, boolean openGlTrace,
+            boolean restrictedBackupMode, boolean persistent,
+            Configuration config, CompatibilityInfo compatInfo,
             Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -874,6 +876,7 @@
         data.writeBundle(testArgs);
         data.writeStrongInterface(testWatcher);
         data.writeInt(debugMode);
+        data.writeInt(openGlTrace ? 1 : 0);
         data.writeInt(restrictedBackupMode ? 1 : 0);
         data.writeInt(persistent ? 1 : 0);
         config.writeToParcel(data, 0);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ea2545f..acebf58 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -84,12 +84,12 @@
     public int startActivity(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo, String resultWho, int requestCode,
-            boolean onlyIfNeeded, boolean debug, String profileFile,
+            boolean onlyIfNeeded, boolean debug, boolean openglTrace, String profileFile,
             ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException;
     public WaitResult startActivityAndWait(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo, String resultWho, int requestCode,
-            boolean onlyIfNeeded, boolean debug, String profileFile,
+            boolean onlyIfNeeded, boolean debug, boolean openglTrace, String profileFile,
             ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException;
     public int startActivityWithConfig(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 6ad1736a..70029d2 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -89,7 +89,7 @@
     void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
             ComponentName testName, String profileName, ParcelFileDescriptor profileFd,
             boolean autoStopProfiler, Bundle testArguments, IInstrumentationWatcher testWatcher,
-            int debugMode, boolean restrictedBackupMode, boolean persistent,
+            int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
             Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
             Bundle coreSettings) throws RemoteException;
     void scheduleExit() throws RemoteException;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index c037ffb..a34e1d3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1384,7 +1384,7 @@
                 .startActivity(whoThread, intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
                         null, 0, token, target != null ? target.mEmbeddedID : null,
-                        requestCode, false, false, null, null, false);
+                        requestCode, false, false, false, null, null, false);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
         }
@@ -1482,7 +1482,8 @@
                 .startActivity(whoThread, intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
                         null, 0, token, target != null ? target.mWho : null,
-                        requestCode, false, false, null, null, false);
+                        requestCode, false, false /* debug */, false /* openglTrace */,
+                        null, null, false);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 12e3ccf..ec67d8c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
@@ -30,6 +32,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Log;
 
 import java.io.File;
@@ -267,90 +270,116 @@
             return CancellationSignal.createTransport();
         }
 
-        private void enforceReadPermission(Uri uri) {
-            final int uid = Binder.getCallingUid();
-            if (uid == mMyUid) {
-                return;
-            }
-            
+        private boolean hasReadPermission(Uri uri) {
             final Context context = getContext();
-            final String rperm = getReadPermission();
             final int pid = Binder.getCallingPid();
-            if (mExported && (rperm == null
-                    || context.checkPermission(rperm, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED)) {
-                return;
-            }
-            
-            PathPermission[] pps = getPathPermissions();
-            if (pps != null) {
-                final String path = uri.getPath();
-                int i = pps.length;
-                while (i > 0) {
-                    i--;
-                    final PathPermission pp = pps[i];
-                    final String pprperm = pp.getReadPermission();
-                    if (pprperm != null && pp.match(path)) {
-                        if (context.checkPermission(pprperm, pid, uid)
-                                == PackageManager.PERMISSION_GRANTED) {
-                            return;
+            final int uid = Binder.getCallingUid();
+
+            if (uid == mMyUid) {
+                return true;
+
+            } else if (mExported) {
+                final String componentPerm = getReadPermission();
+                if (componentPerm != null
+                        && (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED)) {
+                    return true;
+                }
+
+                // track if unprotected read is allowed; any denied
+                // <path-permission> below removes this ability
+                boolean allowDefaultRead = (componentPerm == null);
+
+                final PathPermission[] pps = getPathPermissions();
+                if (pps != null) {
+                    final String path = uri.getPath();
+                    for (PathPermission pp : pps) {
+                        final String pathPerm = pp.getReadPermission();
+                        if (pathPerm != null && pp.match(path)) {
+                            if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+                                return true;
+                            } else {
+                                // any denied <path-permission> means we lose
+                                // default <provider> access.
+                                allowDefaultRead = false;
+                            }
                         }
                     }
                 }
+
+                // if we passed <path-permission> checks above, and no default
+                // <provider> permission, then allow access.
+                if (allowDefaultRead) return true;
             }
-            
-            if (context.checkUriPermission(uri, pid, uid,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                    == PackageManager.PERMISSION_GRANTED) {
+
+            // last chance, check against any uri grants
+            if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                    == PERMISSION_GRANTED) {
+                return true;
+            }
+
+            return false;
+        }
+
+        private void enforceReadPermission(Uri uri) {
+            if (hasReadPermission(uri)) {
                 return;
             }
-            
+
             String msg = "Permission Denial: reading "
                     + ContentProvider.this.getClass().getName()
                     + " uri " + uri + " from pid=" + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + rperm;
+                    + " requires " + getReadPermission();
             throw new SecurityException(msg);
         }
 
         private boolean hasWritePermission(Uri uri) {
+            final Context context = getContext();
+            final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
+
             if (uid == mMyUid) {
                 return true;
-            }
-            
-            final Context context = getContext();
-            final String wperm = getWritePermission();
-            final int pid = Binder.getCallingPid();
-            if (mExported && (wperm == null
-                    || context.checkPermission(wperm, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED)) {
-                return true;
-            }
-            
-            PathPermission[] pps = getPathPermissions();
-            if (pps != null) {
-                final String path = uri.getPath();
-                int i = pps.length;
-                while (i > 0) {
-                    i--;
-                    final PathPermission pp = pps[i];
-                    final String ppwperm = pp.getWritePermission();
-                    if (ppwperm != null && pp.match(path)) {
-                        if (context.checkPermission(ppwperm, pid, uid)
-                                == PackageManager.PERMISSION_GRANTED) {
-                            return true;
+
+            } else if (mExported) {
+                final String componentPerm = getWritePermission();
+                if (componentPerm != null
+                        && (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED)) {
+                    return true;
+                }
+
+                // track if unprotected write is allowed; any denied
+                // <path-permission> below removes this ability
+                boolean allowDefaultWrite = (componentPerm == null);
+
+                final PathPermission[] pps = getPathPermissions();
+                if (pps != null) {
+                    final String path = uri.getPath();
+                    for (PathPermission pp : pps) {
+                        final String pathPerm = pp.getWritePermission();
+                        if (pathPerm != null && pp.match(path)) {
+                            if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+                                return true;
+                            } else {
+                                // any denied <path-permission> means we lose
+                                // default <provider> access.
+                                allowDefaultWrite = false;
+                            }
                         }
                     }
                 }
+
+                // if we passed <path-permission> checks above, and no default
+                // <provider> permission, then allow access.
+                if (allowDefaultWrite) return true;
             }
-            
-            if (context.checkUriPermission(uri, pid, uid,
-                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
-                    == PackageManager.PERMISSION_GRANTED) {
+
+            // last chance, check against any uri grants
+            if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+                    == PERMISSION_GRANTED) {
                 return true;
             }
-            
+
             return false;
         }
         
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 94a23cb..e9b06c6 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -64,19 +64,19 @@
                 break;
         }
 
-        if (mNumParameters != 0) {
-            mBindArgs = new Object[mNumParameters];
-        } else {
-            mBindArgs = null;
+        if (bindArgs != null && bindArgs.length > mNumParameters) {
+            throw new IllegalArgumentException("Too many bind arguments.  "
+                    + bindArgs.length + " arguments were provided but the statement needs "
+                    + mNumParameters + " arguments.");
         }
 
-        if (bindArgs != null) {
-            if (bindArgs.length > mNumParameters) {
-                throw new IllegalArgumentException("Too many bind arguments.  "
-                        + bindArgs.length + " arguments were provided but the statement needs "
-                        + mNumParameters + " arguments.");
+        if (mNumParameters != 0) {
+            mBindArgs = new Object[mNumParameters];
+            if (bindArgs != null) {
+                System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
             }
-            System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
+        } else {
+            mBindArgs = null;
         }
     }
 
diff --git a/core/java/android/util/LocaleUtil.java b/core/java/android/util/LocaleUtil.java
index 9953252..60526e1 100644
--- a/core/java/android/util/LocaleUtil.java
+++ b/core/java/android/util/LocaleUtil.java
@@ -24,7 +24,6 @@
 /**
  * Various utilities for Locales
  *
- * @hide
  */
 public class LocaleUtil {
 
@@ -41,9 +40,7 @@
      * {@link View#LAYOUT_DIRECTION_LTR} or
      * {@link View#LAYOUT_DIRECTION_RTL}.
      *
-     * Be careful: this code will need to be changed when vertical scripts will be supported
-     *
-     * @hide
+     * Be careful: this code will need to be updated when vertical scripts will be supported
      */
     public static int getLayoutDirectionFromLocale(Locale locale) {
         if (locale != null && !locale.equals(Locale.ROOT)) {
@@ -69,7 +66,7 @@
      * {@link View#LAYOUT_DIRECTION_LTR} or
      * {@link View#LAYOUT_DIRECTION_RTL}.
      *
-     * Be careful: this code will need to be changed when vertical scripts will be supported
+     * Be careful: this code will need to be updated when vertical scripts will be supported
      *
      * @hide
      */
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index f60c8f0..a50f09f 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -70,4 +70,204 @@
      * @return The size of this display list in bytes
      */
     public abstract int getSize();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // DisplayList Property Setters
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Set the caching property on the DisplayList, which indicates whether the DisplayList
+     * holds a layer. Layer DisplayLists should avoid creating an alpha layer, since alpha is
+     * handled in the drawLayer operation directly (and more efficiently).
+     *
+     * @param caching true if the DisplayList represents a hardware layer, false otherwise.
+     */
+    public abstract void setCaching(boolean caching);
+
+    /**
+     * Set whether the DisplayList should clip itself to its bounds. This property is controlled by
+     * the view's parent.
+     *
+     * @param clipChildren true if the DisplayList should clip to its bounds
+     */
+    public abstract void setClipChildren(boolean clipChildren);
+
+    /**
+     * Set the application scale on the DisplayList. This scale is incurred by applications that
+     * are auto-scaled for compatibility reasons. By default, the value is 1 (unscaled).
+     *
+     * @param scale The scaling factor
+     */
+    public abstract void setApplicationScale(float scale);
+
+    /**
+     * Sets the alpha value for the DisplayList
+     *
+     * @param alpha The translucency of the DisplayList
+     * @see View#setAlpha(float)
+     */
+    public abstract void setAlpha(float alpha);
+
+    /**
+     * Sets the translationX value for the DisplayList
+     *
+     * @param translationX The translationX value of the DisplayList
+     * @see View#setTranslationX(float)
+     */
+    public abstract void setTranslationX(float translationX);
+
+    /**
+     * Sets the translationY value for the DisplayList
+     *
+     * @param translationY The translationY value of the DisplayList
+     * @see View#setTranslationY(float)
+     */
+    public abstract void setTranslationY(float translationY);
+
+    /**
+     * Sets the rotation value for the DisplayList
+     *
+     * @param rotation The rotation value of the DisplayList
+     * @see View#setRotation(float)
+     */
+    public abstract void setRotation(float rotation);
+
+    /**
+     * Sets the rotationX value for the DisplayList
+     *
+     * @param rotationX The rotationX value of the DisplayList
+     * @see View#setRotationX(float)
+     */
+    public abstract void setRotationX(float rotationX);
+
+    /**
+     * Sets the rotationY value for the DisplayList
+     *
+     * @param rotationY The rotationY value of the DisplayList
+     * @see View#setRotationY(float)
+     */
+    public abstract void setRotationY(float rotationY);
+
+    /**
+     * Sets the scaleX value for the DisplayList
+     *
+     * @param scaleX The scaleX value of the DisplayList
+     * @see View#setScaleX(float)
+     */
+    public abstract void setScaleX(float scaleX);
+
+    /**
+     * Sets the scaleY value for the DisplayList
+     *
+     * @param scaleY The scaleY value of the DisplayList
+     * @see View#setScaleY(float)
+     */
+    public abstract void setScaleY(float scaleY);
+
+    /**
+     * Sets all of the transform-related values of the View onto the DisplayList
+     *
+     * @param alpha The alpha value of the DisplayList
+     * @param translationX The translationX value of the DisplayList
+     * @param translationY The translationY value of the DisplayList
+     * @param rotation The rotation value of the DisplayList
+     * @param rotationX The rotationX value of the DisplayList
+     * @param rotationY The rotationY value of the DisplayList
+     * @param scaleX The scaleX value of the DisplayList
+     * @param scaleY The scaleY value of the DisplayList
+     */
+    public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
+            float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
+
+    /**
+     * Sets the pivotX value for the DisplayList
+     *
+     * @param pivotX The pivotX value of the DisplayList
+     * @see View#setPivotX(float)
+     */
+    public abstract void setPivotX(float pivotX);
+
+    /**
+     * Sets the pivotY value for the DisplayList
+     *
+     * @param pivotY The pivotY value of the DisplayList
+     * @see View#setPivotY(float)
+     */
+    public abstract void setPivotY(float pivotY);
+
+    /**
+     * Sets the camera distance for the DisplayList
+     *
+     * @param distance The distance in z of the camera of the DisplayList
+     * @see View#setCameraDistance(float)
+     */
+    public abstract void setCameraDistance(float distance);
+
+    /**
+     * Sets the left value for the DisplayList
+     *
+     * @param left The left value of the DisplayList
+     * @see View#setLeft(int)
+     */
+    public abstract void setLeft(int left);
+
+    /**
+     * Sets the top value for the DisplayList
+     *
+     * @param top The top value of the DisplayList
+     * @see View#setTop(int)
+     */
+    public abstract void setTop(int top);
+
+    /**
+     * Sets the right value for the DisplayList
+     *
+     * @param right The right value of the DisplayList
+     * @see View#setRight(int)
+     */
+    public abstract void setRight(int right);
+
+    /**
+     * Sets the bottom value for the DisplayList
+     *
+     * @param bottom The bottom value of the DisplayList
+     * @see View#setBottom(int)
+     */
+    public abstract void setBottom(int bottom);
+
+    /**
+     * Sets the left and top values for the DisplayList
+     *
+     * @param left The left value of the DisplayList
+     * @param top The top value of the DisplayList
+     * @see View#setLeft(int)
+     * @see View#setTop(int)
+     */
+    public abstract void setLeftTop(int left, int top);
+
+    /**
+     * Sets the left and top values for the DisplayList
+     *
+     * @param left The left value of the DisplayList
+     * @param top The top value of the DisplayList
+     * @see View#setLeft(int)
+     * @see View#setTop(int)
+     */
+    public abstract void setLeftTopRightBottom(int left, int top, int right, int bottom);
+
+    /**
+     * Offsets the left and right values for the DisplayList
+     *
+     * @param offset The amount that the left and right values of the DisplayList are offset
+     * @see View#offsetLeftAndRight(int)
+     */
+    public abstract void offsetLeftRight(int offset);
+
+    /**
+     * Offsets the top and bottom values for the DisplayList
+     *
+     * @param offset The amount that the top and bottom values of the DisplayList are offset
+     * @see View#offsetTopAndBottom(int)
+     */
+    public abstract void offsetTopBottom(int offset);
 }
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 969c9ab..9b4cf21 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -96,6 +96,251 @@
         return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
     }
 
+    ///////////////////////////////////////////////////////////////////////////
+    // Native View Properties
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void setCaching(boolean caching) {
+        try {
+            nSetCaching(getNativeDisplayList(), caching);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setClipChildren(boolean clipChildren) {
+        try {
+            nSetClipChildren(getNativeDisplayList(), clipChildren);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setApplicationScale(float scale) {
+        try {
+            nSetApplicationScale(getNativeDisplayList(), scale);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        try {
+            nSetAlpha(getNativeDisplayList(), alpha);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setTranslationX(float translationX) {
+        try {
+            nSetTranslationX(getNativeDisplayList(), translationX);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setTranslationY(float translationY) {
+        try {
+            nSetTranslationY(getNativeDisplayList(), translationY);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setRotation(float rotation) {
+        try {
+            nSetRotation(getNativeDisplayList(), rotation);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setRotationX(float rotationX) {
+        try {
+            nSetRotationX(getNativeDisplayList(), rotationX);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setRotationY(float rotationY) {
+        try {
+            nSetRotationY(getNativeDisplayList(), rotationY);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setScaleX(float scaleX) {
+        try {
+            nSetScaleX(getNativeDisplayList(), scaleX);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setScaleY(float scaleY) {
+        try {
+            nSetScaleY(getNativeDisplayList(), scaleY);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setTransformationInfo(float alpha, float translationX, float translationY,
+            float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
+        try {
+            nSetTransformationInfo(getNativeDisplayList(), alpha, translationX, translationY,
+                    rotation, rotationX, rotationY, scaleX, scaleY);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setPivotX(float pivotX) {
+        try {
+            nSetPivotX(getNativeDisplayList(), pivotX);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setPivotY(float pivotY) {
+        try {
+            nSetPivotY(getNativeDisplayList(), pivotY);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setCameraDistance(float distance) {
+        try {
+            nSetCameraDistance(getNativeDisplayList(), distance);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setLeft(int left) {
+        try {
+            nSetLeft(getNativeDisplayList(), left);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setTop(int top) {
+        try {
+            nSetTop(getNativeDisplayList(), top);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setRight(int right) {
+        try {
+            nSetRight(getNativeDisplayList(), right);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setBottom(int bottom) {
+        try {
+            nSetBottom(getNativeDisplayList(), bottom);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setLeftTop(int left, int top) {
+        try {
+            nSetLeftTop(getNativeDisplayList(), left, top);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+        try {
+            nSetLeftTopRightBottom(getNativeDisplayList(), left, top, right, bottom);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void offsetLeftRight(int offset) {
+        try {
+            nOffsetLeftRight(getNativeDisplayList(), offset);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    @Override
+    public void offsetTopBottom(int offset) {
+        try {
+            nOffsetTopBottom(getNativeDisplayList(), offset);
+        } catch (IllegalStateException e) {
+            // invalid DisplayList okay: we'll set current values the next time we render to it
+        }
+    }
+
+    private static native void nOffsetTopBottom(int displayList, int offset);
+    private static native void nOffsetLeftRight(int displayList, int offset);
+    private static native void nSetLeftTopRightBottom(int displayList, int left, int top,
+            int right, int bottom);
+    private static native void nSetLeftTop(int displayList, int left, int top);
+    private static native void nSetBottom(int displayList, int bottom);
+    private static native void nSetRight(int displayList, int right);
+    private static native void nSetTop(int displayList, int top);
+    private static native void nSetLeft(int displayList, int left);
+    private static native void nSetCameraDistance(int displayList, float distance);
+    private static native void nSetPivotY(int displayList, float pivotY);
+    private static native void nSetPivotX(int displayList, float pivotX);
+    private static native void nSetCaching(int displayList, boolean caching);
+    private static native void nSetClipChildren(int displayList, boolean clipChildren);
+    private static native void nSetApplicationScale(int displayList, float scale);
+    private static native void nSetAlpha(int displayList, float alpha);
+    private static native void nSetTranslationX(int displayList, float translationX);
+    private static native void nSetTranslationY(int displayList, float translationY);
+    private static native void nSetRotation(int displayList, float rotation);
+    private static native void nSetRotationX(int displayList, float rotationX);
+    private static native void nSetRotationY(int displayList, float rotationY);
+    private static native void nSetScaleX(int displayList, float scaleX);
+    private static native void nSetScaleY(int displayList, float scaleY);
+    private static native void nSetTransformationInfo(int displayList, float alpha,
+            float translationX, float translationY, float rotation, float rotationX,
+            float rotationY, float scaleX, float scaleY);
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Finalization
+    ///////////////////////////////////////////////////////////////////////////
+
     private static class DisplayListFinalizer {
         final int mNativeDisplayList;
 
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a97167b..e73f7bf 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -36,6 +36,7 @@
     
     int mWidth;
     int mHeight;
+    DisplayList mDisplayList;
 
     boolean mOpaque;
 
@@ -79,6 +80,24 @@
     }
 
     /**
+     * Returns the DisplayList for the layer.
+     *
+     * @return The DisplayList of the hardware layer
+     */
+    DisplayList getDisplayList() {
+        return mDisplayList;
+    }
+
+    /**
+     * Sets the DisplayList for the layer.
+     *
+     * @param displayList The new DisplayList for this layer
+     */
+    void setDisplayList(DisplayList displayList) {
+        mDisplayList = displayList;
+    }
+
+    /**
      * Returns whether or not this layer is opaque.
      * 
      * @return True if the layer is opaque, false otherwise
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 679a65a..bf48ff2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1498,6 +1498,14 @@
     static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
 
     /**
+     * Temporary flag, used to enable processing of View properties in the native DisplayList
+     * object instead of during draw(). Soon to be enabled by default for hardware-accelerated
+     * apps.
+     * @hide
+     */
+    protected static final boolean USE_DISPLAY_LIST_PROPERTIES = false;
+
+    /**
      * Map used to store views' tags.
      */
     private SparseArray<Object> mKeyedTags;
@@ -7284,6 +7292,24 @@
     }
 
     /**
+     * Gets the distance along the Z axis from the camera to this view.
+     *
+     * @see #setCameraDistance(float)
+     *
+     * @return The distance along the Z axis.
+     */
+    public float getCameraDistance() {
+        ensureTransformationInfo();
+        final float dpi = mResources.getDisplayMetrics().densityDpi;
+        final TransformationInfo info = mTransformationInfo;
+        if (info.mCamera == null) {
+            info.mCamera = new Camera();
+            info.matrix3D = new Matrix();
+        }
+        return -(info.mCamera.getLocationZ() * dpi);
+    }
+
+    /**
      * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
      * views are drawn) from the camera to this view. The camera's distance
      * affects 3D transformations, for instance rotations around the X and Y
@@ -7338,6 +7364,9 @@
         info.mMatrixDirty = true;
 
         invalidate(false);
+        if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+            mDisplayList.setCameraDistance(distance);
+        }
     }
 
     /**
@@ -7379,6 +7408,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setRotation(rotation);
+            }
         }
     }
 
@@ -7426,6 +7458,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setRotationY(rotationY);
+            }
         }
     }
 
@@ -7473,6 +7508,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setRotationX(rotationX);
+            }
         }
     }
 
@@ -7512,6 +7550,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setScaleX(scaleX);
+            }
         }
     }
 
@@ -7551,6 +7592,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setScaleY(scaleY);
+            }
         }
     }
 
@@ -7596,6 +7640,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setPivotX(pivotX);
+            }
         }
     }
 
@@ -7640,6 +7687,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setPivotY(pivotY);
+            }
         }
     }
 
@@ -7686,6 +7736,9 @@
             } else {
                 mPrivateFlags &= ~ALPHA_SET;
                 invalidate(false);
+                if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                    mDisplayList.setAlpha(alpha);
+                }
             }
         }
     }
@@ -7710,6 +7763,9 @@
                 return true;
             } else {
                 mPrivateFlags &= ~ALPHA_SET;
+                if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                    mDisplayList.setAlpha(alpha);
+                }
             }
         }
         return false;
@@ -7759,6 +7815,9 @@
             int oldHeight = mBottom - mTop;
 
             mTop = top;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setTop(mTop);
+            }
 
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
@@ -7825,6 +7884,9 @@
             int oldHeight = mBottom - mTop;
 
             mBottom = bottom;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setBottom(mBottom);
+            }
 
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
@@ -7885,6 +7947,9 @@
             int height = mBottom - mTop;
 
             mLeft = left;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setLeft(left);
+            }
 
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
@@ -7898,6 +7963,9 @@
             }
             mBackgroundSizeChanged = true;
             invalidateParentIfNeeded();
+            if (USE_DISPLAY_LIST_PROPERTIES) {
+
+            }
         }
     }
 
@@ -7942,6 +8010,9 @@
             int height = mBottom - mTop;
 
             mRight = right;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setRight(mRight);
+            }
 
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
@@ -8038,6 +8109,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setTranslationX(translationX);
+            }
         }
     }
 
@@ -8075,6 +8149,9 @@
             info.mMatrixDirty = true;
             mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
             invalidate(false);
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setTranslationY(translationY);
+            }
         }
     }
 
@@ -8207,6 +8284,9 @@
 
             mTop += offset;
             mBottom += offset;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.offsetTopBottom(offset);
+            }
 
             if (!matrixIsIdentity) {
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
@@ -8248,6 +8328,9 @@
 
             mLeft += offset;
             mRight += offset;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.offsetLeftRight(offset);
+            }
 
             if (!matrixIsIdentity) {
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
@@ -10384,7 +10467,7 @@
                 return null;
             }
 
-            mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect);
+            mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
             mLocalDirtyRect.setEmpty();
         }
 
@@ -10536,6 +10619,129 @@
     }
 
     /**
+     * Returns a DisplayList. If the incoming displayList is null, one will be created.
+     * Otherwise, the same display list will be returned (after having been rendered into
+     * along the way, depending on the invalidation state of the view).
+     *
+     * @param displayList The previous version of this displayList, could be null.
+     * @param isLayer Whether the requester of the display list is a layer. If so,
+     * the view will avoid creating a layer inside the resulting display list.
+     * @return A new or reused DisplayList object.
+     */
+    private DisplayList getDisplayList(DisplayList displayList, boolean isLayer) {
+        if (!canHaveDisplayList()) {
+            return null;
+        }
+
+        if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
+                displayList == null || !displayList.isValid() ||
+                (!isLayer && mRecreateDisplayList))) {
+            // Don't need to recreate the display list, just need to tell our
+            // children to restore/recreate theirs
+            if (displayList != null && displayList.isValid() &&
+                    !isLayer && !mRecreateDisplayList) {
+                mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+                mPrivateFlags &= ~DIRTY_MASK;
+                dispatchGetDisplayList();
+
+                return displayList;
+            }
+
+            if (!isLayer) {
+                // If we got here, we're recreating it. Mark it as such to ensure that
+                // we copy in child display lists into ours in drawChild()
+                mRecreateDisplayList = true;
+            }
+            if (displayList == null) {
+                final String name = getClass().getSimpleName();
+                displayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
+                // If we're creating a new display list, make sure our parent gets invalidated
+                // since they will need to recreate their display list to account for this
+                // new child display list.
+                invalidateParentCaches();
+            }
+
+            boolean caching = false;
+            final HardwareCanvas canvas = displayList.start();
+            int restoreCount = 0;
+            int width = mRight - mLeft;
+            int height = mBottom - mTop;
+
+            try {
+                canvas.setViewport(width, height);
+                // The dirty rect should always be null for a display list
+                canvas.onPreDraw(null);
+                int layerType = (
+                        !(mParent instanceof ViewGroup) || ((ViewGroup)mParent).mDrawLayers) ?
+                        getLayerType() : LAYER_TYPE_NONE;
+                if (!isLayer && layerType == LAYER_TYPE_HARDWARE && USE_DISPLAY_LIST_PROPERTIES) {
+                    final HardwareLayer layer = getHardwareLayer();
+                    if (layer != null && layer.isValid()) {
+                        canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+                    } else {
+                        canvas.saveLayer(0, 0,
+                                mRight - mLeft, mBottom - mTop, mLayerPaint,
+                                Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+                    }
+                    caching = true;
+                } else {
+
+                    computeScroll();
+
+                    if (!USE_DISPLAY_LIST_PROPERTIES) {
+                        restoreCount = canvas.save();
+                    }
+                    canvas.translate(-mScrollX, -mScrollY);
+                    if (!isLayer) {
+                        mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+                        mPrivateFlags &= ~DIRTY_MASK;
+                    }
+
+                    // Fast path for layouts with no backgrounds
+                    if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+                        dispatchDraw(canvas);
+                    } else {
+                        draw(canvas);
+                    }
+                }
+            } finally {
+                if (USE_DISPLAY_LIST_PROPERTIES) {
+                    canvas.restoreToCount(restoreCount);
+                }
+                canvas.onPostDraw();
+
+                displayList.end();
+                if (USE_DISPLAY_LIST_PROPERTIES) {
+                    displayList.setCaching(caching);
+                }
+                if (isLayer && USE_DISPLAY_LIST_PROPERTIES) {
+                    displayList.setLeftTopRightBottom(0, 0, width, height);
+                } else {
+                    setDisplayListProperties(displayList);
+                }
+            }
+        } else if (!isLayer) {
+            mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+            mPrivateFlags &= ~DIRTY_MASK;
+        }
+
+        return displayList;
+    }
+
+    /**
+     * Get the DisplayList for the HardwareLayer
+     *
+     * @param layer The HardwareLayer whose DisplayList we want
+     * @return A DisplayList fopr the specified HardwareLayer
+     */
+    private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) {
+        DisplayList displayList = getDisplayList(layer.getDisplayList(), true);
+        layer.setDisplayList(displayList);
+        return displayList;
+    }
+
+
+    /**
      * <p>Returns a display list that can be used to draw this view again
      * without executing its draw method.</p>
      *
@@ -10544,70 +10750,7 @@
      * @hide
      */
     public DisplayList getDisplayList() {
-        if (!canHaveDisplayList()) {
-            return null;
-        }
-
-        if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
-                mDisplayList == null || !mDisplayList.isValid() ||
-                mRecreateDisplayList)) {
-            // Don't need to recreate the display list, just need to tell our
-            // children to restore/recreate theirs
-            if (mDisplayList != null && mDisplayList.isValid() &&
-                    !mRecreateDisplayList) {
-                mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-                mPrivateFlags &= ~DIRTY_MASK;
-                dispatchGetDisplayList();
-
-                return mDisplayList;
-            }
-
-            // If we got here, we're recreating it. Mark it as such to ensure that
-            // we copy in child display lists into ours in drawChild()
-            mRecreateDisplayList = true;
-            if (mDisplayList == null) {
-                final String name = getClass().getSimpleName();
-                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
-                // If we're creating a new display list, make sure our parent gets invalidated
-                // since they will need to recreate their display list to account for this
-                // new child display list.
-                invalidateParentCaches();
-            }
-
-            final HardwareCanvas canvas = mDisplayList.start();
-            int restoreCount = 0;
-            try {
-                int width = mRight - mLeft;
-                int height = mBottom - mTop;
-
-                canvas.setViewport(width, height);
-                // The dirty rect should always be null for a display list
-                canvas.onPreDraw(null);
-
-                computeScroll();
-
-                restoreCount = canvas.save();
-                canvas.translate(-mScrollX, -mScrollY);
-                mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-                mPrivateFlags &= ~DIRTY_MASK;
-
-                // Fast path for layouts with no backgrounds
-                if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                    dispatchDraw(canvas);
-                } else {
-                    draw(canvas);
-                }
-            } finally {
-                canvas.restoreToCount(restoreCount);
-                canvas.onPostDraw();
-
-                mDisplayList.end();
-            }
-        } else {
-            mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-            mPrivateFlags &= ~DIRTY_MASK;
-        }
-
+        mDisplayList = getDisplayList(mDisplayList, false);
         return mDisplayList;
     }
 
@@ -11152,19 +11295,57 @@
         return more;
     }
 
+    void setDisplayListProperties() {
+        setDisplayListProperties(mDisplayList);
+    }
+
+    /**
+     * This method is called by getDisplayList() when a display list is created or re-rendered.
+     * It sets or resets the current value of all properties on that display list (resetting is
+     * necessary when a display list is being re-created, because we need to make sure that
+     * previously-set transform values
+     */
+    void setDisplayListProperties(DisplayList displayList) {
+        if (USE_DISPLAY_LIST_PROPERTIES && displayList != null) {
+            displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+            if (mParent instanceof ViewGroup) {
+                displayList.setClipChildren(
+                        (((ViewGroup)mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
+            }
+            if (mAttachInfo != null && mAttachInfo.mScalingRequired &&
+                    mAttachInfo.mApplicationScale != 1.0f) {
+                displayList.setApplicationScale(1f / mAttachInfo.mApplicationScale);
+            }
+            if (mTransformationInfo != null) {
+                displayList.setTransformationInfo(mTransformationInfo.mAlpha,
+                        mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
+                        mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
+                        mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
+                        mTransformationInfo.mScaleY);
+                displayList.setCameraDistance(getCameraDistance());
+                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == PIVOT_EXPLICITLY_SET) {
+                    displayList.setPivotX(getPivotX());
+                    displayList.setPivotY(getPivotY());
+                }
+            }
+        }
+    }
+
     /**
      * This method is called by ViewGroup.drawChild() to have each child view draw itself.
      * This draw() method is an implementation detail and is not intended to be overridden or
      * to be called from anywhere else other than ViewGroup.drawChild().
      */
     boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
+        boolean useDisplayListProperties = USE_DISPLAY_LIST_PROPERTIES && mAttachInfo != null &&
+                mAttachInfo.mHardwareAccelerated;
         boolean more = false;
         final boolean childHasIdentityMatrix = hasIdentityMatrix();
         final int flags = parent.mGroupFlags;
 
-        if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
+        if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) {
             parent.mChildTransformation.clear();
-            parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
+            parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
         }
 
         Transformation transformToApply = null;
@@ -11175,8 +11356,8 @@
         int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
 
         final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
-        if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
-                (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
+        if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
+                (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
             caching = true;
             if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
         } else {
@@ -11188,8 +11369,7 @@
             more = drawAnimation(parent, drawingTime, a, scalingRequired);
             concatMatrix = a.willChangeTransformationMatrix();
             transformToApply = parent.mChildTransformation;
-        } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
-                parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+        } else if ((flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
             final boolean hasTransform =
                     parent.getChildStaticTransformation(this, parent.mChildTransformation);
             if (hasTransform) {
@@ -11239,6 +11419,11 @@
                         buildDrawingCache(true);
                         cache = getDrawingCache(true);
                         break;
+                    case LAYER_TYPE_HARDWARE:
+                        if (useDisplayListProperties) {
+                            hasDisplayList = canHaveDisplayList();
+                        }
+                        break;
                     case LAYER_TYPE_NONE:
                         // Delay getting the display list until animation-driven alpha values are
                         // set up and possibly passed on to the view
@@ -11247,24 +11432,33 @@
                 }
             }
         }
+        useDisplayListProperties &= hasDisplayList;
 
         final boolean hasNoCache = cache == null || hasDisplayList;
         final boolean offsetForScroll = cache == null && !hasDisplayList &&
                 layerType != LAYER_TYPE_HARDWARE;
 
-        final int restoreTo = canvas.save();
+        int restoreTo = -1;
+        if (!useDisplayListProperties) {
+            restoreTo = canvas.save();
+        }
         if (offsetForScroll) {
             canvas.translate(mLeft - sx, mTop - sy);
         } else {
-            canvas.translate(mLeft, mTop);
+            if (!useDisplayListProperties) {
+                canvas.translate(mLeft, mTop);
+            }
             if (scalingRequired) {
+                if (useDisplayListProperties) {
+                    restoreTo = canvas.save();
+                }
                 // mAttachInfo cannot be null, otherwise scalingRequired == false
                 final float scale = 1.0f / mAttachInfo.mApplicationScale;
                 canvas.scale(scale, scale);
             }
         }
 
-        float alpha = getAlpha();
+        float alpha = useDisplayListProperties ? 1 : getAlpha();
         if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -11279,20 +11473,22 @@
                     if (concatMatrix) {
                         // Undo the scroll translation, apply the transformation matrix,
                         // then redo the scroll translate to get the correct result.
-                        canvas.translate(-transX, -transY);
-                        canvas.concat(transformToApply.getMatrix());
-                        canvas.translate(transX, transY);
-                        parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                        if (!hasDisplayList) {
+                            canvas.translate(-transX, -transY);
+                            canvas.concat(transformToApply.getMatrix());
+                            canvas.translate(transX, transY);
+                        }
+                        parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                     }
 
                     float transformAlpha = transformToApply.getAlpha();
                     if (transformAlpha < 1.0f) {
                         alpha *= transformToApply.getAlpha();
-                        parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                        parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                     }
                 }
 
-                if (!childHasIdentityMatrix) {
+                if (!childHasIdentityMatrix && !useDisplayListProperties) {
                     canvas.translate(-transX, -transY);
                     canvas.concat(getMatrix());
                     canvas.translate(transX, transY);
@@ -11300,20 +11496,22 @@
             }
 
             if (alpha < 1.0f) {
-                parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                 if (hasNoCache) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (!onSetAlpha(multipliedAlpha)) {
                         int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-                        if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
+                        if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 ||
                                 layerType != LAYER_TYPE_NONE) {
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (layerType == LAYER_TYPE_NONE) {
-                            final int scrollX = hasDisplayList ? 0 : sx;
-                            final int scrollY = hasDisplayList ? 0 : sy;
-                            canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
-                                    scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+                            if (!useDisplayListProperties) {
+                                final int scrollX = hasDisplayList ? 0 : sx;
+                                final int scrollY = hasDisplayList ? 0 : sy;
+                                canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+                                        scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+                            }
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
@@ -11326,7 +11524,8 @@
             mPrivateFlags &= ~ALPHA_SET;
         }
 
-        if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
+        if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN &&
+                !useDisplayListProperties) {
             if (offsetForScroll) {
                 canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
             } else {
@@ -11351,7 +11550,7 @@
 
         if (hasNoCache) {
             boolean layerRendered = false;
-            if (layerType == LAYER_TYPE_HARDWARE) {
+            if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) {
                 final HardwareLayer layer = getHardwareLayer();
                 if (layer != null && layer.isValid()) {
                     mLayerPaint.setAlpha((int) (alpha * 255));
@@ -11397,11 +11596,10 @@
                 }
                 if (alpha < 1.0f) {
                     cachePaint.setAlpha((int) (alpha * 255));
-                    parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
-                } else if  ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
-                        parent.FLAG_ALPHA_LOWER_THAN_ONE) {
+                    parent.mGroupFlags |= ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
+                } else if  ((flags & ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE) != 0) {
                     cachePaint.setAlpha(255);
-                    parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
+                    parent.mGroupFlags &= ~ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
                 }
             } else {
                 cachePaint = mLayerPaint;
@@ -11410,7 +11608,9 @@
             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
         }
 
-        canvas.restoreToCount(restoreTo);
+        if (restoreTo >= 0) {
+            canvas.restoreToCount(restoreTo);
+        }
 
         if (a != null && !more) {
             if (!hardwareAccelerated && !a.getFillAfter()) {
@@ -11868,6 +12068,9 @@
             mTop = top;
             mRight = right;
             mBottom = bottom;
+            if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+                mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+            }
 
             mPrivateFlags |= HAS_BOUNDS;
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c9e0242..1993ce6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2736,7 +2736,18 @@
      * @attr ref android.R.styleable#ViewGroup_clipChildren
      */
     public void setClipChildren(boolean clipChildren) {
-        setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
+        boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
+        if (clipChildren != previousValue) {
+            setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
+            if (USE_DISPLAY_LIST_PROPERTIES) {
+                for (int i = 0; i < mChildrenCount; ++i) {
+                    View child = getChildAt(i);
+                    if (child.mDisplayList != null) {
+                        child.mDisplayList.setClipChildren(clipChildren);
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -3973,6 +3984,9 @@
             final View v = children[i];
             v.mTop += offset;
             v.mBottom += offset;
+            if (USE_DISPLAY_LIST_PROPERTIES && v.mDisplayList != null) {
+                v.mDisplayList.offsetTopBottom(offset);
+            }
         }
     }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 0fdcd0f..fe0e659 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -866,6 +866,8 @@
                 info.mAlpha = value;
                 break;
         }
+        // TODO: optimize to set only the properties that have changed
+        mView.setDisplayListProperties();
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b8db848..e535170 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11703,8 +11703,10 @@
                     firstLine, lastLine);
 
             if (mTextDisplayList == null || !mTextDisplayList.isValid()) {
+                boolean displayListCreated = false;
                 if (mTextDisplayList == null) {
                     mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
+                    displayListCreated = true;
                 }
 
                 final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -11719,6 +11721,9 @@
                 } finally {
                     hardwareCanvas.onPostDraw();
                     mTextDisplayList.end();
+                    if (displayListCreated && USE_DISPLAY_LIST_PROPERTIES) {
+                        mTextDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+                    }
                 }
             }
             canvas.translate(mScrollX, mScrollY);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 543e32d..92b07b3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -53,6 +53,7 @@
 	android_view_KeyEvent.cpp \
 	android_view_KeyCharacterMap.cpp \
 	android_view_HardwareRenderer.cpp \
+	android_view_GLES20DisplayList.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_MotionEvent.cpp \
 	android_view_PointerIcon.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a512679..92ff8da 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -117,6 +117,7 @@
 extern int register_android_graphics_PixelFormat(JNIEnv* env);
 extern int register_android_view_Display(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_GLES20DisplayList(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_HardwareRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
@@ -1102,6 +1103,7 @@
     REG_JNI(register_android_nio_utils),
     REG_JNI(register_android_graphics_PixelFormat),
     REG_JNI(register_android_graphics_Graphics),
+    REG_JNI(register_android_view_GLES20DisplayList),
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_HardwareRenderer),
     REG_JNI(register_android_view_Surface),
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 76d415a..5176d9a 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -57,6 +57,21 @@
     v->setCameraLocation(SkFloatToScalar(x), SkFloatToScalar(y), SkFloatToScalar(z));
 }
 
+static jfloat Camera_getLocationX(JNIEnv* env, jobject obj) {
+    Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+    return SkScalarToFloat(v->getCameraLocationX());
+}
+
+static jfloat Camera_getLocationY(JNIEnv* env, jobject obj) {
+    Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+    return SkScalarToFloat(v->getCameraLocationY());
+}
+
+static jfloat Camera_getLocationZ(JNIEnv* env, jobject obj) {
+    Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+    return SkScalarToFloat(v->getCameraLocationZ());
+}
+
 static void Camera_getMatrix(JNIEnv* env, jobject obj, int native_matrix) {
     Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
     v->getMatrix((SkMatrix*)native_matrix);
@@ -93,6 +108,9 @@
     { "rotateZ",             "(F)V",   (void*)Camera_rotateZ       },
     { "rotate",              "(FFF)V", (void*)Camera_rotate        },
     { "setLocation",         "(FFF)V", (void*)Camera_setLocation   },
+    { "getLocationX",        "()F",    (void*)Camera_getLocationX  },
+    { "getLocationY",        "()F",    (void*)Camera_getLocationY  },
+    { "getLocationZ",        "()F",    (void*)Camera_getLocationZ  },
     { "nativeGetMatrix",     "(I)V",   (void*)Camera_getMatrix     },
     { "nativeApplyToCanvas", "(I)V",   (void*)Camera_applyToCanvas },
     { "dotWithNormal",       "(FFF)F", (void*)Camera_dotWithNormal }
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 929df540..634efa6 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -556,6 +556,12 @@
     nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
 }
 
+extern void setGLDebugLevel(int level);
+void nativeEnableTracing(JNIEnv *env, jclass clazz)
+{
+    setGLDebugLevel(1);
+}
+
 static int checkFormat(SkBitmap::Config config, int format, int type)
 {
     switch(config) {
@@ -1026,6 +1032,7 @@
     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
     { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+    { "native_enableTracing", "()V",                    (void*)nativeEnableTracing },
 };
 
 static JNINativeMethod gEtc1Methods[] = {
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
new file mode 100644
index 0000000..407c196
--- /dev/null
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <EGL/egl.h>
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <DisplayListRenderer.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+/**
+ * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
+ *       devices. This means all the logic must be compiled only when the
+ *       preprocessor variable USE_OPENGL_RENDERER is defined.
+ */
+#ifdef USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// DisplayList view properties
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20DisplayList_setCaching(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, jboolean caching) {
+    displayList->setCaching(caching);
+}
+
+static void android_view_GLES20DisplayList_setApplicationScale(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float scale) {
+    displayList->setApplicationScale(scale);
+}
+
+static void android_view_GLES20DisplayList_setClipChildren(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, jboolean clipChildren) {
+    displayList->setClipChildren(clipChildren);
+}
+
+static void android_view_GLES20DisplayList_setAlpha(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float alpha) {
+    displayList->setAlpha(alpha);
+}
+
+static void android_view_GLES20DisplayList_setTranslationX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float tx) {
+    displayList->setTranslationX(tx);
+}
+
+static void android_view_GLES20DisplayList_setTranslationY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float ty) {
+    displayList->setTranslationY(ty);
+}
+
+static void android_view_GLES20DisplayList_setRotation(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float rotation) {
+    displayList->setRotation(rotation);
+}
+
+static void android_view_GLES20DisplayList_setRotationX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float rx) {
+    displayList->setRotationX(rx);
+}
+
+static void android_view_GLES20DisplayList_setRotationY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float ry) {
+    displayList->setRotationY(ry);
+}
+
+static void android_view_GLES20DisplayList_setScaleX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float sx) {
+    displayList->setScaleX(sx);
+}
+
+static void android_view_GLES20DisplayList_setScaleY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float sy) {
+    displayList->setScaleY(sy);
+}
+
+static void android_view_GLES20DisplayList_setTransformationInfo(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float alpha,
+        float translationX, float translationY, float rotation, float rotationX, float rotationY,
+        float scaleX, float scaleY) {
+    displayList->setAlpha(alpha);
+    displayList->setTranslationX(translationX);
+    displayList->setTranslationY(translationY);
+    displayList->setRotation(rotation);
+    displayList->setRotationX(rotationX);
+    displayList->setRotationY(rotationY);
+    displayList->setScaleX(scaleX);
+    displayList->setScaleY(scaleY);
+}
+
+static void android_view_GLES20DisplayList_setPivotX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float px) {
+    displayList->setPivotX(px);
+}
+
+static void android_view_GLES20DisplayList_setPivotY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float py) {
+    displayList->setPivotY(py);
+}
+
+static void android_view_GLES20DisplayList_setCameraDistance(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float distance) {
+    displayList->setCameraDistance(distance);
+}
+
+static void android_view_GLES20DisplayList_setLeft(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int left) {
+    displayList->setLeft(left);
+}
+
+static void android_view_GLES20DisplayList_setTop(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int top) {
+    displayList->setTop(top);
+}
+
+static void android_view_GLES20DisplayList_setRight(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int right) {
+    displayList->setRight(right);
+}
+
+static void android_view_GLES20DisplayList_setBottom(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int bottom) {
+    displayList->setBottom(bottom);
+}
+
+static void android_view_GLES20DisplayList_setLeftTop(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int left, int top) {
+    displayList->setLeftTop(left, top);
+}
+
+static void android_view_GLES20DisplayList_setLeftTopRightBottom(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int left, int top,
+        int right, int bottom) {
+    displayList->setLeftTopRightBottom(left, top, right, bottom);
+}
+
+static void android_view_GLES20DisplayList_offsetLeftRight(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int offset) {
+    displayList->offsetLeftRight(offset);
+}
+
+static void android_view_GLES20DisplayList_offsetTopBottom(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, int offset) {
+    displayList->offsetTopBottom(offset);
+}
+
+#endif // USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/GLES20DisplayList";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+    { "nSetCaching",             "(IZ)V",       (void*) android_view_GLES20DisplayList_setCaching },
+    { "nSetApplicationScale",    "(IF)V",
+            (void*) android_view_GLES20DisplayList_setApplicationScale },
+    { "nSetClipChildren",        "(IZ)V",      (void*) android_view_GLES20DisplayList_setClipChildren },
+    { "nSetAlpha",               "(IF)V",      (void*) android_view_GLES20DisplayList_setAlpha },
+    { "nSetTranslationX",        "(IF)V",      (void*) android_view_GLES20DisplayList_setTranslationX },
+    { "nSetTranslationY",        "(IF)V",      (void*) android_view_GLES20DisplayList_setTranslationY },
+    { "nSetRotation",            "(IF)V",      (void*) android_view_GLES20DisplayList_setRotation },
+    { "nSetRotationX",           "(IF)V",      (void*) android_view_GLES20DisplayList_setRotationX },
+    { "nSetRotationY",           "(IF)V",      (void*) android_view_GLES20DisplayList_setRotationY },
+    { "nSetScaleX",              "(IF)V",      (void*) android_view_GLES20DisplayList_setScaleX },
+    { "nSetScaleY",              "(IF)V",      (void*) android_view_GLES20DisplayList_setScaleY },
+    { "nSetTransformationInfo",  "(IFFFFFFFF)V",
+            (void*) android_view_GLES20DisplayList_setTransformationInfo },
+    { "nSetPivotX",              "(IF)V",      (void*) android_view_GLES20DisplayList_setPivotX },
+    { "nSetPivotY",              "(IF)V",      (void*) android_view_GLES20DisplayList_setPivotY },
+    { "nSetCameraDistance",      "(IF)V",
+            (void*) android_view_GLES20DisplayList_setCameraDistance },
+    { "nSetLeft",                "(II)V",      (void*) android_view_GLES20DisplayList_setLeft },
+    { "nSetTop",                 "(II)V",      (void*) android_view_GLES20DisplayList_setTop },
+    { "nSetRight",               "(II)V",      (void*) android_view_GLES20DisplayList_setRight },
+    { "nSetBottom",              "(II)V",      (void*) android_view_GLES20DisplayList_setBottom },
+    { "nSetLeftTop",             "(III)V",     (void*) android_view_GLES20DisplayList_setLeftTop },
+    { "nSetLeftTopRightBottom",  "(IIIII)V",
+            (void*) android_view_GLES20DisplayList_setLeftTopRightBottom },
+    { "nOffsetLeftRight",        "(II)V",      (void*) android_view_GLES20DisplayList_offsetLeftRight },
+    { "nOffsetTopBottom",        "(II)V",      (void*) android_view_GLES20DisplayList_offsetTopBottom },
+
+#endif
+};
+
+#ifdef USE_OPENGL_RENDERER
+    #define FIND_CLASS(var, className) \
+            var = env->FindClass(className); \
+            LOG_FATAL_IF(! var, "Unable to find class " className);
+
+    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+            var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+            LOG_FATAL_IF(! var, "Unable to find method " methodName);
+#else
+    #define FIND_CLASS(var, className)
+    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor)
+#endif
+
+int register_android_view_GLES20DisplayList(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
+
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index f46546f..649ec3e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -97,6 +97,11 @@
         mOutputWriter = new BufferedWriter(new FileWriter(new File(
                 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
         mAct.turnScreenOn();
+        if (mAct.mWifiManager.isWifiApEnabled()) {
+            // if soft AP is enabled, disable it
+            assertTrue(mAct.mWifiManager.setWifiApEnabled(null, false));
+            Log.v(TAG, "disable soft ap");
+        }
         if (!mAct.mWifiManager.isWifiEnabled()) {
             log("Enable wi-fi before stress tests.");
             if (!mAct.enableWifi()) {
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index 7ef35a9..6f71a2b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -100,6 +100,27 @@
     public native void rotate(float x, float y, float z);
 
     /**
+     * Gets the x location of the camera.
+     *
+     * @see #setLocation(float, float, float)
+     */
+    public native float getLocationX();
+
+    /**
+     * Gets the y location of the camera.
+     *
+     * @see #setLocation(float, float, float)
+     */
+    public native float getLocationY();
+
+    /**
+     * Gets the z location of the camera.
+     *
+     * @see #setLocation(float, float, float)
+     */
+    public native float getLocationZ();
+
+    /**
      * Sets the location of the camera. The default location is set at
      * 0, 0, -8.
      * 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 18d0a70..24f4f1c 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -20,13 +20,11 @@
 #include "DisplayListLogBuffer.h"
 #include "DisplayListRenderer.h"
 #include "Caches.h"
-
-#include <utils/String8.h>
+#include "SkCamera.h"
 
 namespace android {
 namespace uirenderer {
 
-
 ///////////////////////////////////////////////////////////////////////////////
 // Display list
 ///////////////////////////////////////////////////////////////////////////////
@@ -101,6 +99,37 @@
     clearResources();
 }
 
+void DisplayList::initProperties() {
+    mLeft = 0;
+    mTop = 0;
+    mTop = 0;
+    mBottom = 0;
+    mApplicationScale = -1;
+    mClipChildren = true;
+    mAlpha = 1;
+    mMultipliedAlpha = 255;
+    mTranslationX = 0;
+    mTranslationY = 0;
+    mRotation = 0;
+    mRotationX = 0;
+    mRotationY= 0;
+    mScaleX = 1;
+    mScaleY = 1;
+    mPivotX = 0;
+    mPivotY = 0;
+    mMatrixDirty = false;
+    mMatrixFlags = 0;
+    mPrevWidth = -1;
+    mPrevHeight = -1;
+    mWidth = 0;
+    mHeight = 0;
+    mPivotExplicitlySet = false;
+    mTransformMatrix = NULL;
+    mTransformCamera = NULL;
+    mTransformMatrix3D = NULL;
+    mCaching = false;
+}
+
 void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
     if (displayList) {
         DISPLAY_LIST_LOGD("Deferring display list destruction");
@@ -111,6 +140,19 @@
 void DisplayList::clearResources() {
     sk_free((void*) mReader.base());
 
+    if (mTransformMatrix) {
+        delete mTransformMatrix;
+        mTransformMatrix = NULL;
+    }
+    if (mTransformCamera) {
+        delete mTransformCamera;
+        mTransformCamera = NULL;
+    }
+    if (mTransformMatrix3D) {
+        delete mTransformMatrix3D;
+        mTransformMatrix3D = NULL;
+    }
+
     Caches& caches = Caches::getInstance();
 
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
@@ -159,6 +201,7 @@
         // re-using display list - clear out previous allocations
         clearResources();
     }
+    initProperties();
 
     mSize = writer.size();
     void* buffer = sk_malloc_throw(mSize);
@@ -230,6 +273,7 @@
 
     int saveCount = renderer.getSaveCount() - 1;
 
+    outputViewProperties(renderer, (char*) indent);
     mReader.rewind();
 
     while (!mReader.eof()) {
@@ -238,7 +282,7 @@
             int skip = mReader.readInt();
             ALOGD("%sSkip %d", (char*) indent, skip);
             op &= ~OP_MAY_BE_SKIPPED_MASK;
-       }
+        }
 
         switch (op) {
             case DrawGLFunction: {
@@ -268,7 +312,7 @@
                 SkPaint* paint = getPaint(renderer);
                 int flags = getInt();
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                    OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
             }
             break;
             case SaveLayerAlpha: {
@@ -279,7 +323,7 @@
                 int alpha = getInt();
                 int flags = getInt();
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                    OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
             }
             break;
             case Translate: {
@@ -312,7 +356,10 @@
             break;
             case ConcatMatrix: {
                 SkMatrix* matrix = getMatrix();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+                ALOGD("%s%s new concat %p: [%f, %f, %f]   [%f, %f, %f]   [%f, %f, %f]",
+                        (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1),
+                        matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5),
+                        matrix->get(6), matrix->get(7), matrix->get(8));
             }
             break;
             case ClipRect: {
@@ -322,7 +369,7 @@
                 float f4 = getFloat();
                 int regionOp = getInt();
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                    f1, f2, f3, f4, regionOp);
+                        f1, f2, f3, f4, regionOp);
             }
             break;
             case DrawDisplayList: {
@@ -331,7 +378,7 @@
                 uint32_t height = getUInt();
                 int32_t flags = getInt();
                 ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                    displayList, width, height, flags, level + 1);
+                        displayList, width, height, flags, level + 1);
                 renderer.outputDisplayList(displayList, level + 1);
             }
             break;
@@ -341,7 +388,7 @@
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    layer, x, y, paint);
+                        layer, x, y, paint);
             }
             break;
             case DrawBitmap: {
@@ -350,7 +397,7 @@
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    bitmap, x, y, paint);
+                        bitmap, x, y, paint);
             }
             break;
             case DrawBitmapMatrix: {
@@ -358,7 +405,7 @@
                 SkMatrix* matrix = getMatrix();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                    bitmap, matrix, paint);
+                        bitmap, matrix, paint);
             }
             break;
             case DrawBitmapRect: {
@@ -373,7 +420,7 @@
                 float f8 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+                        (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
             }
             break;
             case DrawBitmapMesh: {
@@ -422,7 +469,7 @@
                 float f4 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    f1, f2, f3, f4, paint);
+                        f1, f2, f3, f4, paint);
             }
             break;
             case DrawRoundRect: {
@@ -434,7 +481,7 @@
                 float f6 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
             }
             break;
             case DrawCircle: {
@@ -443,7 +490,7 @@
                 float f3 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
             }
             break;
             case DrawOval: {
@@ -453,7 +500,7 @@
                 float f4 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
             }
             break;
             case DrawArc: {
@@ -466,7 +513,7 @@
                 int i1 = getInt();
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
             }
             break;
             case DrawPath: {
@@ -497,7 +544,7 @@
                 SkPaint* paint = getPaint(renderer);
                 float length = getFloat();
                 ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, x, y, paint, length);
+                        text.text(), text.length(), count, x, y, paint, length);
             }
             break;
             case DrawTextOnPath: {
@@ -518,7 +565,7 @@
                 float* positions = getFloats(positionsCount);
                 SkPaint* paint = getPaint(renderer);
                 ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, paint);
+                        text.text(), text.length(), count, paint);
             }
             case ResetShader: {
                 ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -548,7 +595,7 @@
                 float dy = getFloat();
                 int color = getInt();
                 ALOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                    radius, dx, dy, color);
+                        radius, dx, dy, color);
             }
             break;
             case ResetPaintFilter: {
@@ -563,20 +610,193 @@
             break;
             default:
                 ALOGD("Display List error: op not handled: %s%s",
-                    (char*) indent, OP_NAMES[op]);
+                        (char*) indent, OP_NAMES[op]);
                 break;
         }
     }
-
-    ALOGD("%sDone", (char*) indent + 2);
+    ALOGD("%sDone (%p, %s)", (char*) indent + 2, this, mName.string());
 }
 
+void DisplayList::updateMatrix() {
+    if (mMatrixDirty) {
+        if (!mTransformMatrix) {
+            mTransformMatrix = new SkMatrix();
+        }
+        if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
+            mTransformMatrix->reset();
+        } else {
+            if (!mPivotExplicitlySet) {
+                if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
+                    mPrevWidth = mWidth;
+                    mPrevHeight = mHeight;
+                    mPivotX = mPrevWidth / 2;
+                    mPivotY = mPrevHeight / 2;
+                }
+            }
+            if ((mMatrixFlags & ROTATION_3D) == 0) {
+                mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
+                mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
+                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+            } else {
+                if (!mTransformCamera) {
+                    mTransformCamera = new Sk3DView();
+                    mTransformMatrix3D = new SkMatrix();
+                }
+                mTransformMatrix->reset();
+                mTransformCamera->save();
+                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+                mTransformCamera->rotateX(mRotationX);
+                mTransformCamera->rotateY(mRotationY);
+                mTransformCamera->rotateZ(-mRotation);
+                mTransformCamera->getMatrix(mTransformMatrix3D);
+                mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
+                mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
+                        mPivotY + mTranslationY);
+                mTransformMatrix->postConcat(*mTransformMatrix3D);
+                mTransformCamera->restore();
+            }
+        }
+        mMatrixDirty = false;
+    }
+}
+
+void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) {
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+        updateMatrix();
+        if (mApplicationScale >= 0) {
+            ALOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
+                    mApplicationScale, mApplicationScale);
+        }
+        if (mLeft != 0 || mTop != 0) {
+            ALOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+        }
+        if (mAlpha < 1) {
+            // TODO: should be able to store the size of a DL at record time and not
+            // have to pass it into this call. In fact, this information might be in the
+            // location/size info that we store with the new native transform data.
+            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            if (mClipChildren) {
+                flags |= SkCanvas::kClipToLayer_SaveFlag;
+            }
+            ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+                    mMultipliedAlpha, flags);
+        }
+        if (mMatrixFlags != 0) {
+            if (mMatrixFlags == TRANSLATION) {
+                ALOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+            } else {
+                ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                        indent, "ConcatMatrix", mTransformMatrix,
+                        mTransformMatrix->get(0), mTransformMatrix->get(1),
+                        mTransformMatrix->get(2), mTransformMatrix->get(3),
+                        mTransformMatrix->get(4), mTransformMatrix->get(5),
+                        mTransformMatrix->get(6), mTransformMatrix->get(7),
+                        mTransformMatrix->get(8));
+            }
+        }
+        if (mClipChildren) {
+            ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+                    (float) mRight - mLeft, (float) mBottom - mTop);
+        }
+    }
+}
+
+void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+        uint32_t level) {
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+#if DEBUG_DISPLAY_LIST
+        uint32_t count = (level + 1) * 2;
+        char indent[count + 1];
+        for (uint32_t i = 0; i < count; i++) {
+            indent[i] = ' ';
+        }
+        indent[count] = '\0';
+#endif
+        updateMatrix();
+        if (mLeft != 0 || mTop != 0) {
+            DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+            renderer.translate(mLeft, mTop);
+        }
+        if (mApplicationScale >= 0) {
+            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
+                    mApplicationScale, mApplicationScale);
+            renderer.scale(mApplicationScale, mApplicationScale);
+        }
+        if (mAlpha < 1 && !mCaching) {
+            // TODO: should be able to store the size of a DL at record time and not
+            // have to pass it into this call. In fact, this information might be in the
+            // location/size info that we store with the new native transform data.
+            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            if (mClipChildren) {
+                flags |= SkCanvas::kClipToLayer_SaveFlag;
+            }
+            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+                    mMultipliedAlpha, flags);
+            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
+                    mMultipliedAlpha, flags);
+        }
+        if (mMatrixFlags != 0) {
+            if (mMatrixFlags == TRANSLATION) {
+                DISPLAY_LIST_LOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+                renderer.translate(mTranslationX, mTranslationY);
+            } else {
+                DISPLAY_LIST_LOGD(
+                        "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                        indent, "ConcatMatrix", mTransformMatrix,
+                        mTransformMatrix->get(0), mTransformMatrix->get(1),
+                        mTransformMatrix->get(2), mTransformMatrix->get(3),
+                        mTransformMatrix->get(4), mTransformMatrix->get(5),
+                        mTransformMatrix->get(6), mTransformMatrix->get(7),
+                        mTransformMatrix->get(8));
+                renderer.concatMatrix(mTransformMatrix);
+            }
+        }
+        if (mClipChildren) {
+            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+                    (float) mRight - mLeft, (float) mBottom - mTop);
+            renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
+                    SkRegion::kIntersect_Op);
+        }
+    }
+}
+
+void DisplayList::transformRect(float left, float top, float right, float bottom, Rect& result) {
+    result.left = left + mLeft;
+    result.top = top + mTop;
+    result.right = right + mLeft;
+    result.bottom = bottom + mTop;
+    if (mMatrixFlags != 0) {
+        if (mMatrixFlags == TRANSLATION) {
+            result.left += mTranslationX;
+            result.top += mTranslationY;
+            result.right += mTranslationX;
+            result.bottom += mTranslationY;
+        } else {
+            updateMatrix();
+            SkRect r;
+            r.fLeft = result.left;
+            r.fTop = result.top;
+            r.fRight = result.right;
+            r.fBottom = result.bottom;
+            mTransformMatrix->mapRect(&r);
+            result.left = r.fLeft;
+            result.top = r.fTop;
+            result.right = r.fRight;
+            result.bottom = r.fBottom;
+        }
+    }
+}
+
+
 /**
  * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
  * in the output() function, since that function processes the same list of opcodes for the
  * purposes of logging display list info for a given view.
  */
-bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t width,
+        uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
     mReader.rewind();
@@ -592,6 +812,13 @@
 #endif
 
     renderer.startMark(mName.string());
+    int restoreTo = 0;
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+        DISPLAY_LIST_LOGD("%s%s %d", indent, "Save",
+                SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    }
+    setViewProperties(renderer, width, height, level);
 
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
@@ -644,7 +871,7 @@
                 SkPaint* paint = getPaint(renderer);
                 int32_t flags = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                    OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
                 renderer.saveLayer(f1, f2, f3, f4, paint, flags);
             }
             break;
@@ -656,7 +883,7 @@
                 int32_t alpha = getInt();
                 int32_t flags = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                    OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
                 renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
             }
             break;
@@ -695,7 +922,12 @@
             break;
             case ConcatMatrix: {
                 SkMatrix* matrix = getMatrix();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+                DISPLAY_LIST_LOGD(
+                        "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+                        (char*) indent, OP_NAMES[op], matrix,
+                        matrix->get(0), matrix->get(1), matrix->get(2),
+                        matrix->get(3), matrix->get(4), matrix->get(5),
+                        matrix->get(6), matrix->get(7), matrix->get(8));
                 renderer.concatMatrix(matrix);
             }
             break;
@@ -706,7 +938,7 @@
                 float f4 = getFloat();
                 int32_t regionOp = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                    f1, f2, f3, f4, regionOp);
+                        f1, f2, f3, f4, regionOp);
                 renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
             }
             break;
@@ -716,9 +948,9 @@
                 uint32_t height = getUInt();
                 int32_t flags = getInt();
                 DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                    displayList, width, height, flags, level + 1);
-                needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
-                        dirty, flags, level + 1);
+                        displayList, width, height, flags, level + 1);
+                needsInvalidate |= renderer.drawDisplayList(displayList, width,
+                        height, dirty, flags, level + 1);
             }
             break;
             case DrawLayer: {
@@ -726,8 +958,11 @@
                 float x = getFloat();
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
+                if (mCaching && mMultipliedAlpha < 255) {
+                    paint->setAlpha(mMultipliedAlpha);
+                }
                 DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    layer, x, y, paint);
+                        layer, x, y, paint);
                 renderer.drawLayer(layer, x, y, paint);
             }
             break;
@@ -737,7 +972,7 @@
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    bitmap, x, y, paint);
+                        bitmap, x, y, paint);
                 renderer.drawBitmap(bitmap, x, y, paint);
             }
             break;
@@ -746,7 +981,7 @@
                 SkMatrix* matrix = getMatrix();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                    bitmap, matrix, paint);
+                        bitmap, matrix, paint);
                 renderer.drawBitmap(bitmap, matrix, paint);
             }
             break;
@@ -762,7 +997,8 @@
                 float f8 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+                        (char*) indent, OP_NAMES[op], bitmap,
+                        f1, f2, f3, f4, f5, f6, f7, f8,paint);
                 renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
             }
             break;
@@ -821,7 +1057,7 @@
                 float f4 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                    f1, f2, f3, f4, paint);
+                        f1, f2, f3, f4, paint);
                 renderer.drawRect(f1, f2, f3, f4, paint);
             }
             break;
@@ -834,7 +1070,7 @@
                 float f6 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
                 renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint);
             }
             break;
@@ -844,7 +1080,7 @@
                 float f3 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
                 renderer.drawCircle(f1, f2, f3, paint);
             }
             break;
@@ -855,7 +1091,7 @@
                 float f4 = getFloat();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
                 renderer.drawOval(f1, f2, f3, f4, paint);
             }
             break;
@@ -869,7 +1105,7 @@
                 int32_t i1 = getInt();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
                 renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint);
             }
             break;
@@ -965,7 +1201,7 @@
                 float dy = getFloat();
                 int32_t color = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                    radius, dx, dy, color);
+                        radius, dx, dy, color);
                 renderer.setupShadow(radius, dx, dy, color);
             }
             break;
@@ -984,14 +1220,19 @@
             break;
             default:
                 DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s",
-                    (char*) indent, OP_NAMES[op]);
+                        (char*) indent, OP_NAMES[op]);
                 break;
         }
     }
 
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+        DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+        renderer.restoreToCount(restoreTo);
+    }
     renderer.endMark();
 
-    DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate);
+    DISPLAY_LIST_LOGD("%sDone (%p, %s), returning %d", (char*) indent + 2, this, mName.string(),
+            needsInvalidate);
     return needsInvalidate;
 }
 
@@ -999,7 +1240,7 @@
 // Base structure
 ///////////////////////////////////////////////////////////////////////////////
 
-DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE),
+DisplayListRenderer::DisplayListRenderer() : mWriter(MIN_WRITER_SIZE),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
 }
 
@@ -1177,7 +1418,19 @@
         uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
-    const bool reject = quickReject(0.0f, 0.0f, width, height);
+    float top = 0;
+    float left = 0;
+    float right = width;
+    float bottom = height;
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+        Rect transformedRect;
+        displayList->transformRect(left, top, right, bottom, transformedRect);
+        left = transformedRect.left;
+        top = transformedRect.top;
+        right = transformedRect.right;
+        bottom = transformedRect.bottom;
+    }
+    const bool reject = quickReject(left, top, right, bottom);
     uint32_t* location = addOp(DisplayList::DrawDisplayList, reject);
     addDisplayList(displayList);
     addSize(width, height);
@@ -1274,7 +1527,7 @@
 }
 
 void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, SkPaint* paint) {
+        float rx, float ry, SkPaint* paint) {
     const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
             quickReject(left, top, right, bottom);
     uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 02f8438..abe8b82 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -20,6 +20,7 @@
 #include <SkChunkAlloc.h>
 #include <SkFlattenable.h>
 #include <SkMatrix.h>
+#include <SkCamera.h>
 #include <SkPaint.h>
 #include <SkPath.h>
 #include <SkRefCnt.h>
@@ -28,11 +29,8 @@
 
 #include <cutils/compiler.h>
 
-#include <utils/String8.h>
-
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
-#include "utils/Functor.h"
 
 namespace android {
 namespace uirenderer {
@@ -51,6 +49,16 @@
     #define DISPLAY_LIST_LOGD(...)
 #endif
 
+// Set to 1 to enable native processing of View properties. 0 by default. Eventually this
+// will go away and we will always use this approach for accelerated apps.
+#define USE_DISPLAY_LIST_PROPERTIES 0
+
+#define TRANSLATION 0x0001
+#define ROTATION    0x0002
+#define ROTATION_3D 0x0004
+#define SCALE       0x0008
+#define PIVOT       0x0010
+
 ///////////////////////////////////////////////////////////////////////////////
 // Display list
 ///////////////////////////////////////////////////////////////////////////////
@@ -119,13 +127,18 @@
 
     static const char* OP_NAMES[];
 
+    void setViewProperties(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+            uint32_t level);
+    void outputViewProperties(OpenGLRenderer& renderer, char* indent);
+
     ANDROID_API size_t getSize();
     ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
     ANDROID_API static void outputLogBuffer(int fd);
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
+    bool replay(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+            Rect& dirty, int32_t flags, uint32_t level = 0);
 
     void output(OpenGLRenderer& renderer, uint32_t level = 0);
 
@@ -143,11 +156,240 @@
         }
     }
 
+    void setApplicationScale(float scale) {
+        mApplicationScale = scale;
+    }
+
+    void setClipChildren(bool clipChildren) {
+        mClipChildren = clipChildren;
+    }
+
+    void setAlpha(float alpha) {
+        if (alpha != mAlpha) {
+            mAlpha = alpha;
+            mMultipliedAlpha = (int)(255 * alpha);
+        }
+    }
+
+    void setTranslationX(float translationX) {
+        if (translationX != mTranslationX) {
+            mTranslationX = translationX;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+                mMatrixFlags &= ~TRANSLATION;
+            } else {
+                mMatrixFlags |= TRANSLATION;
+            }
+        }
+    }
+
+    void setTranslationY(float translationY) {
+        if (translationY != mTranslationY) {
+            mTranslationY = translationY;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+                mMatrixFlags &= ~TRANSLATION;
+            } else {
+                mMatrixFlags |= TRANSLATION;
+            }
+        }
+    }
+
+    void setRotation(float rotation) {
+        if (rotation != mRotation) {
+            mRotation = rotation;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mRotation, 0)) {
+                mMatrixFlags &= ~ROTATION;
+            } else {
+                mMatrixFlags |= ROTATION;
+            }
+        }
+    }
+
+    void setRotationX(float rotationX) {
+        if (rotationX != mRotationX) {
+            mRotationX = rotationX;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+                mMatrixFlags &= ~ROTATION_3D;
+            } else {
+                mMatrixFlags |= ROTATION_3D;
+            }
+        }
+    }
+
+    void setRotationY(float rotationY) {
+        if (rotationY != mRotationY) {
+            mRotationY = rotationY;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+                mMatrixFlags &= ~ROTATION_3D;
+            } else {
+                mMatrixFlags |= ROTATION_3D;
+            }
+        }
+    }
+
+    void setScaleX(float scaleX) {
+        if (scaleX != mScaleX) {
+            mScaleX = scaleX;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mScaleX, 1) && ALMOST_EQUAL(mScaleY, 1)) {
+                mMatrixFlags &= ~SCALE;
+            } else {
+                mMatrixFlags |= SCALE;
+            }
+        }
+    }
+
+    void setScaleY(float scaleY) {
+        if (scaleY != mScaleY) {
+            mScaleY = scaleY;
+            mMatrixDirty = true;
+            if (ALMOST_EQUAL(mScaleX, 1) && ALMOST_EQUAL(mScaleY, 1)) {
+                mMatrixFlags &= ~SCALE;
+            } else {
+                mMatrixFlags |= SCALE;
+            }
+        }
+    }
+
+    void setPivotX(float pivotX) {
+        mPivotX = pivotX;
+        mMatrixDirty = true;
+        if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+            mMatrixFlags &= ~PIVOT;
+        } else {
+            mMatrixFlags |= PIVOT;
+        }
+        mPivotExplicitlySet = true;
+    }
+
+    void setPivotY(float pivotY) {
+        mPivotY = pivotY;
+        mMatrixDirty = true;
+        if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+            mMatrixFlags &= ~PIVOT;
+        } else {
+            mMatrixFlags |= PIVOT;
+        }
+        mPivotExplicitlySet = true;
+    }
+
+    void setCameraDistance(float distance) {
+        if (distance != mCameraDistance) {
+            mCameraDistance = distance;
+            mMatrixDirty = true;
+            if (!mTransformCamera) {
+                mTransformCamera = new Sk3DView();
+                mTransformMatrix3D = new SkMatrix();
+            }
+            mTransformCamera->setCameraLocation(0, 0, distance);
+        }
+    }
+
+    void setLeft(int left) {
+        if (left != mLeft) {
+            mLeft = left;
+            mWidth = mRight - mLeft;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setTop(int top) {
+        if (top != mTop) {
+            mTop = top;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setRight(int right) {
+        if (right != mRight) {
+            mRight = right;
+            mWidth = mRight - mLeft;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setBottom(int bottom) {
+        if (bottom != mBottom) {
+            mBottom = bottom;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setLeftTop(int left, int top) {
+        if (left != mLeft || top != mTop) {
+            mLeft = left;
+            mTop = top;
+            mWidth = mRight - mLeft;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+        if (left != mLeft || top != mTop || right != mRight || bottom != mBottom) {
+            mLeft = left;
+            mTop = top;
+            mRight = right;
+            mBottom = bottom;
+            mWidth = mRight - mLeft;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void offsetLeftRight(int offset) {
+        if (offset != 0) {
+            mLeft += offset;
+            mRight += offset;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void offsetTopBottom(int offset) {
+        if (offset != 0) {
+            mTop += offset;
+            mBottom += offset;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setCaching(bool caching) {
+        mCaching = caching;
+    }
+
+    void transformRect(float left, float top, float right, float bottom, Rect& result);
+
 private:
     void init();
 
+    void initProperties();
+
     void clearResources();
 
+    void updateMatrix();
+
     class TextContainer {
     public:
         size_t length() const {
@@ -241,6 +483,28 @@
     bool mIsRenderable;
 
     String8 mName;
+
+    // View properties
+    float mApplicationScale;
+    bool mClipChildren;
+    float mAlpha;
+    int mMultipliedAlpha;
+    float mTranslationX, mTranslationY;
+    float mRotation, mRotationX, mRotationY;
+    float mScaleX, mScaleY;
+    float mPivotX, mPivotY;
+    float mCameraDistance;
+    int mLeft, mTop, mRight, mBottom;
+    int mWidth, mHeight;
+    int mPrevWidth, mPrevHeight;
+    bool mPivotExplicitlySet;
+    bool mMatrixDirty;
+    bool mMatrixIsIdentity;
+    uint32_t mMatrixFlags;
+    SkMatrix* mTransformMatrix;
+    Sk3DView* mTransformCamera;
+    SkMatrix* mTransformMatrix3D;
+    bool mCaching;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b4310ea..685fddc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1323,14 +1323,26 @@
 
 bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
         Rect& dirty, int32_t flags, uint32_t level) {
-    if (quickReject(0.0f, 0.0f, width, height)) {
+    float top = 0;
+    float left = 0;
+    float right = width;
+    float bottom = height;
+    if (USE_DISPLAY_LIST_PROPERTIES) {
+        Rect transformedRect;
+        displayList->transformRect(left, top, right, bottom, transformedRect);
+        left = transformedRect.left;
+        top = transformedRect.top;
+        right = transformedRect.right;
+        bottom = transformedRect.bottom;
+    }
+    if (quickReject(left, top, right, bottom)) {
         return false;
     }
 
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
-        return displayList->replay(*this, dirty, flags, level);
+        return displayList->replay(*this, width, height, dirty, flags, level);
     }
 
     return false;
@@ -2174,13 +2186,12 @@
         return;
     }
 
+    if (length < 0.0f) length = paint->measureText(text, bytesCount);
     switch (paint->getTextAlign()) {
         case SkPaint::kCenter_Align:
-            if (length < 0.0f) length = paint->measureText(text, bytesCount);
             x -= length / 2.0f;
             break;
         case SkPaint::kRight_Align:
-            if (length < 0.0f) length = paint->measureText(text, bytesCount);
             x -= length;
             break;
         default:
@@ -2189,7 +2200,6 @@
 
     SkPaint::FontMetrics metrics;
     paint->getFontMetrics(&metrics, 0.0f);
-    // If no length was specified, just perform the hit test on the Y axis
     if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
         return;
     }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e663e91..139ff01 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -813,6 +813,13 @@
      *
      * @param path the path of the file, or the http/rtsp URL of the stream you want to play
      * @throws IllegalStateException if it is called in an invalid state
+     *
+     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
+     * process other than the calling application.  This implies that the pathname
+     * should be an absolute path (as any other process runs with unspecified current working
+     * directory), and that the pathname should reference a world-readable file.
+     * As an alternative, the application could first open the file for reading,
+     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
      */
     public native void setDataSource(String path)
             throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index b17ae45..6003608 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -42,7 +42,6 @@
     $(TOP)/frameworks/media/libvideoeditor/vss/common/inc \
     $(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
     $(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc \
-    $(TOP)/frameworks/media/libvideoeditor/include \
     $(TOP)/frameworks/media/libvideoeditor/lvpp \
     $(TOP)/frameworks/media/libvideoeditor/osal/inc
 
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index 125c56e..1527f22 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -227,9 +227,9 @@
     /**
      * Return a string for the EGL error code, or the hex representation
      * if the error is unknown.
-     * 
+     *
      * @param error The EGL error to convert into a String.
-     * 
+     *
      * @return An error string corresponding to the EGL error code.
      */
     public static String getEGLErrorString(int error) {
@@ -269,6 +269,14 @@
         }
     }
 
+    /**
+     * Enable tracing of OpenGL functions for this application.
+     * @hide
+     */
+    public static void enableTracing() {
+        native_enableTracing();
+    }
+
     native private static void nativeClassInit();
 
     native private static int native_getInternalFormat(Bitmap bitmap);
@@ -277,4 +285,5 @@
             Bitmap bitmap, int type, int border);
     native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset,
             Bitmap bitmap, int format, int type);
+    native private static void native_enableTracing();
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1763674..e0a0d2d 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3832,7 +3832,8 @@
                         int result = ActivityManagerNative.getDefault()
                                 .startActivity(null, dock,
                                         dock.resolveTypeIfNeeded(mContext.getContentResolver()),
-                                        null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
+                                        null, 0, null, null, 0, true /* onlyIfNeeded*/,
+                                        false /* debug */, false /* openglTrace */,
                                         null, null, false);
                         if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
                             return false;
@@ -3842,7 +3843,8 @@
                 int result = ActivityManagerNative.getDefault()
                         .startActivity(null, mHomeIntent,
                                 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                                null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
+                                null, 0, null, null, 0, true /* onlyIfNeeded*/,
+                                false /* debug */, false /* openglTrace */,
                                 null, null, false);
                 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
                     return false;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index fd968e0..94b9e91 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import com.android.internal.R;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessStats;
@@ -55,6 +57,7 @@
 import android.content.ClipData;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -746,6 +749,7 @@
     ParcelFileDescriptor mProfileFd;
     int mProfileType = 0;
     boolean mAutoStopProfiler = false;
+    String mOpenGlTraceApp = null;
 
     final RemoteCallbackList<IProcessObserver> mProcessObservers
             = new RemoteCallbackList<IProcessObserver>();
@@ -2263,7 +2267,8 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
-            String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+            boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+            boolean autoStopProfiler) {
         enforceNotIsolatedCaller("startActivity");
         int userId = 0;
         if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
@@ -2281,24 +2286,25 @@
         }
         return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded,
-                debug, profileFile, profileFd, autoStopProfiler, null, null, userId);
+                debug, openglTrace, profileFile, profileFd, autoStopProfiler, null, null, userId);
     }
 
     public final WaitResult startActivityAndWait(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
-            String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+            boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+            boolean autoStopProfiler) {
         enforceNotIsolatedCaller("startActivityAndWait");
         WaitResult res = new WaitResult();
         int userId = Binder.getOrigCallingUser();
         mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 grantedUriPermissions, grantedMode, resultTo, resultWho,
-                requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
+                requestCode, onlyIfNeeded, debug, openglTrace, profileFile, profileFd, autoStopProfiler,
                 res, null, userId);
         return res;
     }
-    
+
     public final int startActivityWithConfig(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
@@ -2308,7 +2314,7 @@
         int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 grantedUriPermissions, grantedMode, resultTo, resultWho,
                 requestCode, onlyIfNeeded,
-                debug, null, null, false, null, config, Binder.getOrigCallingUser());
+                debug, false, null, null, false, null, config, Binder.getOrigCallingUser());
         return ret;
     }
 
@@ -2451,7 +2457,7 @@
         }
 
         int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType,
-                null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false,
+                null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false, false,
                 null, null, false, null, null, userId);
         return ret;
     }
@@ -3833,6 +3839,11 @@
                 profileFd = mProfileFd;
                 profileAutoStop = mAutoStopProfiler;
             }
+            boolean enableOpenGlTrace = false;
+            if (mOpenGlTraceApp != null && mOpenGlTraceApp.equals(processName)) {
+                enableOpenGlTrace = true;
+                mOpenGlTraceApp = null;
+            }
 
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
@@ -3858,8 +3869,8 @@
             }
             thread.bindApplication(processName, appInfo, providers,
                     app.instrumentationClass, profileFile, profileFd, profileAutoStop,
-                    app.instrumentationArguments, app.instrumentationWatcher, testMode, 
-                    isRestrictedBackupMode || !normalMode, app.persistent,
+                    app.instrumentationArguments, app.instrumentationWatcher, testMode,
+                    enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent,
                     new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                     mCoreSettingsObserver.getCoreSettingsLocked());
             updateLruProcessLocked(app, false, true);
@@ -4543,76 +4554,91 @@
         throw new SecurityException(msg);
     }
 
-    private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
-            ProviderInfo pi, Uri uri, int uid, int modeFlags) {
-        boolean readPerm = (modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
-        boolean writePerm = (modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
+    /**
+     * Determine if UID is holding permissions required to access {@link Uri} in
+     * the given {@link ProviderInfo}. Final permission checking is always done
+     * in {@link ContentProvider}.
+     */
+    private final boolean checkHoldingPermissionsLocked(
+            IPackageManager pm, ProviderInfo pi, Uri uri, int uid, int modeFlags) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                 "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
+
+        if (pi.applicationInfo.uid == uid) {
+            return true;
+        } else if (!pi.exported) {
+            return false;
+        }
+
+        boolean readMet = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
+        boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
         try {
-            // Is the component private from the target uid?
-            final boolean prv = !pi.exported && pi.applicationInfo.uid != uid;
-
-            // Acceptable if the there is no read permission needed from the
-            // target or the target is holding the read permission.
-            if (!readPerm) {
-                if ((!prv && pi.readPermission == null) ||
-                        (pm.checkUidPermission(pi.readPermission, uid)
-                                == PackageManager.PERMISSION_GRANTED)) {
-                    readPerm = true;
-                }
+            // check if target holds top-level <provider> permissions
+            if (!readMet && pi.readPermission != null
+                    && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) {
+                readMet = true;
+            }
+            if (!writeMet && pi.writePermission != null
+                    && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) {
+                writeMet = true;
             }
 
-            // Acceptable if the there is no write permission needed from the
-            // target or the target is holding the read permission.
-            if (!writePerm) {
-                if (!prv && (pi.writePermission == null) ||
-                        (pm.checkUidPermission(pi.writePermission, uid)
-                                == PackageManager.PERMISSION_GRANTED)) {
-                    writePerm = true;
-                }
-            }
+            // track if unprotected read/write is allowed; any denied
+            // <path-permission> below removes this ability
+            boolean allowDefaultRead = pi.readPermission == null;
+            boolean allowDefaultWrite = pi.writePermission == null;
 
-            // Acceptable if there is a path permission matching the URI that
-            // the target holds the permission on.
-            PathPermission[] pps = pi.pathPermissions;
-            if (pps != null && (!readPerm || !writePerm)) {
+            // check if target holds any <path-permission> that match uri
+            final PathPermission[] pps = pi.pathPermissions;
+            if (pps != null) {
                 final String path = uri.getPath();
                 int i = pps.length;
-                while (i > 0 && (!readPerm || !writePerm)) {
+                while (i > 0 && (!readMet || !writeMet)) {
                     i--;
                     PathPermission pp = pps[i];
-                    if (!readPerm) {
-                        final String pprperm = pp.getReadPermission();
-                        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
-                                + pprperm + " for " + pp.getPath()
-                                + ": match=" + pp.match(path)
-                                + " check=" + pm.checkUidPermission(pprperm, uid));
-                        if (pprperm != null && pp.match(path) &&
-                                (pm.checkUidPermission(pprperm, uid)
-                                        == PackageManager.PERMISSION_GRANTED)) {
-                            readPerm = true;
+                    if (pp.match(path)) {
+                        if (!readMet) {
+                            final String pprperm = pp.getReadPermission();
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
+                                    + pprperm + " for " + pp.getPath()
+                                    + ": match=" + pp.match(path)
+                                    + " check=" + pm.checkUidPermission(pprperm, uid));
+                            if (pprperm != null) {
+                                if (pm.checkUidPermission(pprperm, uid) == PERMISSION_GRANTED) {
+                                    readMet = true;
+                                } else {
+                                    allowDefaultRead = false;
+                                }
+                            }
                         }
-                    }
-                    if (!writePerm) {
-                        final String ppwperm = pp.getWritePermission();
-                        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
-                                + ppwperm + " for " + pp.getPath()
-                                + ": match=" + pp.match(path)
-                                + " check=" + pm.checkUidPermission(ppwperm, uid));
-                        if (ppwperm != null && pp.match(path) &&
-                                (pm.checkUidPermission(ppwperm, uid)
-                                        == PackageManager.PERMISSION_GRANTED)) {
-                            writePerm = true;
+                        if (!writeMet) {
+                            final String ppwperm = pp.getWritePermission();
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
+                                    + ppwperm + " for " + pp.getPath()
+                                    + ": match=" + pp.match(path)
+                                    + " check=" + pm.checkUidPermission(ppwperm, uid));
+                            if (ppwperm != null) {
+                                if (pm.checkUidPermission(ppwperm, uid) == PERMISSION_GRANTED) {
+                                    writeMet = true;
+                                } else {
+                                    allowDefaultWrite = false;
+                                }
+                            }
                         }
                     }
                 }
             }
+
+            // grant unprotected <provider> read/write, if not blocked by
+            // <path-permission> above
+            if (allowDefaultRead) readMet = true;
+            if (allowDefaultWrite) writeMet = true;
+
         } catch (RemoteException e) {
             return false;
         }
 
-        return readPerm && writePerm;
+        return readMet && writeMet;
     }
 
     private final boolean checkUriPermissionLocked(Uri uri, int uid,
@@ -5819,6 +5845,11 @@
         return providers;
     }
 
+    /**
+     * Check if {@link ProcessRecord} has a possible chance at accessing the
+     * given {@link ProviderInfo}. Final permission checking is always done
+     * in {@link ContentProvider}.
+     */
     private final String checkContentProviderPermissionLocked(
             ProviderInfo cpi, ProcessRecord r) {
         final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
@@ -6671,6 +6702,19 @@
         }
     }
 
+    void setOpenGlTraceApp(ApplicationInfo app, String processName) {
+        synchronized (this) {
+            boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+            if (!isDebuggable) {
+                if ((app.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+                    throw new SecurityException("Process not debuggable: " + app.packageName);
+                }
+            }
+
+            mOpenGlTraceApp = processName;
+        }
+    }
+
     void setProfileApp(ApplicationInfo app, String processName, String profileFile,
             ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
         synchronized (this) {
@@ -8625,6 +8669,9 @@
                     + " mDebugTransient=" + mDebugTransient
                     + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
         }
+        if (mOpenGlTraceApp != null) {
+            pw.println("  mOpenGlTraceApp=" + mOpenGlTraceApp);
+        }
         if (mProfileApp != null || mProfileProc != null || mProfileFile != null
                 || mProfileFd != null) {
             pw.println("  mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a4e573d..64d52ed 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2828,7 +2828,8 @@
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
-            String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+            boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+            boolean autoStopProfiler) {
         // Collect information about the target of the Intent.
         ActivityInfo aInfo;
         try {
@@ -2857,6 +2858,12 @@
                 }
             }
 
+            if (openglTrace) {
+                if (!aInfo.processName.equals("system")) {
+                    mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
+                }
+            }
+
             if (profileFile != null) {
                 if (!aInfo.processName.equals("system")) {
                     mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
@@ -2871,7 +2878,7 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
-            boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+            boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
             boolean autoStopProfiler,
             WaitResult outResult, Configuration config, int userId) {
         // Refuse possible leaked file descriptors
@@ -2884,7 +2891,7 @@
         intent = new Intent(intent);
 
         // Collect information about the target of the Intent.
-        ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
+        ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug, openglTrace,
                 profileFile, profileFd, autoStopProfiler);
         aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
@@ -3074,7 +3081,7 @@
                     intent = new Intent(intent);
 
                     // Collect information about the target of the Intent.
-                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
+                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false, false,
                             null, null, false);
                     // TODO: New, check if this is correct
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 6e4dd58..5f1a014 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -231,7 +231,8 @@
                     internalDataEnabled &&
                     desiredPowerState &&
                     !mPendingRestartRadio &&
-                    !mCdmaPhone.needsOtaServiceProvisioning();
+                    ((mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) ||
+                            !mCdmaPhone.needsOtaServiceProvisioning());
         if (!allowed && DBG) {
             String reason = "";
             if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
index 517eb1e..cad37c5 100644
--- a/tests/SmokeTest/tests/AndroidManifest.xml
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -18,20 +18,30 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.smoketest.tests">
 
-    <!-- We add an application tag here just so that we can indicate that
-         this package needs to link against the android.test library,
-         which is needed when building test cases. -->    
+    <!--
+    We add an application tag here just so that we can indicate that this package needs to link
+    against the android.test library, which is needed when building test cases.
+    -->
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <!--
-    This declares that this app uses the instrumentation test runner targeting
-    the package of com.android.smoketest.  To run the tests use the command:
-    "adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner"
+    This declares that this app uses the instrumentation test runner targeting the package of
+    com.android.smoketest.  To run the tests use the command:
+    `adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner`
     -->
     <instrumentation android:name="android.test.InstrumentationTestRunner"
                      android:targetPackage="com.android.smoketest"
                      android:label="System Smoke Tests"/>
 
+    <!--
+    This declares a method to run the instrumentation with a special runner, which will run each
+    app as a separate testcase.  To do so, use the command:
+    `adb shell am instrument -w com.android.smoketest.tests/com.android.smoketest.SmokeTestRunner`
+    -->
+    <instrumentation android:name="com.android.smoketest.SmokeTestRunner"
+                     android:targetPackage="com.android.smoketest"
+                     android:label="System Smoke Tests"/>
+
 </manifest>
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
index 1a2dcb9..3efd658 100644
--- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -16,8 +16,6 @@
 
 package com.android.smoketest;
 
-import com.android.internal.os.RuntimeInit;
-
 import android.app.ActivityManager;
 import android.app.ActivityManager.ProcessErrorStateInfo;
 import android.content.Context;
@@ -42,10 +40,18 @@
 public class ProcessErrorsTest extends AndroidTestCase {
     
     private static final String TAG = "ProcessErrorsTest";
-    
+
+    private final Intent mHomeIntent;
+
     protected ActivityManager mActivityManager;
     protected PackageManager mPackageManager;
 
+    public ProcessErrorsTest() {
+        mHomeIntent = new Intent(Intent.ACTION_MAIN);
+        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -59,7 +65,7 @@
         assertNotNull(mPackageManager);
     }
 
-    public void testNoProcessErrors() throws Exception {
+    public void testNoProcessErrorsAfterBoot() throws Exception {
         final String reportMsg = checkForProcessErrors();
         if (reportMsg != null) {
             Log.w(TAG, reportMsg);
@@ -72,16 +78,80 @@
     private String checkForProcessErrors() throws Exception {
         List<ProcessErrorStateInfo> errList;
         errList = mActivityManager.getProcessesInErrorState();
-        
+
         // note: this contains information about each process that is currently in an error
-        // condition.  if the list is empty (null) then "we're good".  
-        
+        // condition.  if the list is empty (null) then "we're good".
+
         // if the list is non-empty, then it's useful to report the contents of the list
         final String reportMsg = reportListContents(errList);
         return reportMsg;
     }
 
     /**
+     * A helper function to query the provided {@link PackageManager} for a list of Activities that
+     * can be launched from Launcher.
+     */
+    static List<ResolveInfo> getLauncherActivities(PackageManager pm) {
+        final Intent launchable = new Intent(Intent.ACTION_MAIN);
+        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+        final List<ResolveInfo> activities = pm.queryIntentActivities(launchable, 0);
+        return activities;
+    }
+
+    /**
+     * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying
+     * an activity to be launched.
+     */
+    static Intent intentForActivity(ResolveInfo app) {
+        // build an Intent to launch the specified app
+        final ComponentName component = new ComponentName(app.activityInfo.packageName,
+                app.activityInfo.name);
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(component);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        return intent;
+    }
+
+    /**
+     * A method to run the specified Activity and return a {@link Collection} of the Activities that
+     * were in an error state, as listed by {@link ActivityManager.getProcessesInErrorState()}.
+     * <p />
+     * The method will launch the app, wait for 7 seconds, check for apps in the error state, send
+     * the Home intent, wait for 2 seconds, and then return.
+     */
+    public Collection<ProcessErrorStateInfo> runOneActivity(ResolveInfo app) {
+        final long appLaunchWait = 7000;
+        final long homeLaunchWait = 2000;
+
+        Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName,
+                app.activityInfo.name));
+
+        // launch app, and wait 7 seconds for it to start/settle
+        final Intent intent = intentForActivity(app);
+        getContext().startActivity(intent);
+        try {
+            Thread.sleep(appLaunchWait);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        // See if there are any errors
+        final Collection<ProcessErrorStateInfo> errProcs =
+                mActivityManager.getProcessesInErrorState();
+
+        // Send the "home" intent and wait 2 seconds for us to get there
+        getContext().startActivity(mHomeIntent);
+        try {
+            Thread.sleep(homeLaunchWait);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        return errProcs;
+    }
+
+    /**
      * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
      * happened while doing so.
      * <p />
@@ -89,46 +159,12 @@
      * FIXME: first app doesn't go away.
      */
     public void testRunAllActivities() throws Exception {
-        final Intent home = new Intent(Intent.ACTION_MAIN);
-        home.addCategory(Intent.CATEGORY_HOME);
-        home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        final Intent launchable = new Intent(Intent.ACTION_MAIN);
-        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
-        final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
         final Set<ProcessError> errSet = new HashSet<ProcessError>();
 
-        for (ResolveInfo info : activities) {
-            Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
-                    info.activityInfo.name));
-
-            // build an Intent to launch the app
-            final ComponentName component = new ComponentName(info.activityInfo.packageName,
-                    info.activityInfo.name);
-            final Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.setComponent(component);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-            // launch app, and wait 7 seconds for it to start/settle
-            getContext().startActivity(intent);
-            try {
-                Thread.sleep(7000);
-            } catch (InterruptedException e) {
-                // ignore
-            }
-
-            // See if there are any errors
-            Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
-            if (procs != null) {
-                errSet.addAll(ProcessError.fromCollection(procs));
-            }
-
-            // Send the "home" intent and wait 2 seconds for us to get there
-            getContext().startActivity(home);
-            try {
-                Thread.sleep(2000);
-            } catch (InterruptedException e) {
-                // ignore
+        for (ResolveInfo app : getLauncherActivities(mPackageManager)) {
+            final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
+            if (errProcs != null) {
+                errSet.addAll(ProcessError.fromCollection(errProcs));
             }
         }
 
@@ -138,7 +174,7 @@
         }
     }
 
-    private String reportWrappedListContents(Collection<ProcessError> errList) {
+    String reportWrappedListContents(Collection<ProcessError> errList) {
         List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
         for (ProcessError err : errList) {
             newList.add(err.info);
@@ -186,7 +222,7 @@
      * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
      * crashes are considered equal).
      */
-    private static class ProcessError {
+    static class ProcessError {
         public final ProcessErrorStateInfo info;
 
         public ProcessError(ProcessErrorStateInfo newInfo) {
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
new file mode 100644
index 0000000..40b11c5
--- /dev/null
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.InstrumentationTestRunner;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A special test runner which does a test-start for each app in a separate testcase
+ */
+public class SmokeTestRunner extends InstrumentationTestRunner {
+
+    private static final String SUITE_NAME = "Smoke Test Suite";
+
+    /**
+     * Returns a single testcase for each app to launch
+     */
+    @Override
+    public TestSuite getAllTests() {
+        final TestSuite suite = new TestSuite(SUITE_NAME);
+
+        final PackageManager pm = getTargetContext().getPackageManager();
+        final List<ResolveInfo> apps = ProcessErrorsTest.getLauncherActivities(pm);
+
+        // FIXME: figure out some way to control the reported class names for these anonymous
+        // FIXME: class instances.
+
+        final TestCase setupTest = new ProcessErrorsTest() {
+            @Override
+            public void runTest() throws Exception {
+                testSetUpConditions();
+            }
+        };
+        setupTest.setName("testSetUpConditions");
+        suite.addTest(setupTest);
+
+        final TestCase postBootTest = new ProcessErrorsTest() {
+            @Override
+            public void runTest() throws Exception {
+                testNoProcessErrorsAfterBoot();
+            }
+        };
+        postBootTest.setName("testNoProcessErrorsAfterBoot");
+        suite.addTest(postBootTest);
+
+        for (final ResolveInfo app : apps) {
+            final TestCase appTest = new ProcessErrorsTest() {
+                @Override
+                public void runTest() throws Exception {
+                    final Set<ProcessError> errSet = new HashSet<ProcessError>();
+                    final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
+                    if (errProcs != null) {
+                        errSet.addAll(ProcessError.fromCollection(errProcs));
+                    }
+
+                    if (!errSet.isEmpty()) {
+                        fail(String.format("Got %d errors: %s", errSet.size(),
+                                reportWrappedListContents(errSet)));
+                    }
+                }
+            };
+            appTest.setName(app.activityInfo.name);
+            suite.addTest(appTest);
+        }
+
+        return suite;
+    }
+}
+