Merge "Adding idle maintenance service."
diff --git a/Android.mk b/Android.mk
index c8576a0..b9cd7bf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,6 +69,7 @@
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
+	core/java/android/app/INotificationListener.aidl \
 	core/java/android/app/INotificationManager.aidl \
 	core/java/android/app/IProcessObserver.aidl \
 	core/java/android/app/ISearchManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 41ebf4b..d661daa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1174,6 +1174,7 @@
     field public static final int windowMinWidthMinor = 16843607; // 0x1010357
     field public static final int windowNoDisplay = 16843294; // 0x101021e
     field public static final int windowNoTitle = 16842838; // 0x1010056
+    field public static final int windowOverscan = 16843727; // 0x10103cf
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1693,6 +1694,7 @@
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
+    field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
     field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
     field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1711,9 +1713,11 @@
     field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
     field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
     field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
+    field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
     field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
     field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
     field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
+    field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
     field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
     field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
     field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1736,9 +1740,11 @@
     field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
     field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
     field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
+    field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
     field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
     field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
     field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
+    field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
     field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
     field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
     field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1746,12 +1752,14 @@
     field public static final int Theme_Light = 16973836; // 0x103000c
     field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
     field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
+    field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_NoDisplay = 16973909; // 0x1030055
     field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
+    field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
     field public static final int Theme_Panel = 16973913; // 0x1030059
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -11443,6 +11451,11 @@
     field public static final int MPEG4ProfileSimpleFBA = 128; // 0x80
     field public static final int MPEG4ProfileSimpleFace = 64; // 0x40
     field public static final int MPEG4ProfileSimpleScalable = 2; // 0x2
+    field public static final int VP8Level_Version0 = 1; // 0x1
+    field public static final int VP8Level_Version1 = 2; // 0x2
+    field public static final int VP8Level_Version2 = 4; // 0x4
+    field public static final int VP8Level_Version3 = 8; // 0x8
+    field public static final int VP8ProfileMain = 1; // 0x1
     field public int level;
     field public int profile;
   }
@@ -13419,6 +13432,7 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
+    field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
     field public int networkId;
     field public java.lang.String preSharedKey;
@@ -13476,6 +13490,45 @@
     field public static final java.lang.String[] strings;
   }
 
+  public class WifiEnterpriseConfig implements android.os.Parcelable {
+    ctor public WifiEnterpriseConfig();
+    ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+    method public int describeContents();
+    method public java.lang.String getAnonymousIdentity();
+    method public int getEapMethod();
+    method public java.lang.String getIdentity();
+    method public int getPhase2Method();
+    method public java.lang.String getSubjectMatch();
+    method public void setAnonymousIdentity(java.lang.String);
+    method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+    method public void setEapMethod(int);
+    method public void setIdentity(java.lang.String);
+    method public void setPassword(java.lang.String);
+    method public void setPhase2Method(int);
+    method public void setSubjectMatch(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class WifiEnterpriseConfig.Eap {
+    ctor public WifiEnterpriseConfig.Eap();
+    field public static final int NONE = -1; // 0xffffffff
+    field public static final int PEAP = 0; // 0x0
+    field public static final int PWD = 3; // 0x3
+    field public static final int TLS = 1; // 0x1
+    field public static final int TTLS = 2; // 0x2
+  }
+
+  public static final class WifiEnterpriseConfig.Phase2 {
+    ctor public WifiEnterpriseConfig.Phase2();
+    field public static final int GTC = 4; // 0x4
+    field public static final int MSCHAP = 2; // 0x2
+    field public static final int MSCHAPV2 = 3; // 0x3
+    field public static final int NONE = 0; // 0x0
+    field public static final int PAP = 1; // 0x1
+  }
+
   public class WifiInfo implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.String getBSSID();
@@ -16559,9 +16612,15 @@
   public class StatFs {
     ctor public StatFs(java.lang.String);
     method public int getAvailableBlocks();
+    method public long getAvailableBlocksLong();
+    method public long getAvailableBytes();
     method public int getBlockCount();
+    method public long getBlockCountLong();
     method public int getBlockSize();
+    method public long getBlockSizeLong();
     method public int getFreeBlocks();
+    method public long getFreeBlocksLong();
+    method public long getFreeBytes();
     method public void restat(java.lang.String);
   }
 
@@ -20072,6 +20131,9 @@
     method public static android.renderscript.Sampler CLAMP_LINEAR(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler CLAMP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler CLAMP_NEAREST(android.renderscript.RenderScript);
+    method public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR(android.renderscript.RenderScript);
+    method public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR_MIP_LINEAR(android.renderscript.RenderScript);
+    method public static android.renderscript.Sampler MIRRORED_REPEAT_NEAREST(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler WRAP_LINEAR(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler WRAP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler WRAP_NEAREST(android.renderscript.RenderScript);
@@ -20099,6 +20161,7 @@
     enum_constant public static final android.renderscript.Sampler.Value LINEAR;
     enum_constant public static final android.renderscript.Sampler.Value LINEAR_MIP_LINEAR;
     enum_constant public static final android.renderscript.Sampler.Value LINEAR_MIP_NEAREST;
+    enum_constant public static final android.renderscript.Sampler.Value MIRRORED_REPEAT;
     enum_constant public static final android.renderscript.Sampler.Value NEAREST;
     enum_constant public static final android.renderscript.Sampler.Value WRAP;
   }
@@ -22913,9 +22976,14 @@
 
   public class EasyEditSpan implements android.text.ParcelableSpan {
     ctor public EasyEditSpan();
+    ctor public EasyEditSpan(android.app.PendingIntent);
+    ctor public EasyEditSpan(android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String EXTRA_TEXT_CHANGED_TYPE = "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
+    field public static final int TEXT_DELETED = 1; // 0x1
+    field public static final int TEXT_MODIFIED = 2; // 0x2
   }
 
   public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
@@ -26197,6 +26265,7 @@
     field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
     field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
     field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
+    field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
     field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
     field public static final int FLAG_NOT_FOCUSABLE = 8; // 0x8
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk
index 8b321b3..f8350dc 100644
--- a/cmds/am/Android.mk
+++ b/cmds/am/Android.mk
@@ -1,31 +1,15 @@
 # Copyright 2008 The Android Open Source Project
 #
 LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
+include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 LOCAL_MODULE := am
 include $(BUILD_JAVA_LIBRARY)
 
 include $(CLEAR_VARS)
-ALL_PREBUILT += $(TARGET_OUT)/bin/am
-$(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP)
-	$(transform-prebuilt-to-target)
-
-NOTICE_FILE := NOTICE
-files_noticed := bin/am
-
-# Generate rules for a single file. The argument is the file path relative to
-# the installation root
-define make-notice-file
-
-$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
-	@echo Notice file: $$< -- $$@
-	@mkdir -p $$(dir $$@)
-	@cat $$< >> $$@
-
-$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
-
-endef
-
-$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
+LOCAL_MODULE := am
+LOCAL_SRC_FILES := am
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3c1fbfe..9fa7dbb 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,7 +26,6 @@
 import android.app.Instrumentation;
 import android.app.UiAutomationConnection;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -39,7 +38,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.AndroidException;
-import android.view.Display;
 import android.view.IWindowManager;
 
 import java.io.BufferedReader;
@@ -134,10 +132,6 @@
             runMonitor();
         } else if (op.equals("screen-compat")) {
             runScreenCompat();
-        } else if (op.equals("display-size")) {
-            runDisplaySize();
-        } else if (op.equals("display-density")) {
-            runDisplayDensity();
         } else if (op.equals("to-uri")) {
             runToUri(false);
         } else if (op.equals("to-intent-uri")) {
@@ -1201,82 +1195,6 @@
         } while (packageName != null);
     }
 
-    private void runDisplaySize() throws Exception {
-        String size = nextArgRequired();
-        int w, h;
-        if ("reset".equals(size)) {
-            w = h = -1;
-        } else {
-            int div = size.indexOf('x');
-            if (div <= 0 || div >= (size.length()-1)) {
-                System.err.println("Error: bad size " + size);
-                return;
-            }
-            String wstr = size.substring(0, div);
-            String hstr = size.substring(div+1);
-            try {
-                w = Integer.parseInt(wstr);
-                h = Integer.parseInt(hstr);
-            } catch (NumberFormatException e) {
-                System.err.println("Error: bad number " + e);
-                return;
-            }
-        }
-
-        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
-                Context.WINDOW_SERVICE));
-        if (wm == null) {
-            System.err.println(NO_SYSTEM_ERROR_CODE);
-            throw new AndroidException("Can't connect to window manager; is the system running?");
-        }
-
-        try {
-            if (w >= 0 && h >= 0) {
-                // TODO(multidisplay): For now Configuration only applies to main screen.
-                wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
-            } else {
-                wm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
-            }
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void runDisplayDensity() throws Exception {
-        String densityStr = nextArgRequired();
-        int density;
-        if ("reset".equals(densityStr)) {
-            density = -1;
-        } else {
-            try {
-                density = Integer.parseInt(densityStr);
-            } catch (NumberFormatException e) {
-                System.err.println("Error: bad number " + e);
-                return;
-            }
-            if (density < 72) {
-                System.err.println("Error: density must be >= 72");
-                return;
-            }
-        }
-
-        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
-                Context.WINDOW_SERVICE));
-        if (wm == null) {
-            System.err.println(NO_SYSTEM_ERROR_CODE);
-            throw new AndroidException("Can't connect to window manager; is the system running?");
-        }
-
-        try {
-            if (density > 0) {
-                // TODO(multidisplay): For now Configuration only applies to main screen.
-                wm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
-            } else {
-                wm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
-            }
-        } catch (RemoteException e) {
-        }
-    }
-
     private void runToUri(boolean intentScheme) throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
         System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
@@ -1454,8 +1372,6 @@
                 "       am clear-debug-app\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
-                "       am display-size [reset|WxH]\n" +
-                "       am display-density [reset|DENSITY]\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
@@ -1524,17 +1440,13 @@
                 "am clear-debug-app: clear the previously set-debug-app.\n" +
                 "\n" +
                 "am bug-report: request bug report generation; will launch UI\n" +
-                "    when done to select where it should be delivered." +
+                "    when done to select where it should be delivered.\n" +
                 "\n" +
                 "am monitor: start monitoring for crashes or ANRs.\n" +
                 "    --gdb: start gdbserv on the given port at crash/ANR\n" +
                 "\n" +
                 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
                 "\n" +
-                "am display-size: override display size.\n" +
-                "\n" +
-                "am display-density: override display density.\n" +
-                "\n" +
                 "am to-uri: print the given Intent specification as a URI.\n" +
                 "\n" +
                 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk
index 88c46f2..9302e2f 100644
--- a/cmds/content/Android.mk
+++ b/cmds/content/Android.mk
@@ -1,33 +1,15 @@
 # Copyright 2012 The Android Open Source Project
 
 LOCAL_PATH:= $(call my-dir)
+
 include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
 LOCAL_MODULE := content
-
 include $(BUILD_JAVA_LIBRARY)
 
 include $(CLEAR_VARS)
-ALL_PREBUILT += $(TARGET_OUT)/bin/content
-$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP)
-	$(transform-prebuilt-to-target)
-
-NOTICE_FILE := NOTICE
-files_noticed := bin/content
-
-# Generate rules for a single file. The argument is the file path relative to
-# the installation root
-define make-notice-file
-
-$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
-	@echo Notice file: $$< -- $$@
-	@mkdir -p $$(dir $$@)
-	@cat $$< >> $$@
-
-$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
-
-endef
-
-$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
+LOCAL_MODULE := content
+LOCAL_SRC_FILES := content
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk
new file mode 100644
index 0000000..3f3795f
--- /dev/null
+++ b/cmds/wm/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2013 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := wm
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := wm
+LOCAL_SRC_FILES := wm
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/wm/MODULE_LICENSE_APACHE2 b/cmds/wm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/wm/MODULE_LICENSE_APACHE2
diff --git a/cmds/wm/NOTICE b/cmds/wm/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/wm/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
new file mode 100644
index 0000000..f48764f
--- /dev/null
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -0,0 +1,241 @@
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+package com.android.commands.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.AndroidException;
+import android.view.Display;
+import android.view.IWindowManager;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Wm {
+
+    private IWindowManager mWm;
+    private String[] mArgs;
+    private int mNextArg;
+    private String mCurArgData;
+
+    // These are magic strings understood by the Eclipse plugin.
+    private static final String FATAL_ERROR_CODE = "Error type 1";
+    private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
+    private static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
+    /**
+     * Command-line entry point.
+     *
+     * @param args The command-line arguments
+     */
+    public static void main(String[] args) {
+        try {
+            (new Wm()).run(args);
+        } catch (IllegalArgumentException e) {
+            showUsage();
+            System.err.println("Error: " + e.getMessage());
+        } catch (Exception e) {
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+    }
+
+    private void run(String[] args) throws Exception {
+        if (args.length < 1) {
+            showUsage();
+            return;
+        }
+
+        mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
+                        Context.WINDOW_SERVICE));
+        if (mWm == null) {
+            System.err.println(NO_SYSTEM_ERROR_CODE);
+            throw new AndroidException("Can't connect to window manager; is the system running?");
+        }
+
+        mArgs = args;
+        String op = args[0];
+        mNextArg = 1;
+
+        if (op.equals("size")) {
+            runDisplaySize();
+        } else if (op.equals("density")) {
+            runDisplayDensity();
+        } else if (op.equals("overscan")) {
+            runDisplayOverscan();
+        } else {
+            throw new IllegalArgumentException("Unknown command: " + op);
+        }
+    }
+
+    private void runDisplaySize() throws Exception {
+        String size = nextArgRequired();
+        int w, h;
+        if ("reset".equals(size)) {
+            w = h = -1;
+        } else {
+            int div = size.indexOf('x');
+            if (div <= 0 || div >= (size.length()-1)) {
+                System.err.println("Error: bad size " + size);
+                return;
+            }
+            String wstr = size.substring(0, div);
+            String hstr = size.substring(div+1);
+            try {
+                w = Integer.parseInt(wstr);
+                h = Integer.parseInt(hstr);
+            } catch (NumberFormatException e) {
+                System.err.println("Error: bad number " + e);
+                return;
+            }
+        }
+
+        try {
+            if (w >= 0 && h >= 0) {
+                // TODO(multidisplay): For now Configuration only applies to main screen.
+                mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
+            } else {
+                mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runDisplayDensity() throws Exception {
+        String densityStr = nextArgRequired();
+        int density;
+        if ("reset".equals(densityStr)) {
+            density = -1;
+        } else {
+            try {
+                density = Integer.parseInt(densityStr);
+            } catch (NumberFormatException e) {
+                System.err.println("Error: bad number " + e);
+                return;
+            }
+            if (density < 72) {
+                System.err.println("Error: density must be >= 72");
+                return;
+            }
+        }
+
+        try {
+            if (density > 0) {
+                // TODO(multidisplay): For now Configuration only applies to main screen.
+                mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
+            } else {
+                mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runDisplayOverscan() throws Exception {
+        String overscanStr = nextArgRequired();
+        Rect rect = new Rect();
+        int density;
+        if ("reset".equals(overscanStr)) {
+            rect.set(0, 0, 0, 0);
+        } else {
+            final Pattern FLATTENED_PATTERN = Pattern.compile(
+                    "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
+            Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
+            if (!matcher.matches()) {
+                System.err.println("Error: bad rectangle arg: " + overscanStr);
+                return;
+            }
+            rect.left = Integer.parseInt(matcher.group(1));
+            rect.top = Integer.parseInt(matcher.group(2));
+            rect.right = Integer.parseInt(matcher.group(3));
+            rect.bottom = Integer.parseInt(matcher.group(4));
+        }
+
+        try {
+            mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private String nextOption() {
+        if (mCurArgData != null) {
+            String prev = mArgs[mNextArg - 1];
+            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+        }
+        if (mNextArg >= mArgs.length) {
+            return null;
+        }
+        String arg = mArgs[mNextArg];
+        if (!arg.startsWith("-")) {
+            return null;
+        }
+        mNextArg++;
+        if (arg.equals("--")) {
+            return null;
+        }
+        if (arg.length() > 1 && arg.charAt(1) != '-') {
+            if (arg.length() > 2) {
+                mCurArgData = arg.substring(2);
+                return arg.substring(0, 2);
+            } else {
+                mCurArgData = null;
+                return arg;
+            }
+        }
+        mCurArgData = null;
+        return arg;
+    }
+
+    private String nextArg() {
+        if (mCurArgData != null) {
+            String arg = mCurArgData;
+            mCurArgData = null;
+            return arg;
+        } else if (mNextArg < mArgs.length) {
+            return mArgs[mNextArg++];
+        } else {
+            return null;
+        }
+    }
+
+    private String nextArgRequired() {
+        String arg = nextArg();
+        if (arg == null) {
+            String prev = mArgs[mNextArg - 1];
+            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
+        }
+        return arg;
+    }
+
+    private static void showUsage() {
+        System.err.println(
+                "usage: wm [subcommand] [options]\n" +
+                "       wm size [reset|WxH]\n" +
+                "       wm density [reset|DENSITY]\n" +
+                "       wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" +
+                "\n" +
+                "wm size: override display size.\n" +
+                "\n" +
+                "wm density: override display density.\n" +
+                "\n" +
+                "wm overscan: set overscan area for display.\n"
+                );
+    }
+}
diff --git a/cmds/wm/wm b/cmds/wm/wm
new file mode 100755
index 0000000..f7a5bc7
--- /dev/null
+++ b/cmds/wm/wm
@@ -0,0 +1,6 @@
+# Script to start "wm" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/wm.jar
+exec app_process $base/bin com.android.commands.wm.Wm "$@"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a40fe75..734d435 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -460,7 +460,8 @@
         registerService(STORAGE_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     try {
-                        return new StorageManager(ctx.mMainThread.getHandler().getLooper());
+                        return new StorageManager(
+                                ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
                     } catch (RemoteException rex) {
                         Log.e(TAG, "Failed to create StorageManager", rex);
                         return null;
diff --git a/core/java/android/app/INotificationListener.aidl b/core/java/android/app/INotificationListener.aidl
new file mode 100644
index 0000000..f010a2a
--- /dev/null
+++ b/core/java/android/app/INotificationListener.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+oneway interface INotificationListener
+{
+    void onNotificationPosted(in StatusBarNotification notification);
+    void onNotificationRemoved(in StatusBarNotification notification);
+}
\ No newline at end of file
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 1f4c81d..14bcc0d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -17,6 +17,7 @@
 
 package android.app;
 
+import android.app.INotificationListener;
 import android.app.ITransientNotification;
 import android.app.Notification;
 import android.content.Intent;
@@ -39,5 +40,8 @@
 
     StatusBarNotification[] getActiveNotifications(String callingPkg);
     StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
+
+    void registerListener(in INotificationListener listener, int userid);
+    void unregisterListener(in INotificationListener listener, int userid);
 }
 
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 9b5857f..06ef472 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -27,7 +27,7 @@
 import android.os.ServiceManager;
 import android.view.IWindowManager;
 import android.view.InputEvent;
-import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
 
@@ -135,7 +135,7 @@
         }
         final long identity = Binder.clearCallingIdentity();
         try {
-            return Surface.screenshot(width, height);
+            return SurfaceControl.screenshot(width, height);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 9ad33a5..b678df7 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -227,6 +227,7 @@
         String libDir = (appInfo.nativeLibraryDir != null)
                 ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                 : null;
+        String externalFilesDir = getExternalFilesDir(null).getCanonicalPath();
 
         // Filters, the scan queue, and the set of resulting entities
         HashSet<String> filterSet = new HashSet<String>();
@@ -254,6 +255,12 @@
         filterSet.add(databaseDir);
         filterSet.remove(sharedPrefsDir);
         fullBackupFileTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, sharedPrefsDir, filterSet, data);
+
+        // getExternalFilesDir() location associated with this app.  Technically there should
+        // not be any files here if the app does not properly have permission to access
+        // external storage, but edge cases happen. fullBackupFileTree() catches
+        // IOExceptions and similar, and treats them as non-fatal, so we rely on that here.
+        fullBackupFileTree(packageName, FullBackup.MANAGED_EXTERNAL_TREE_TOKEN, externalFilesDir, null, data);
     }
 
     /**
@@ -274,6 +281,7 @@
         String spDir;
         String cacheDir;
         String libDir;
+        String efDir;
         String filePath;
 
         ApplicationInfo appInfo = getApplicationInfo();
@@ -287,6 +295,7 @@
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
+            efDir = getExternalFilesDir(null).getCanonicalPath();
 
             // Now figure out which well-defined tree the file is placed in, working from
             // most to least specific.  We also specifically exclude the lib and cache dirs.
@@ -315,6 +324,9 @@
         } else if (filePath.startsWith(mainDir)) {
             domain = FullBackup.ROOT_TREE_TOKEN;
             rootpath = mainDir;
+        } else if (filePath.startsWith(efDir)) {
+            domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
+            rootpath = efDir;
         } else {
             Log.w(TAG, "File " + filePath + " is in an unsupported location; skipping");
             return;
@@ -438,6 +450,8 @@
             basePath = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
         } else if (domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
             basePath = getCacheDir().getCanonicalPath();
+        } else if (domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
+            basePath = getExternalFilesDir(null).getCanonicalPath();
         } else {
             // Not a supported location
             Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index f859599..2fe08f3 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -46,6 +46,7 @@
     public static final String DATA_TREE_TOKEN = "f";
     public static final String DATABASE_TREE_TOKEN = "db";
     public static final String SHAREDPREFS_TREE_TOKEN = "sp";
+    public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
     public static final String CACHE_TREE_TOKEN = "c";
     public static final String SHARED_STORAGE_TOKEN = "shared";
 
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 354a8c4..21995c0 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -25,14 +25,15 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.os.Message;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
-import android.util.Log;
 
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
@@ -81,15 +82,21 @@
     private State mActiveNetworkState = new ActiveNetworkState();
     private State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState();
 
+    private static final String SETUP_WIZARD_PACKAGE = "com.google.android.setupwizard";
+    private boolean mDeviceProvisioned = false;
+    private ProvisioningObserver mProvisioningObserver;
+
     private CaptivePortalTracker(Context context, IConnectivityManager cs) {
         super(TAG);
 
         mContext = context;
         mConnService = cs;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mProvisioningObserver = new ProvisioningObserver();
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
         mContext.registerReceiver(mReceiver, filter);
 
         mServer = Settings.Global.getString(mContext.getContentResolver(),
@@ -106,11 +113,31 @@
         setInitialState(mNoActiveNetworkState);
     }
 
+    private class ProvisioningObserver extends ContentObserver {
+        ProvisioningObserver() {
+            super(new Handler());
+            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.DEVICE_PROVISIONED), false, this);
+            onChange(false); // load initial value
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+        }
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+            // Normally, we respond to CONNECTIVITY_ACTION, allowing time for the change in
+            // connectivity to stabilize, but if the device is not yet provisioned, respond
+            // immediately to speed up transit through the setup wizard.
+            if ((mDeviceProvisioned && action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
+                    || (!mDeviceProvisioned
+                            && action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE))) {
                 NetworkInfo info = intent.getParcelableExtra(
                         ConnectivityManager.EXTRA_NETWORK_INFO);
                 sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info));
@@ -222,8 +249,12 @@
         @Override
         public void enter() {
             if (DBG) log(getName() + "\n");
-            sendMessageDelayed(obtainMessage(CMD_DELAYED_CAPTIVE_CHECK,
-                        ++mDelayedCheckToken, 0), DELAYED_CHECK_INTERVAL_MS);
+            Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
+            if (mDeviceProvisioned) {
+                sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
+            } else {
+                sendMessage(message);
+            }
         }
 
         @Override
@@ -233,13 +264,26 @@
                 case CMD_DELAYED_CAPTIVE_CHECK:
                     if (message.arg1 == mDelayedCheckToken) {
                         InetAddress server = lookupHost(mServer);
-                        if (server != null) {
-                            if (isCaptivePortal(server)) {
-                                if (DBG) log("Captive network " + mNetworkInfo);
+                        boolean captive = server != null && isCaptivePortal(server);
+                        if (captive) {
+                            if (DBG) log("Captive network " + mNetworkInfo);
+                        } else {
+                            if (DBG) log("Not captive network " + mNetworkInfo);
+                        }
+                        if (mDeviceProvisioned) {
+                            if (captive) {
+                                // Setup Wizard will assist the user in connecting to a captive
+                                // portal, so make the notification visible unless during setup
                                 setNotificationVisible(true);
                             }
+                        } else {
+                            Intent intent = new Intent(
+                                    ConnectivityManager.ACTION_CAPTIVE_PORTAL_TEST_COMPLETED);
+                            intent.putExtra(ConnectivityManager.EXTRA_IS_CAPTIVE_PORTAL, captive);
+                            intent.setPackage(SETUP_WIZARD_PACKAGE);
+                            mContext.sendBroadcast(intent);
                         }
-                        if (DBG) log("Not captive network " + mNetworkInfo);
+
                         transitionTo(mActiveNetworkState);
                     }
                     break;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a8a68d0..000c56c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -228,6 +228,21 @@
     public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
     /**
+     * Broadcast Action: The captive portal tracker has finished its test.
+     * Sent only while running Setup Wizard, in lieu of showing a user
+     * notification.
+     * @hide
+     */
+    public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED =
+            "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED";
+    /**
+     * The lookup key for a boolean that indicates whether a captive portal was detected.
+     * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+     * @hide
+     */
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal";
+
+    /**
      * The absence of APN..
      * @hide
      */
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index c757605..9cb904d 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -135,6 +135,18 @@
             builder.append(" operations=").append(operations);
             return builder.toString();
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o instanceof Entry) {
+                final Entry e = (Entry) o;
+                return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes
+                        && rxPackets == e.rxPackets && txBytes == e.txBytes
+                        && txPackets == e.txPackets && operations == e.operations
+                        && iface.equals(e.iface);
+            }
+            return false;
+        }
     }
 
     public NetworkStats(long elapsedRealtime, int initialSize) {
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index ca7fdba..60ec0d7 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -65,6 +65,14 @@
     }
 
     /**
+     * The size, in bytes, of a block on the file system. This corresponds to
+     * the Unix {@code statfs.f_bsize} field.
+     */
+    public long getBlockSizeLong() {
+        return mStat.f_bsize;
+    }
+
+    /**
      * The total number of blocks on the file system. This corresponds to the
      * Unix {@code statfs.f_blocks} field.
      */
@@ -73,6 +81,14 @@
     }
 
     /**
+     * The size, in bytes, of a block on the file system. This corresponds to
+     * the Unix {@code statfs.f_bsize} field.
+     */
+    public long getBlockCountLong() {
+        return mStat.f_blocks;
+    }
+
+    /**
      * The total number of blocks that are free on the file system, including
      * reserved blocks (that are not available to normal applications). This
      * corresponds to the Unix {@code statfs.f_bfree} field. Most applications
@@ -83,10 +99,44 @@
     }
 
     /**
+     * The total number of blocks that are free on the file system, including
+     * reserved blocks (that are not available to normal applications). This
+     * corresponds to the Unix {@code statfs.f_bfree} field. Most applications
+     * will want to use {@link #getAvailableBlocks()} instead.
+     */
+    public long getFreeBlocksLong() {
+        return mStat.f_bfree;
+    }
+
+    /**
+     * The number of bytes that are free on the file system, including
+     * reserved blocks (that are not available to normal applications).
+     */
+    public long getFreeBytes() {
+        return mStat.f_bfree * mStat.f_bsize;
+    }
+
+    /**
      * The number of blocks that are free on the file system and available to
      * applications. This corresponds to the Unix {@code statfs.f_bavail} field.
      */
     public int getAvailableBlocks() {
         return (int) mStat.f_bavail;
     }
+
+    /**
+     * The number of blocks that are free on the file system and available to
+     * applications. This corresponds to the Unix {@code statfs.f_bavail} field.
+     */
+    public long getAvailableBlocksLong() {
+        return mStat.f_bavail;
+    }
+
+    /**
+     * The number of bytes that are free on the file system and available to
+     * applications.
+     */
+    public long getAvailableBytes() {
+        return mStat.f_bavail * mStat.f_bsize;
+    }
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 862a95c..f5e728d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,7 +16,9 @@
 
 package android.os.storage;
 
-import android.app.NotificationManager;
+import static android.net.TrafficStats.MB_IN_BYTES;
+
+import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Environment;
 import android.os.Handler;
@@ -25,6 +27,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -54,20 +57,20 @@
  * {@link android.content.Context#getSystemService(java.lang.String)} with an
  * argument of {@link android.content.Context#STORAGE_SERVICE}.
  */
-
-public class StorageManager
-{
+public class StorageManager {
     private static final String TAG = "StorageManager";
 
+    private final ContentResolver mResolver;
+
     /*
      * Our internal MountService binder reference
      */
-    final private IMountService mMountService;
+    private final IMountService mMountService;
 
     /*
      * The looper target for callbacks
      */
-    Looper mTgtLooper;
+    private final Looper mTgtLooper;
 
     /*
      * Target listener for binder callbacks
@@ -308,16 +311,16 @@
      *
      * @hide
      */
-    public StorageManager(Looper tgtLooper) throws RemoteException {
+    public StorageManager(ContentResolver resolver, Looper tgtLooper) throws RemoteException {
+        mResolver = resolver;
+        mTgtLooper = tgtLooper;
         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
         if (mMountService == null) {
             Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
             return;
         }
-        mTgtLooper = tgtLooper;
     }
 
-
     /**
      * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
      *
@@ -610,4 +613,36 @@
         Log.w(TAG, "No primary storage defined");
         return null;
     }
+
+    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
+    private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
+    private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
+
+    /**
+     * Return the number of available bytes at which the given path is
+     * considered running low on storage.
+     *
+     * @hide
+     */
+    public long getStorageLowBytes(File path) {
+        final long lowPercent = Settings.Global.getInt(mResolver,
+                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
+        final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
+
+        final long maxLowBytes = Settings.Global.getLong(mResolver,
+                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
+
+        return Math.min(lowBytes, maxLowBytes);
+    }
+
+    /**
+     * Return the number of available bytes at which the given path is
+     * considered full.
+     *
+     * @hide
+     */
+    public long getStorageFullBytes(File path) {
+        return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
+                DEFAULT_FULL_THRESHOLD_BYTES);
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 25954b9..8715349 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2671,13 +2671,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_APN);
             MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_REQUIRED);
             MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_HELP_URI);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_NOTIFICATION_TYPE);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_POLLING_SEC);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_RESET_DAY);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_THRESHOLD_BYTES);
-            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_VALUE_KBITSPS);
             MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
             MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
@@ -4706,50 +4699,6 @@
        public static final String TETHER_DUN_APN = "tether_dun_apn";
 
        /**
-        * The bandwidth throttle polling freqency in seconds
-        * @hide
-        */
-       public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec";
-
-       /**
-        * The bandwidth throttle threshold (long)
-        * @hide
-        */
-       public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes";
-
-       /**
-        * The bandwidth throttle value (kbps)
-        * @hide
-        */
-       public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps";
-
-       /**
-        * The bandwidth throttle reset calendar day (1-28)
-        * @hide
-        */
-       public static final String THROTTLE_RESET_DAY = "throttle_reset_day";
-
-       /**
-        * The throttling notifications we should send
-        * @hide
-        */
-       public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
-
-       /**
-        * Help URI for data throttling policy
-        * @hide
-        */
-       public static final String THROTTLE_HELP_URI = "throttle_help_uri";
-
-       /**
-        * The length of time in Sec that we allow our notion of NTP time
-        * to be cached before we refresh it
-        * @hide
-        */
-       public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC =
-               "throttle_max_ntp_cache_age_sec";
-
-       /**
         * USB Mass Storage Enabled
         */
        public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index f8a49e6..651693a 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -78,7 +78,7 @@
                 return _result;
             }
 
-            public int insert(String name, byte[] item) throws RemoteException {
+            public int insert(String name, byte[] item, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
@@ -86,6 +86,7 @@
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
                     _data.writeByteArray(item);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -96,13 +97,14 @@
                 return _result;
             }
 
-            public int del(String name) throws RemoteException {
+            public int del(String name, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_del, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -113,13 +115,14 @@
                 return _result;
             }
 
-            public int exist(String name) throws RemoteException {
+            public int exist(String name, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_exist, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -130,13 +133,14 @@
                 return _result;
             }
 
-            public String[] saw(String name) throws RemoteException {
+            public String[] saw(String name, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 String[] _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_saw, _data, _reply, 0);
                     _reply.readException();
                     int size = _reply.readInt();
@@ -235,13 +239,14 @@
                 return _result;
             }
 
-            public int generate(String name) throws RemoteException {
+            public int generate(String name, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -252,7 +257,7 @@
                 return _result;
             }
 
-            public int import_key(String name, byte[] data) throws RemoteException {
+            public int import_key(String name, byte[] data, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
@@ -260,6 +265,7 @@
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
                     _data.writeByteArray(data);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -324,13 +330,14 @@
                 return _result;
             }
 
-            public int del_key(String name) throws RemoteException {
+            public int del_key(String name, int uid) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 int _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeString(name);
+                    _data.writeInt(uid);
                     mRemote.transact(Stub.TRANSACTION_del_key, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.readInt();
@@ -467,13 +474,13 @@
 
     public byte[] get(String name) throws RemoteException;
 
-    public int insert(String name, byte[] item) throws RemoteException;
+    public int insert(String name, byte[] item, int uid) throws RemoteException;
 
-    public int del(String name) throws RemoteException;
+    public int del(String name, int uid) throws RemoteException;
 
-    public int exist(String name) throws RemoteException;
+    public int exist(String name, int uid) throws RemoteException;
 
-    public String[] saw(String name) throws RemoteException;
+    public String[] saw(String name, int uid) throws RemoteException;
 
     public int reset() throws RemoteException;
 
@@ -485,9 +492,9 @@
 
     public int zero() throws RemoteException;
 
-    public int generate(String name) throws RemoteException;
+    public int generate(String name, int uid) throws RemoteException;
 
-    public int import_key(String name, byte[] data) throws RemoteException;
+    public int import_key(String name, byte[] data, int uid) throws RemoteException;
 
     public byte[] sign(String name, byte[] data) throws RemoteException;
 
@@ -495,7 +502,7 @@
 
     public byte[] get_pubkey(String name) throws RemoteException;
 
-    public int del_key(String name) throws RemoteException;
+    public int del_key(String name, int uid) throws RemoteException;
 
     public int grant(String name, int granteeUid) throws RemoteException;
 
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 3e33e8e..ab8f82f 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -20,10 +20,12 @@
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 
 /**
  * Speech synthesis request that writes the audio to a WAV file.
@@ -39,16 +41,19 @@
     private static final short WAV_FORMAT_PCM = 0x0001;
 
     private final Object mStateLock = new Object();
-    private final File mFileName;
+
     private int mSampleRateInHz;
     private int mAudioFormat;
     private int mChannelCount;
-    private RandomAccessFile mFile;
+
+    private FileChannel mFileChannel;
+
+    private boolean mStarted = false;
     private boolean mStopped = false;
     private boolean mDone = false;
 
-    FileSynthesisCallback(File fileName) {
-        mFileName = fileName;
+    FileSynthesisCallback(FileChannel fileChannel) {
+        mFileChannel = fileChannel;
     }
 
     @Override
@@ -63,54 +68,23 @@
      * Must be called while holding the monitor on {@link #mStateLock}.
      */
     private void cleanUp() {
-        closeFileAndWidenPermissions();
-        if (mFile != null) {
-            mFileName.delete();
-        }
+        closeFile();
     }
 
     /**
      * Must be called while holding the monitor on {@link #mStateLock}.
      */
-    private void closeFileAndWidenPermissions() {
+    private void closeFile() {
         try {
-            if (mFile != null) {
-                mFile.close();
-                mFile = null;
+            if (mFileChannel != null) {
+                mFileChannel.close();
+                mFileChannel = null;
             }
         } catch (IOException ex) {
-            Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
-        }
-
-        try {
-            // Make the written file readable and writeable by everyone.
-            // This allows the app that requested synthesis to read the file.
-            //
-            // Note that the directory this file was written must have already
-            // been world writeable in order it to have been
-            // written to in the first place.
-            FileUtils.setPermissions(mFileName.getAbsolutePath(), 0666, -1, -1); //-rw-rw-rw
-        } catch (SecurityException se) {
-            Log.e(TAG, "Security exception setting rw permissions on : " + mFileName);
+            Log.e(TAG, "Failed to close output file descriptor", ex);
         }
     }
 
-    /**
-     * Checks whether a given file exists, and deletes it if it does.
-     */
-    private boolean maybeCleanupExistingFile(File file) {
-        if (file.exists()) {
-            Log.v(TAG, "File " + file + " exists, deleting.");
-            if (!file.delete()) {
-                Log.e(TAG, "Failed to delete " + file);
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-
     @Override
     public int getMaxBufferSize() {
         return MAX_AUDIO_BUFFER_SIZE;
@@ -132,25 +106,20 @@
                 if (DBG) Log.d(TAG, "Request has been aborted.");
                 return TextToSpeech.ERROR;
             }
-            if (mFile != null) {
+            if (mStarted) {
                 cleanUp();
                 throw new IllegalArgumentException("FileSynthesisRequest.start() called twice");
             }
-
-            if (!maybeCleanupExistingFile(mFileName)) {
-                return TextToSpeech.ERROR;
-            }
-
+            mStarted = true;
             mSampleRateInHz = sampleRateInHz;
             mAudioFormat = audioFormat;
             mChannelCount = channelCount;
+
             try {
-                mFile = new RandomAccessFile(mFileName, "rw");
-                // Reserve space for WAV header
-                mFile.write(new byte[WAV_HEADER_LENGTH]);
+                mFileChannel.write(ByteBuffer.allocate(WAV_HEADER_LENGTH));
                 return TextToSpeech.SUCCESS;
             } catch (IOException ex) {
-                Log.e(TAG, "Failed to open " + mFileName + ": " + ex);
+                Log.e(TAG, "Failed to write wav header to output file descriptor" + ex);
                 cleanUp();
                 return TextToSpeech.ERROR;
             }
@@ -168,15 +137,15 @@
                 if (DBG) Log.d(TAG, "Request has been aborted.");
                 return TextToSpeech.ERROR;
             }
-            if (mFile == null) {
+            if (mFileChannel == null) {
                 Log.e(TAG, "File not open");
                 return TextToSpeech.ERROR;
             }
             try {
-                mFile.write(buffer, offset, length);
+                mFileChannel.write(ByteBuffer.wrap(buffer,  offset,  length));
                 return TextToSpeech.SUCCESS;
             } catch (IOException ex) {
-                Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
+                Log.e(TAG, "Failed to write to output file descriptor", ex);
                 cleanUp();
                 return TextToSpeech.ERROR;
             }
@@ -197,21 +166,21 @@
                 if (DBG) Log.d(TAG, "Request has been aborted.");
                 return TextToSpeech.ERROR;
             }
-            if (mFile == null) {
+            if (mFileChannel == null) {
                 Log.e(TAG, "File not open");
                 return TextToSpeech.ERROR;
             }
             try {
                 // Write WAV header at start of file
-                mFile.seek(0);
-                int dataLength = (int) (mFile.length() - WAV_HEADER_LENGTH);
-                mFile.write(
+                mFileChannel.position(0);
+                int dataLength = (int) (mFileChannel.size() - WAV_HEADER_LENGTH);
+                mFileChannel.write(
                         makeWavHeader(mSampleRateInHz, mAudioFormat, mChannelCount, dataLength));
-                closeFileAndWidenPermissions();
+                closeFile();
                 mDone = true;
                 return TextToSpeech.SUCCESS;
             } catch (IOException ex) {
-                Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
+                Log.e(TAG, "Failed to write to output file descriptor", ex);
                 cleanUp();
                 return TextToSpeech.ERROR;
             }
@@ -226,7 +195,7 @@
         }
     }
 
-    private byte[] makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
+    private ByteBuffer makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
             int dataLength) {
         // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
         int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
@@ -251,8 +220,9 @@
         header.putShort(bitsPerSample);
         header.put(new byte[]{ 'd', 'a', 't', 'a' });
         header.putInt(dataLength);
+        header.flip();
 
-        return headerBuf;
+        return header;
     }
 
 }
diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl
index 6982029..b7bc70c 100644
--- a/core/java/android/speech/tts/ITextToSpeechService.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechService.aidl
@@ -18,6 +18,7 @@
 
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
 import android.speech.tts.ITextToSpeechCallback;
 
 /**
@@ -44,11 +45,12 @@
      * @param callingInstance a binder representing the identity of the calling
      *        TextToSpeech object.
      * @param text The text to synthesize.
-     * @param filename The file to write the synthesized audio to.
+     * @param fileDescriptor The file descriptor to write the synthesized audio to. Has to be
+              writable.
      * @param param Request parameters.
      */
-    int synthesizeToFile(in IBinder callingInstance, in String text,
-        in String filename, in Bundle params);
+    int synthesizeToFileDescriptor(in IBinder callingInstance, in String text,
+        in ParcelFileDescriptor fileDescriptor, in Bundle params);
 
     /**
      * Plays an existing audio resource.
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c1af7a5..73d400e 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -27,11 +27,15 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -1225,8 +1229,29 @@
         return runAction(new Action<Integer>() {
             @Override
             public Integer run(ITextToSpeechService service) throws RemoteException {
-                return service.synthesizeToFile(getCallerIdentity(), text, filename,
-                        getParams(params));
+                ParcelFileDescriptor fileDescriptor;
+                int returnValue;
+                try {
+                    File file = new File(filename);
+                    if(file.exists() && !file.canWrite()) {
+                        Log.e(TAG, "Can't write to " + filename);
+                        return ERROR;
+                    }
+                    fileDescriptor = ParcelFileDescriptor.open(file,
+                            ParcelFileDescriptor.MODE_WRITE_ONLY |
+                            ParcelFileDescriptor.MODE_CREATE |
+                            ParcelFileDescriptor.MODE_TRUNCATE);
+                    returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
+                            fileDescriptor, getParams(params));
+                    fileDescriptor.close();
+                    return returnValue;
+                } catch (FileNotFoundException e) {
+                    Log.e(TAG, "Opening file " + filename + " failed", e);
+                    return ERROR;
+                } catch (IOException e) {
+                    Log.e(TAG, "Closing file " + filename + " failed", e);
+                    return ERROR;
+                }
             }
         }, ERROR, "synthesizeToFile");
     }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 4054740..1bcf3e0 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -26,6 +26,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.provider.Settings;
@@ -33,7 +34,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Set;
@@ -654,19 +656,19 @@
         }
     }
 
-    private class SynthesisToFileSpeechItem extends SynthesisSpeechItem {
-        private final File mFile;
+    private class SynthesisToFileSpeechDescriptorItem extends SynthesisSpeechItem {
+        private final FileDescriptor mFileDescriptor;
 
-        public SynthesisToFileSpeechItem(Object callerIdentity, int callerUid, int callerPid,
-                Bundle params, String text,
-                File file) {
+        public SynthesisToFileSpeechDescriptorItem(Object callerIdentity, int callerUid,
+                int callerPid, Bundle params, String text, FileDescriptor fileDescriptor) {
             super(callerIdentity, callerUid, callerPid, params, text);
-            mFile = file;
+            mFileDescriptor = fileDescriptor;
         }
 
         @Override
         protected AbstractSynthesisCallback createSynthesisCallback() {
-            return new FileSynthesisCallback(mFile);
+            FileOutputStream fileOutputStream = new FileOutputStream(mFileDescriptor);
+            return new FileSynthesisCallback(fileOutputStream.getChannel());
         }
 
         @Override
@@ -797,15 +799,15 @@
         }
 
         @Override
-        public int synthesizeToFile(IBinder caller, String text, String filename,
-                Bundle params) {
-            if (!checkNonNull(caller, text, filename, params)) {
+        public int synthesizeToFileDescriptor(IBinder caller, String text, ParcelFileDescriptor
+                fileDescriptor, Bundle params) {
+            if (!checkNonNull(caller, text, fileDescriptor, params)) {
                 return TextToSpeech.ERROR;
             }
 
-            File file = new File(filename);
-            SpeechItem item = new SynthesisToFileSpeechItem(caller, Binder.getCallingUid(),
-                    Binder.getCallingPid(), params, text, file);
+            SpeechItem item = new SynthesisToFileSpeechDescriptorItem(caller, Binder.getCallingUid(),
+                    Binder.getCallingPid(), params, text,
+                    fileDescriptor.getFileDescriptor());
             return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
         }
 
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index 0c8cbe6..0635559 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -20,9 +20,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+
 import junit.framework.TestCase;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 /**
  * Extend this if you need to access Resources or other things that depend on Activity Context.
@@ -152,11 +154,11 @@
      * @throws IllegalAccessException
      */
     protected void scrubClass(final Class<?> testCaseClass)
-    throws IllegalAccessException {
+            throws IllegalAccessException {
         final Field[] fields = getClass().getDeclaredFields();
         for (Field field : fields) {
-            final Class<?> fieldClass = field.getDeclaringClass();
-            if (testCaseClass.isAssignableFrom(fieldClass) && !field.getType().isPrimitive()) {
+            if (!field.getType().isPrimitive() &&
+                    !Modifier.isStatic(field.getModifiers())) {
                 try {
                     field.setAccessible(true);
                     field.set(this, null);
@@ -170,6 +172,4 @@
             }
         }
     }
-
-
 }
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 1508d10..2ab9bf8 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -757,7 +757,7 @@
                     break;
 
                 case EASY_EDIT_SPAN:
-                    readSpan(p, sp, new EasyEditSpan());
+                    readSpan(p, sp, new EasyEditSpan(p));
                     break;
 
                 case LOCALE_SPAN:
diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java
index 2feb719..03b4f60 100644
--- a/core/java/android/text/style/EasyEditSpan.java
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.app.PendingIntent;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
@@ -25,12 +26,62 @@
  * Provides an easy way to edit a portion of text.
  * <p>
  * The {@link TextView} uses this span to allow the user to delete a chuck of text in one click.
- * the text. {@link TextView} removes this span as soon as the text is edited, or the cursor moves.
+ * <p>
+ * {@link TextView} removes the span when the user deletes the whole text or modifies it.
+ * <p>
+ * This span can be also used to receive notification when the user deletes or modifies the text;
  */
 public class EasyEditSpan implements ParcelableSpan {
 
+    /**
+     * The extra key field in the pending intent that describes how the text changed.
+     *
+     * @see #TEXT_DELETED
+     * @see #TEXT_MODIFIED
+     * @see #getPendingIntent()
+     */
+    public static final String EXTRA_TEXT_CHANGED_TYPE =
+            "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
+
+    /**
+     * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is deleted.
+     */
+    public static final int TEXT_DELETED = 1;
+
+    /**
+     * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is modified.
+     */
+    public static final int TEXT_MODIFIED = 2;
+
+    private final PendingIntent mPendingIntent;
+
+    private boolean mDeleteEnabled;
+
+    /**
+     * Creates the span. No intent is sent when the wrapped text is modified or
+     * deleted.
+     */
     public EasyEditSpan() {
-        // Empty
+        mPendingIntent = null;
+        mDeleteEnabled = true;
+    }
+
+    /**
+     * @param pendingIntent The intent will be sent when the wrapped text is deleted or modified.
+     *                      When the pending intent is sent, {@link #EXTRA_TEXT_CHANGED_TYPE} is
+     *                      added in the intent to describe how the text changed.
+     */
+    public EasyEditSpan(PendingIntent pendingIntent) {
+        mPendingIntent = pendingIntent;
+        mDeleteEnabled = true;
+    }
+
+    /**
+     * Constructor called from {@link TextUtils} to restore the span.
+     */
+    public EasyEditSpan(Parcel source) {
+        mPendingIntent = source.readParcelable(null);
+        mDeleteEnabled = (source.readByte() == 1);
     }
 
     @Override
@@ -40,11 +91,39 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        // Empty
+        dest.writeParcelable(mPendingIntent, 0);
+        dest.writeByte((byte) (mDeleteEnabled ? 1 : 0));
     }
 
     @Override
     public int getSpanTypeId() {
         return TextUtils.EASY_EDIT_SPAN;
     }
+
+    /**
+     * @return True if the {@link TextView} should offer the ability to delete the text.
+     *
+     * @hide
+     */
+    public boolean isDeleteEnabled() {
+        return mDeleteEnabled;
+    }
+
+    /**
+     * Enables or disables the deletion of the text.
+     *
+     * @hide
+     */
+    public void setDeleteEnabled(boolean value) {
+        mDeleteEnabled = value;
+    }
+
+    /**
+     * @return the pending intent to send when the wrapped text is deleted or modified.
+     *
+     * @hide
+     */
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
+    }
 }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index b661748..f28e4b5 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -693,7 +693,7 @@
             // At this time Surface Flinger won't send us vsyncs for secondary displays
             // but that could change in the future so let's log a message to help us remember
             // that we need to fix this.
-            if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) {
+            if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                 Log.d(TAG, "Received vsync from secondary display, but we don't support "
                         + "this case yet.  Choreographer needs a way to explicitly request "
                         + "vsync for a specific display to ensure it doesn't lose track "
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 758abb5..e6a7950 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -437,6 +437,20 @@
     }
 
     /**
+     * @hide
+     * Return a rectangle defining the insets of the overscan region of the display.
+     * Each field of the rectangle is the number of pixels the overscan area extends
+     * into the display on that side.
+     */
+    public void getOverscanInsets(Rect outRect) {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
+                    mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
+        }
+    }
+
+    /**
      * Returns the rotation of the screen from its "natural" orientation.
      * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
      * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index a919ffc..4dade20 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -102,7 +102,7 @@
      * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
      * timebase.
      * @param builtInDisplayId The surface flinger built-in display id such as
-     * {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}.
+     * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_MAIN}.
      * @param frame The frame number.  Increases by one for each vertical sync interval.
      */
     public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
@@ -114,7 +114,7 @@
      * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
      * timebase.
      * @param builtInDisplayId The surface flinger built-in display id such as
-     * {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}.
+     * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_HDMI}.
      * @param connected True if the display is connected, false if it disconnected.
      */
     public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 305fd5c..9fcd9b1 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -109,6 +109,30 @@
     public int logicalHeight;
 
     /**
+     * @hide
+     * Number of overscan pixels on the left side of the display.
+     */
+    public int overscanLeft;
+
+    /**
+     * @hide
+     * Number of overscan pixels on the top side of the display.
+     */
+    public int overscanTop;
+
+    /**
+     * @hide
+     * Number of overscan pixels on the right side of the display.
+     */
+    public int overscanRight;
+
+    /**
+     * @hide
+     * Number of overscan pixels on the bottom side of the display.
+     */
+    public int overscanBottom;
+
+    /**
      * The rotation of the display relative to its natural orientation.
      * May be one of {@link android.view.Surface#ROTATION_0},
      * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
@@ -196,6 +220,10 @@
                 && largestNominalAppHeight == other.largestNominalAppHeight
                 && logicalWidth == other.logicalWidth
                 && logicalHeight == other.logicalHeight
+                && overscanLeft == other.overscanLeft
+                && overscanTop == other.overscanTop
+                && overscanRight == other.overscanRight
+                && overscanBottom == other.overscanBottom
                 && rotation == other.rotation
                 && refreshRate == other.refreshRate
                 && logicalDensityDpi == other.logicalDensityDpi
@@ -222,6 +250,10 @@
         largestNominalAppHeight = other.largestNominalAppHeight;
         logicalWidth = other.logicalWidth;
         logicalHeight = other.logicalHeight;
+        overscanLeft = other.overscanLeft;
+        overscanTop = other.overscanTop;
+        overscanRight = other.overscanRight;
+        overscanBottom = other.overscanBottom;
         rotation = other.rotation;
         refreshRate = other.refreshRate;
         logicalDensityDpi = other.logicalDensityDpi;
@@ -243,6 +275,10 @@
         largestNominalAppHeight = source.readInt();
         logicalWidth = source.readInt();
         logicalHeight = source.readInt();
+        overscanLeft = source.readInt();
+        overscanTop = source.readInt();
+        overscanRight = source.readInt();
+        overscanBottom = source.readInt();
         rotation = source.readInt();
         refreshRate = source.readFloat();
         logicalDensityDpi = source.readInt();
@@ -265,6 +301,10 @@
         dest.writeInt(largestNominalAppHeight);
         dest.writeInt(logicalWidth);
         dest.writeInt(logicalHeight);
+        dest.writeInt(overscanLeft);
+        dest.writeInt(overscanTop);
+        dest.writeInt(overscanRight);
+        dest.writeInt(overscanBottom);
         dest.writeInt(rotation);
         dest.writeFloat(refreshRate);
         dest.writeInt(logicalDensityDpi);
@@ -318,18 +358,55 @@
     // For debugging purposes
     @Override
     public String toString() {
-        return "DisplayInfo{\"" + name + "\", app " + appWidth + " x " + appHeight
-                + ", real " + logicalWidth + " x " + logicalHeight
-                + ", largest app " + largestNominalAppWidth + " x " + largestNominalAppHeight
-                + ", smallest app " + smallestNominalAppWidth + " x " + smallestNominalAppHeight
-                + ", " + refreshRate + " fps"
-                + ", rotation " + rotation
-                + ", density " + logicalDensityDpi
-                + ", " + physicalXDpi + " x " + physicalYDpi + " dpi"
-                + ", layerStack " + layerStack
-                + ", type " + Display.typeToString(type)
-                + ", address " + address
-                + flagsToString(flags) + "}";
+        StringBuilder sb = new StringBuilder();
+        sb.append("DisplayInfo{\"");
+        sb.append(name);
+        sb.append("\", app ");
+        sb.append(appWidth);
+        sb.append(" x ");
+        sb.append(appHeight);
+        sb.append(", real ");
+        sb.append(logicalWidth);
+        sb.append(" x ");
+        sb.append(logicalHeight);
+        if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
+            sb.append(", overscan (");
+            sb.append(overscanLeft);
+            sb.append(",");
+            sb.append(overscanTop);
+            sb.append(",");
+            sb.append(overscanRight);
+            sb.append(",");
+            sb.append(overscanBottom);
+            sb.append(")");
+        }
+        sb.append(", largest app ");
+        sb.append(largestNominalAppWidth);
+        sb.append(" x ");
+        sb.append(largestNominalAppHeight);
+        sb.append(", smallest app ");
+        sb.append(smallestNominalAppWidth);
+        sb.append(" x ");
+        sb.append(smallestNominalAppHeight);
+        sb.append(", ");
+        sb.append(refreshRate);
+        sb.append(" fps, rotation");
+        sb.append(rotation);
+        sb.append(", density ");
+        sb.append(logicalDensityDpi);
+        sb.append(" (");
+        sb.append(physicalXDpi);
+        sb.append(" x ");
+        sb.append(physicalYDpi);
+        sb.append(") dpi, layerStack ");
+        sb.append(layerStack);
+        sb.append(", type ");
+        sb.append(Display.typeToString(type));
+        sb.append(", address ");
+        sb.append(address);
+        sb.append(flagsToString(flags));
+        sb.append("}");
+        return sb.toString();
     }
 
     private static String flagsToString(int flags) {
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index e996e67..3bad98e 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -19,13 +19,109 @@
 import android.graphics.Matrix;
 
 /**
- * A display lists records a series of graphics related operation and can replay
+ * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
- * {@link android.graphics.Canvas}. Replaying the operations from a display list
- * avoids executing views drawing code on every frame, and is thus much more
- * efficient.
+ * {@link HardwareCanvas}. Replaying the operations from a display list avoids
+ * executing application code on every frame, and is thus much more efficient.</p>
  *
- * @hide 
+ * <p>Display lists are used internally for all views by default, and are not
+ * typically used directly. One reason to consider using a display is a custom
+ * {@link View} implementation that needs to issue a large number of drawing commands.
+ * When the view invalidates, all the drawing commands must be reissued, even if
+ * large portions of the drawing command stream stay the same frame to frame, which
+ * can become a performance bottleneck. To solve this issue, a custom View might split
+ * its content into several display lists. A display list is updated only when its
+ * content, and only its content, needs to be updated.</p>
+ *
+ * <p>A text editor might for instance store each paragraph into its own display list.
+ * Thus when the user inserts or removes characters, only the display list of the
+ * affected paragraph needs to be recorded again.</p>
+ *
+ * <h3>Hardware acceleration</h3>
+ * <p>Display lists can only be replayed using a {@link HardwareCanvas}. They are not
+ * supported in software. Always make sure that the {@link android.graphics.Canvas}
+ * you are using to render a display list is hardware accelerated using
+ * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
+ *
+ * <h3>Creating a display list</h3>
+ * <pre class="prettyprint">
+ *     HardwareRenderer renderer = myView.getHardwareRenderer();
+ *     if (renderer != null) {
+ *         DisplayList displayList = renderer.createDisplayList();
+ *         HardwareCanvas canvas = displayList.start(width, height);
+ *         try {
+ *             // Draw onto the canvas
+ *             // For instance: canvas.drawBitmap(...);
+ *         } finally {
+ *             displayList.end();
+ *         }
+ *     }
+ * </pre>
+ *
+ * <h3>Rendering a display list on a View</h3>
+ * <pre class="prettyprint">
+ *     protected void onDraw(Canvas canvas) {
+ *         if (canvas.isHardwareAccelerated()) {
+ *             HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
+ *             hardwareCanvas.drawDisplayList(mDisplayList);
+ *         }
+ *     }
+ * </pre>
+ *
+ * <h3>Releasing resources</h3>
+ * <p>This step is not mandatory but recommended if you want to release resources
+ * held by a display list as soon as possible.</p>
+ * <pre class="prettyprint">
+ *     // Mark this display list invalid, it cannot be used for drawing anymore,
+ *     // and release resources held by this display list
+ *     displayList.clear();
+ * </pre>
+ *
+ * <h3>Properties</h3>
+ * <p>In addition, a display list offers several properties, such as
+ * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
+ * the drawing commands recorded within. For instance, these properties can be used
+ * to move around a large number of images without re-issuing all the individual
+ * <code>drawBitmap()</code> calls.</p>
+ *
+ * <pre class="prettyprint">
+ *     private void createDisplayList() {
+ *         HardwareRenderer renderer = getHardwareRenderer();
+ *         if (renderer != null) {
+ *             mDisplayList = renderer.createDisplayList();
+ *             HardwareCanvas canvas = mDisplayList.start(width, height);
+ *             try {
+ *                 for (Bitmap b : mBitmaps) {
+ *                     canvas.drawBitmap(b, 0.0f, 0.0f, null);
+ *                     canvas.translate(0.0f, b.getHeight());
+ *                 }
+ *             } finally {
+ *                 displayList.end();
+ *             }
+ *         }
+ *     }
+ *
+ *     protected void onDraw(Canvas canvas) {
+ *         if (canvas.isHardwareAccelerated()) {
+ *             HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
+ *             hardwareCanvas.drawDisplayList(mDisplayList);
+ *         }
+ *     }
+ *
+ *     private void moveContentBy(int x) {
+ *          // This will move all the bitmaps recorded inside the display list
+ *          // by x pixels to the right and redraw this view. All the commands
+ *          // recorded in createDisplayList() won't be re-issued, only onDraw()
+ *          // will be invoked and will execute very quickly
+ *          mDisplayList.offsetLeftAndRight(x);
+ *          invalidate();
+ *     }
+ * </pre>
+ *
+ * <h3>Threading</h3>
+ * <p>Display lists must be created on and manipulated from the UI thread only.</p>
+ *
+ * @hide
  */
 public abstract class DisplayList {
     private boolean mDirty;
@@ -36,6 +132,8 @@
      * When this flag is set, draw operations lying outside of the bounds of the
      * display list will be culled early. It is recommeneded to always set this
      * flag.
+     *
+     * @hide
      */
     public static final int FLAG_CLIP_CHILDREN = 0x1;
 
@@ -44,14 +142,18 @@
     /**
      * Indicates that the display list is done drawing.
      * 
-     * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)  
+     * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+     *
+     * @hide
      */
     public static final int STATUS_DONE = 0x0;
 
     /**
      * Indicates that the display list needs another drawing pass.
      * 
-     * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) 
+     * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+     *
+     * @hide
      */
     public static final int STATUS_DRAW = 0x1;
 
@@ -59,7 +161,9 @@
      * Indicates that the display list needs to re-execute its GL functors.
      * 
      * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) 
-     * @see HardwareCanvas#callDrawGLFunction(int) 
+     * @see HardwareCanvas#callDrawGLFunction(int)
+     *
+     * @hide
      */
     public static final int STATUS_INVOKE = 0x2;
 
@@ -67,53 +171,79 @@
      * Indicates that the display list performed GL drawing operations.
      *
      * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+     *
+     * @hide
      */
     public static final int STATUS_DREW = 0x4;
 
     /**
      * Starts recording the display list. All operations performed on the
      * returned canvas are recorded and stored in this display list.
-     * 
+     *
+     * Calling this method will mark the display list invalid until
+     * {@link #end()} is called. Only valid display lists can be replayed.
+     *
+     * @param width The width of the display list's viewport
+     * @param height The height of the display list's viewport
+     *
      * @return A canvas to record drawing operations.
+     *
+     * @see #end()
+     * @see #isValid()
      */
-    public abstract HardwareCanvas start();
+    public abstract HardwareCanvas start(int width, int height);
 
     /**
      * Ends the recording for this display list. A display list cannot be
-     * replayed if recording is not finished. 
+     * replayed if recording is not finished. Calling this method marks
+     * the display list valid and {@link #isValid()} will return true.
+     *
+     * @see #start(int, int)
+     * @see #isValid()
      */
     public abstract void end();
 
     /**
-     * Invalidates the display list, indicating that it should be repopulated
-     * with new drawing commands prior to being used again. Calling this method
-     * causes calls to {@link #isValid()} to return <code>false</code>.
-     */
-    public abstract void invalidate();
-
-    /**
-     * Clears additional resources held onto by this display list. You should
-     * only invoke this method after {@link #invalidate()}.
+     * Clears resources held onto by this display list. After calling this method
+     * {@link #isValid()} will return false.
+     *
+     * @see #isValid()
      */
     public abstract void clear();
 
     /**
-     * Sets the dirty flag. When a display list is dirty, both
-     * {@link #invalidate()} and {@link #clear()} should be invoked whenever
-     * possible.
-     *
-     * @param dirty True to mark the display list dirty, false otherwise
+     * Sets the dirty flag. When a display list is dirty, {@link #clear()} should
+     * be invoked whenever possible.
      *
      * @see #isDirty()
+     * @see #clear()
+     *
+     * @hide
      */
-    public void setDirty(boolean dirty) {
-        mDirty = dirty;
+    public void markDirty() {
+        mDirty = true;
+    }
+
+    /**
+     * Removes the dirty flag. This method can be used to cancel a cleanup
+     * previously scheduled by setting the dirty flag.
+     *
+     * @see #isDirty()
+     * @see #clear()
+     *
+     * @hide
+     */
+    protected void clearDirty() {
+        mDirty = false;
     }
 
     /**
      * Indicates whether the display list is dirty.
      *
-     * @see #setDirty(boolean)
+     * @see #markDirty()
+     * @see #clear()
+     *
+     * @hide
      */
     public boolean isDirty() {
         return mDirty;
@@ -131,6 +261,8 @@
      * Return the amount of memory used by this display list.
      * 
      * @return The size of this display list in bytes
+     *
+     * @hide
      */
     public abstract int getSize();
 
@@ -139,228 +271,412 @@
     ///////////////////////////////////////////////////////////////////////////
 
     /**
-     * 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
+     * Set the caching property on the display list, which indicates whether the display list
+     * holds a layer. Layer display lists 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.
+     * @param caching true if the display list represents a hardware layer, false otherwise.
+     *
+     * @hide
      */
     public abstract void setCaching(boolean caching);
 
     /**
-     * Set whether the DisplayList should clip itself to its bounds. This property is controlled by
+     * Set whether the display list 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
+     * @param clipChildren true if the display list should clip to its bounds
      */
     public abstract void setClipChildren(boolean clipChildren);
 
     /**
-     * Set the static matrix on the DisplayList. This matrix exists if a custom ViewGroup
-     * overrides
-     * {@link ViewGroup#getChildStaticTransformation(View, android.view.animation.Transformation)}
-     * and also has {@link ViewGroup#setStaticTransformationsEnabled(boolean)} set to true.
-     * This matrix will be concatenated with any other matrices in the DisplayList to position
-     * the view appropriately.
+     * Set the static matrix on the display list. The specified matrix is combined with other
+     * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
      *
-     * @param matrix The matrix
+     * @param matrix A transform matrix to apply to this display list
+     *
+     * @see #getMatrix(android.graphics.Matrix)
+     * @see #getMatrix()
      */
-    public abstract void setStaticMatrix(Matrix matrix);
+    public abstract void setMatrix(Matrix matrix);
 
     /**
-     * Set the Animation matrix on the DisplayList. This matrix exists if an Animation is
-     * currently playing on a View, and is set on the DisplayList during at draw() time. When
+     * Returns the static matrix set on this display list.
+     *
+     * @return A new {@link Matrix} instance populated with this display list's static
+     *         matrix
+     *
+     * @see #getMatrix(android.graphics.Matrix)
+     * @see #setMatrix(android.graphics.Matrix)
+     */
+    public Matrix getMatrix() {
+        return getMatrix(new Matrix());
+    }
+
+    /**
+     * Copies this display list's static matrix into the specified matrix.
+     *
+     * @param matrix The {@link Matrix} instance in which to copy this display
+     *               list's static matrix. Cannot be null
+     *
+     * @return The <code>matrix</code> parameter, for convenience
+     *
+     * @see #getMatrix()
+     * @see #setMatrix(android.graphics.Matrix)
+     */
+    public abstract Matrix getMatrix(Matrix matrix);
+
+    /**
+     * Set the Animation matrix on the display list. This matrix exists if an Animation is
+     * currently playing on a View, and is set on the display list during at draw() time. When
      * the Animation finishes, the matrix should be cleared by sending <code>null</code>
      * for the matrix parameter.
      *
      * @param matrix The matrix, null indicates that the matrix should be cleared.
+     *
+     * @hide
      */
     public abstract void setAnimationMatrix(Matrix matrix);
 
     /**
-     * Sets the alpha value for the DisplayList
+     * Sets the translucency level for the display list.
      *
-     * @param alpha The translucency of the DisplayList
+     * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
+     *
      * @see View#setAlpha(float)
+     * @see #getAlpha()
      */
     public abstract void setAlpha(float alpha);
 
     /**
-     * Sets whether the DisplayList renders content which overlaps. Non-overlapping rendering
-     * can use a fast path for alpha that avoids rendering to an offscreen buffer.
+     * Returns the translucency level of this display list.
      *
-     * @param hasOverlappingRendering
+     * @return A value between 0.0f and 1.0f
+     *
+     * @see #setAlpha(float)
+     */
+    public abstract float getAlpha();
+
+    /**
+     * Sets whether the display list renders content which overlaps. Non-overlapping rendering
+     * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default
+     * display lists consider they do not have overlapping content.
+     *
+     * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
+     *                                true otherwise.
+     *
      * @see android.view.View#hasOverlappingRendering()
+     * @see #hasOverlappingRendering()
      */
     public abstract void setHasOverlappingRendering(boolean hasOverlappingRendering);
 
     /**
-     * Sets the translationX value for the DisplayList
+     * Indicates whether the content of this display list overlaps.
      *
-     * @param translationX The translationX value of the DisplayList
+     * @return True if this display list renders content which overlaps, false otherwise.
+     *
+     * @see #setHasOverlappingRendering(boolean)
+     */
+    public abstract boolean hasOverlappingRendering();
+
+    /**
+     * Sets the translation value for the display list on the X axis
+     *
+     * @param translationX The X axis translation value of the display list, in pixels
+     *
      * @see View#setTranslationX(float)
+     * @see #getTranslationX()
      */
     public abstract void setTranslationX(float translationX);
 
     /**
-     * Sets the translationY value for the DisplayList
+     * Returns the translation value for this display list on the X axis, in pixels.
      *
-     * @param translationY The translationY value of the DisplayList
+     * @see #setTranslationX(float)
+     */
+    public abstract float getTranslationX();
+
+    /**
+     * Sets the translation value for the display list on the Y axis
+     *
+     * @param translationY The Y axis translation value of the display list, in pixels
+     *
      * @see View#setTranslationY(float)
+     * @see #getTranslationY()
      */
     public abstract void setTranslationY(float translationY);
 
     /**
-     * Sets the rotation value for the DisplayList
+     * Returns the translation value for this display list on the Y axis, in pixels.
      *
-     * @param rotation The rotation value of the DisplayList
+     * @see #setTranslationY(float)
+     */
+    public abstract float getTranslationY();
+
+    /**
+     * Sets the rotation value for the display list around the Z axis
+     *
+     * @param rotation The rotation value of the display list, in degrees
+     *
      * @see View#setRotation(float)
+     * @see #getRotation()
      */
     public abstract void setRotation(float rotation);
 
     /**
-     * Sets the rotationX value for the DisplayList
+     * Returns the rotation value for this display list around the Z axis, in degrees.
      *
-     * @param rotationX The rotationX value of the DisplayList
+     * @see #setRotation(float)
+     */
+    public abstract float getRotation();
+
+    /**
+     * Sets the rotation value for the display list around the X axis
+     *
+     * @param rotationX The rotation value of the display list, in degrees
+     *
      * @see View#setRotationX(float)
+     * @see #getRotationX()
      */
     public abstract void setRotationX(float rotationX);
 
     /**
-     * Sets the rotationY value for the DisplayList
+     * Returns the rotation value for this display list around the X axis, in degrees.
      *
-     * @param rotationY The rotationY value of the DisplayList
+     * @see #setRotationX(float)
+     */
+    public abstract float getRotationX();
+
+    /**
+     * Sets the rotation value for the display list around the Y axis
+     *
+     * @param rotationY The rotation value of the display list, in degrees
+     *
      * @see View#setRotationY(float)
+     * @see #getRotationY()
      */
     public abstract void setRotationY(float rotationY);
 
     /**
-     * Sets the scaleX value for the DisplayList
+     * Returns the rotation value for this display list around the Y axis, in degrees.
      *
-     * @param scaleX The scaleX value of the DisplayList
+     * @see #setRotationY(float)
+     */
+    public abstract float getRotationY();
+
+    /**
+     * Sets the scale value for the display list on the X axis
+     *
+     * @param scaleX The scale value of the display list
+     *
      * @see View#setScaleX(float)
+     * @see #getScaleX()
      */
     public abstract void setScaleX(float scaleX);
 
     /**
-     * Sets the scaleY value for the DisplayList
+     * Returns the scale value for this display list on the X axis.
      *
-     * @param scaleY The scaleY value of the DisplayList
+     * @see #setScaleX(float)
+     */
+    public abstract float getScaleX();
+
+    /**
+     * Sets the scale value for the display list on the Y axis
+     *
+     * @param scaleY The scale value of the display list
+     *
      * @see View#setScaleY(float)
+     * @see #getScaleY()
      */
     public abstract void setScaleY(float scaleY);
 
     /**
-     * Sets all of the transform-related values of the View onto the DisplayList
+     * Returns the scale value for this display list on the Y axis.
      *
-     * @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
+     * @see #setScaleY(float)
+     */
+    public abstract float getScaleY();
+
+    /**
+     * Sets all of the transform-related values of the display list
+     *
+     * @param alpha The alpha value of the display list
+     * @param translationX The translationX value of the display list
+     * @param translationY The translationY value of the display list
+     * @param rotation The rotation value of the display list
+     * @param rotationX The rotationX value of the display list
+     * @param rotationY The rotationY value of the display list
+     * @param scaleX The scaleX value of the display list
+     * @param scaleY The scaleY value of the display list
+     *
+     * @hide
      */
     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
+     * Sets the pivot value for the display list on the X axis
      *
-     * @param pivotX The pivotX value of the DisplayList
+     * @param pivotX The pivot value of the display list on the X axis, in pixels
+     *
      * @see View#setPivotX(float)
+     * @see #getPivotX()
      */
     public abstract void setPivotX(float pivotX);
 
     /**
-     * Sets the pivotY value for the DisplayList
+     * Returns the pivot value for this display list on the X axis, in pixels.
      *
-     * @param pivotY The pivotY value of the DisplayList
+     * @see #setPivotX(float)
+     */
+    public abstract float getPivotX();
+
+    /**
+     * Sets the pivot value for the display list on the Y axis
+     *
+     * @param pivotY The pivot value of the display list on the Y axis, in pixels
+     *
      * @see View#setPivotY(float)
+     * @see #getPivotY()
      */
     public abstract void setPivotY(float pivotY);
 
     /**
-     * Sets the camera distance for the DisplayList
+     * Returns the pivot value for this display list on the Y axis, in pixels.
      *
-     * @param distance The distance in z of the camera of the DisplayList
+     * @see #setPivotY(float)
+     */
+    public abstract float getPivotY();
+
+    /**
+     * Sets the camera distance for the display list. Refer to
+     * {@link View#setCameraDistance(float)} for more information on how to
+     * use this property.
+     *
+     * @param distance The distance in Z of the camera of the display list
+     *
      * @see View#setCameraDistance(float)
+     * @see #getCameraDistance()
      */
     public abstract void setCameraDistance(float distance);
 
     /**
-     * Sets the left value for the DisplayList
+     * Returns the distance in Z of the camera of the display list.
      *
-     * @param left The left value of the DisplayList
+     * @see #setCameraDistance(float)
+     */
+    public abstract float getCameraDistance();
+
+    /**
+     * Sets the left position for the display list.
+     *
+     * @param left The left position, in pixels, of the display list
+     *
      * @see View#setLeft(int)
+     * @see #getLeft()
      */
     public abstract void setLeft(int left);
 
     /**
-     * Sets the top value for the DisplayList
+     * Returns the left position for the display list in pixels.
      *
-     * @param top The top value of the DisplayList
+     * @see #setLeft(int)
+     */
+    public abstract float getLeft();
+
+    /**
+     * Sets the top position for the display list.
+     *
+     * @param top The top position, in pixels, of the display list
+     *
      * @see View#setTop(int)
+     * @see #getTop()
      */
     public abstract void setTop(int top);
 
     /**
-     * Sets the right value for the DisplayList
+     * Returns the top position for the display list in pixels.
      *
-     * @param right The right value of the DisplayList
+     * @see #setTop(int)
+     */
+    public abstract float getTop();
+
+    /**
+     * Sets the right position for the display list.
+     *
+     * @param right The right position, in pixels, of the display list
+     *
      * @see View#setRight(int)
+     * @see #getRight()
      */
     public abstract void setRight(int right);
 
     /**
-     * Sets the bottom value for the DisplayList
+     * Returns the right position for the display list in pixels.
      *
-     * @param bottom The bottom value of the DisplayList
+     * @see #setRight(int)
+     */
+    public abstract float getRight();
+
+    /**
+     * Sets the bottom position for the display list.
+     *
+     * @param bottom The bottom position, in pixels, of the display list
+     *
      * @see View#setBottom(int)
+     * @see #getBottom()
      */
     public abstract void setBottom(int bottom);
 
     /**
-     * Sets the left and top values for the DisplayList
+     * Returns the bottom position for the display list in pixels.
      *
-     * @param left The left value of the DisplayList
-     * @param top The top value of the DisplayList
-     * @see View#setLeft(int)
-     * @see View#setTop(int)
+     * @see #setBottom(int)
      */
-    public abstract void setLeftTop(int left, int top);
+    public abstract float getBottom();
 
     /**
-     * Sets the left and top values for the DisplayList
+     * Sets the left and top positions for the display list
      *
-     * @param left The left value of the DisplayList
-     * @param top The top value of the DisplayList
+     * @param left The left position of the display list, in pixels
+     * @param top The top position of the display list, in pixels
+     * @param right The right position of the display list, in pixels
+     * @param bottom The bottom position of the display list, in pixels
+     *
      * @see View#setLeft(int)
      * @see View#setTop(int)
+     * @see View#setRight(int)
+     * @see View#setBottom(int)
      */
     public abstract void setLeftTopRightBottom(int left, int top, int right, int bottom);
 
     /**
-     * Offsets the left and right values for the DisplayList
+     * Offsets the left and right positions for the display list
      *
-     * @param offset The amount that the left and right values of the DisplayList are offset
+     * @param offset The amount that the left and right positions of the display
+     *               list are offset, in pixels
+     *
      * @see View#offsetLeftAndRight(int)
      */
-    public abstract void offsetLeftRight(int offset);
+    public abstract void offsetLeftAndRight(float offset);
 
     /**
-     * Offsets the top and bottom values for the DisplayList
+     * Offsets the top and bottom values for the display list
      *
-     * @param offset The amount that the top and bottom values of the DisplayList are offset
+     * @param offset The amount that the top and bottom positions of the display
+     *               list are offset, in pixels
+     *
      * @see View#offsetTopAndBottom(int)
      */
-    public abstract void offsetTopBottom(int offset);
+    public abstract void offsetTopAndBottom(float offset);
 
     /**
-     * Reset native resources. This is called when cleaning up the state of DisplayLists
+     * Reset native resources. This is called when cleaning up the state of display lists
      * during destruction of hardware resources, to ensure that we do not hold onto
      * obsolete resources after related resources are gone.
+     *
+     * @hide
      */
     public abstract void reset();
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index ec7c65a..7ff8d09 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -377,24 +377,13 @@
     }
 
     private static native int nGetDisplayList(int renderer, int displayList);
-    
-    static void destroyDisplayList(int displayList) {
-        nDestroyDisplayList(displayList);
+
+    @Override
+    void outputDisplayList(DisplayList displayList) {
+        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
     }
 
-    private static native void nDestroyDisplayList(int displayList);
-
-    static int getDisplayListSize(int displayList) {
-        return nGetDisplayListSize(displayList);
-    }
-
-    private static native int nGetDisplayListSize(int displayList);
-
-    static void setDisplayListName(int displayList, String name) {
-        nSetDisplayListName(displayList, name);
-    }
-
-    private static native void nSetDisplayListName(int displayList, String name);
+    private static native void nOutputDisplayList(int renderer, int displayList);
 
     @Override
     public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
@@ -405,13 +394,6 @@
     private static native int nDrawDisplayList(int renderer, int displayList,
             Rect dirty, int flags);
 
-    @Override
-    void outputDisplayList(DisplayList displayList) {
-        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
-    }
-
-    private static native void nOutputDisplayList(int renderer, int displayList);
-
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
@@ -515,22 +497,22 @@
 
     @Override
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
-        return nQuickReject(mRenderer, left, top, right, bottom);
+        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
     }
     
     private static native boolean nQuickReject(int renderer, float left, float top,
-            float right, float bottom);
+            float right, float bottom, int edge);
 
     @Override
     public boolean quickReject(Path path, EdgeType type) {
         path.computeBounds(mPathBounds, true);
         return nQuickReject(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom);
+                mPathBounds.right, mPathBounds.bottom, type.nativeInt);
     }
 
     @Override
     public boolean quickReject(RectF rect, EdgeType type) {
-        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
+        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom, type.nativeInt);
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -901,9 +883,9 @@
         final int count = (meshWidth + 1) * (meshHeight + 1);
         checkRange(verts.length, vertOffset, count * 2);
 
-        // TODO: Colors are ignored for now
-        colors = null;
-        colorOffset = 0;
+        if (colors != null) {
+            checkRange(colors.length, colorOffset, count);
+        }
 
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         try {
@@ -955,6 +937,8 @@
 
     @Override
     public void drawLines(float[] pts, int offset, int count, Paint paint) {
+        if (count < 4) return;
+
         if ((offset | count) < 0 || offset + count > pts.length) {
             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
         }
@@ -1078,6 +1062,8 @@
 
     @Override
     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
+        if (count < 2) return;
+
         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
         try {
             nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index e9bd0c4..9c5cdb2 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -58,7 +58,7 @@
     }
 
     @Override
-    public HardwareCanvas start() {
+    public HardwareCanvas start(int width, int height) {
         if (mCanvas != null) {
             throw new IllegalStateException("Recording has already started");
         }
@@ -66,24 +66,25 @@
         mValid = false;
         mCanvas = GLES20RecordingCanvas.obtain(this);
         mCanvas.start();
+
+        mCanvas.setViewport(width, height);
+        // The dirty rect should always be null for a display list
+        mCanvas.onPreDraw(null);
+
         return mCanvas;
     }
-
     @Override
-    public void invalidate() {
+    public void clear() {
+        clearDirty();
+
         if (mCanvas != null) {
             mCanvas.recycle();
             mCanvas = null;
         }
         mValid = false;
-    }
 
-    @Override
-    public void clear() {
-        if (!mValid) {
-            mBitmaps.clear();
-            mChildDisplayLists.clear();
-        }
+        mBitmaps.clear();
+        mChildDisplayLists.clear();
     }
 
     @Override
@@ -101,11 +102,12 @@
     @Override
     public void end() {
         if (mCanvas != null) {
+            mCanvas.onPostDraw();
             if (mFinalizer != null) {
                 mCanvas.end(mFinalizer.mNativeDisplayList);
             } else {
                 mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
-                GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
+                nSetDisplayListName(mFinalizer.mNativeDisplayList, mName);
             }
             mCanvas.recycle();
             mCanvas = null;
@@ -116,9 +118,13 @@
     @Override
     public int getSize() {
         if (mFinalizer == null) return 0;
-        return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
+        return nGetDisplayListSize(mFinalizer.mNativeDisplayList);
     }
 
+    private static native void nDestroyDisplayList(int displayList);
+    private static native int nGetDisplayListSize(int displayList);
+    private static native void nSetDisplayListName(int displayList, String name);
+
     ///////////////////////////////////////////////////////////////////////////
     // Native View Properties
     ///////////////////////////////////////////////////////////////////////////
@@ -138,13 +144,21 @@
     }
 
     @Override
-    public void setStaticMatrix(Matrix matrix) {
+    public void setMatrix(Matrix matrix) {
         if (hasNativeDisplayList()) {
             nSetStaticMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
         }
     }
 
     @Override
+    public Matrix getMatrix(Matrix matrix) {
+        if (hasNativeDisplayList()) {
+            nGetMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
+        }
+        return matrix;
+    }
+
+    @Override
     public void setAnimationMatrix(Matrix matrix) {
         if (hasNativeDisplayList()) {
             nSetAnimationMatrix(mFinalizer.mNativeDisplayList,
@@ -160,6 +174,14 @@
     }
 
     @Override
+    public float getAlpha() {
+        if (hasNativeDisplayList()) {
+            return nGetAlpha(mFinalizer.mNativeDisplayList);
+        }
+        return 1.0f;
+    }
+
+    @Override
     public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
         if (hasNativeDisplayList()) {
             nSetHasOverlappingRendering(mFinalizer.mNativeDisplayList, hasOverlappingRendering);
@@ -167,6 +189,15 @@
     }
 
     @Override
+    public boolean hasOverlappingRendering() {
+        //noinspection SimplifiableIfStatement
+        if (hasNativeDisplayList()) {
+            return nHasOverlappingRendering(mFinalizer.mNativeDisplayList);
+        }
+        return true;
+    }
+
+    @Override
     public void setTranslationX(float translationX) {
         if (hasNativeDisplayList()) {
             nSetTranslationX(mFinalizer.mNativeDisplayList, translationX);
@@ -174,6 +205,14 @@
     }
 
     @Override
+    public float getTranslationX() {
+        if (hasNativeDisplayList()) {
+            return nGetTranslationX(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setTranslationY(float translationY) {
         if (hasNativeDisplayList()) {
             nSetTranslationY(mFinalizer.mNativeDisplayList, translationY);
@@ -181,6 +220,14 @@
     }
 
     @Override
+    public float getTranslationY() {
+        if (hasNativeDisplayList()) {
+            return nGetTranslationY(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setRotation(float rotation) {
         if (hasNativeDisplayList()) {
             nSetRotation(mFinalizer.mNativeDisplayList, rotation);
@@ -188,6 +235,14 @@
     }
 
     @Override
+    public float getRotation() {
+        if (hasNativeDisplayList()) {
+            return nGetRotation(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setRotationX(float rotationX) {
         if (hasNativeDisplayList()) {
             nSetRotationX(mFinalizer.mNativeDisplayList, rotationX);
@@ -195,6 +250,14 @@
     }
 
     @Override
+    public float getRotationX() {
+        if (hasNativeDisplayList()) {
+            return nGetRotationX(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setRotationY(float rotationY) {
         if (hasNativeDisplayList()) {
             nSetRotationY(mFinalizer.mNativeDisplayList, rotationY);
@@ -202,6 +265,14 @@
     }
 
     @Override
+    public float getRotationY() {
+        if (hasNativeDisplayList()) {
+            return nGetRotationY(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setScaleX(float scaleX) {
         if (hasNativeDisplayList()) {
             nSetScaleX(mFinalizer.mNativeDisplayList, scaleX);
@@ -209,6 +280,14 @@
     }
 
     @Override
+    public float getScaleX() {
+        if (hasNativeDisplayList()) {
+            return nGetScaleX(mFinalizer.mNativeDisplayList);
+        }
+        return 1.0f;
+    }
+
+    @Override
     public void setScaleY(float scaleY) {
         if (hasNativeDisplayList()) {
             nSetScaleY(mFinalizer.mNativeDisplayList, scaleY);
@@ -216,6 +295,14 @@
     }
 
     @Override
+    public float getScaleY() {
+        if (hasNativeDisplayList()) {
+            return nGetScaleY(mFinalizer.mNativeDisplayList);
+        }
+        return 1.0f;
+    }
+
+    @Override
     public void setTransformationInfo(float alpha, float translationX, float translationY,
             float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
         if (hasNativeDisplayList()) {
@@ -232,6 +319,14 @@
     }
 
     @Override
+    public float getPivotX() {
+        if (hasNativeDisplayList()) {
+            return nGetPivotX(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setPivotY(float pivotY) {
         if (hasNativeDisplayList()) {
             nSetPivotY(mFinalizer.mNativeDisplayList, pivotY);
@@ -239,6 +334,14 @@
     }
 
     @Override
+    public float getPivotY() {
+        if (hasNativeDisplayList()) {
+            return nGetPivotY(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setCameraDistance(float distance) {
         if (hasNativeDisplayList()) {
             nSetCameraDistance(mFinalizer.mNativeDisplayList, distance);
@@ -246,6 +349,14 @@
     }
 
     @Override
+    public float getCameraDistance() {
+        if (hasNativeDisplayList()) {
+            return nGetCameraDistance(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setLeft(int left) {
         if (hasNativeDisplayList()) {
             nSetLeft(mFinalizer.mNativeDisplayList, left);
@@ -253,6 +364,14 @@
     }
 
     @Override
+    public float getLeft() {
+        if (hasNativeDisplayList()) {
+            return nGetLeft(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setTop(int top) {
         if (hasNativeDisplayList()) {
             nSetTop(mFinalizer.mNativeDisplayList, top);
@@ -260,6 +379,14 @@
     }
 
     @Override
+    public float getTop() {
+        if (hasNativeDisplayList()) {
+            return nGetTop(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setRight(int right) {
         if (hasNativeDisplayList()) {
             nSetRight(mFinalizer.mNativeDisplayList, right);
@@ -267,6 +394,14 @@
     }
 
     @Override
+    public float getRight() {
+        if (hasNativeDisplayList()) {
+            return nGetRight(mFinalizer.mNativeDisplayList);
+        }
+        return 0.0f;
+    }
+
+    @Override
     public void setBottom(int bottom) {
         if (hasNativeDisplayList()) {
             nSetBottom(mFinalizer.mNativeDisplayList, bottom);
@@ -274,10 +409,11 @@
     }
 
     @Override
-    public void setLeftTop(int left, int top) {
+    public float getBottom() {
         if (hasNativeDisplayList()) {
-            nSetLeftTop(mFinalizer.mNativeDisplayList, left, top);
+            return nGetBottom(mFinalizer.mNativeDisplayList);
         }
+        return 0.0f;
     }
 
     @Override
@@ -288,25 +424,24 @@
     }
 
     @Override
-    public void offsetLeftRight(int offset) {
+    public void offsetLeftAndRight(float offset) {
         if (hasNativeDisplayList()) {
-            nOffsetLeftRight(mFinalizer.mNativeDisplayList, offset);
+            nOffsetLeftAndRight(mFinalizer.mNativeDisplayList, offset);
         }
     }
 
     @Override
-    public void offsetTopBottom(int offset) {
+    public void offsetTopAndBottom(float offset) {
         if (hasNativeDisplayList()) {
-            nOffsetTopBottom(mFinalizer.mNativeDisplayList, offset);
+            nOffsetTopAndBottom(mFinalizer.mNativeDisplayList, offset);
         }
     }
 
     private static native void nReset(int displayList);
-    private static native void nOffsetTopBottom(int displayList, int offset);
-    private static native void nOffsetLeftRight(int displayList, int offset);
+    private static native void nOffsetTopAndBottom(int displayList, float offset);
+    private static native void nOffsetLeftAndRight(int displayList, float 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);
@@ -332,6 +467,23 @@
     private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
     private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
 
+    private static native boolean nHasOverlappingRendering(int displayList);
+    private static native void nGetMatrix(int displayList, int matrix);
+    private static native float nGetAlpha(int displayList);
+    private static native float nGetLeft(int displayList);
+    private static native float nGetTop(int displayList);
+    private static native float nGetRight(int displayList);
+    private static native float nGetBottom(int displayList);
+    private static native float nGetCameraDistance(int displayList);
+    private static native float nGetScaleX(int displayList);
+    private static native float nGetScaleY(int displayList);
+    private static native float nGetTranslationX(int displayList);
+    private static native float nGetTranslationY(int displayList);
+    private static native float nGetRotation(int displayList);
+    private static native float nGetRotationX(int displayList);
+    private static native float nGetRotationY(int displayList);
+    private static native float nGetPivotX(int displayList);
+    private static native float nGetPivotY(int displayList);
 
     ///////////////////////////////////////////////////////////////////////////
     // Finalization
@@ -347,7 +499,7 @@
         @Override
         protected void finalize() throws Throwable {
             try {
-                GLES20Canvas.destroyDisplayList(mNativeDisplayList);
+                nDestroyDisplayList(mNativeDisplayList);
             } finally {
                 super.finalize();
             }
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 812fb97..7ee628b 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -53,12 +53,12 @@
     }
 
     @Override
-    boolean copyInto(Bitmap bitmap) {
+    public boolean copyInto(Bitmap bitmap) {
         return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
     }
 
     @Override
-    void destroy() {
+    public void destroy() {
         if (mFinalizer != null) {
             mFinalizer.destroy();
             mFinalizer = null;
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index 44d4719..086e78c 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -92,6 +92,10 @@
         if (currentCanvas instanceof GLES20Canvas) {
             ((GLES20Canvas) currentCanvas).resume();
         }
+        HardwareCanvas canvas = getCanvas();
+        if (canvas != null) {
+            canvas.onPostDraw();
+        }
     }
 
     @Override
@@ -99,7 +103,10 @@
         if (currentCanvas instanceof GLES20Canvas) {
             ((GLES20Canvas) currentCanvas).interrupt();
         }
-        return getCanvas();
+        HardwareCanvas canvas = getCanvas();
+        canvas.setViewport(mWidth, mHeight);
+        canvas.onPreDraw(null);
+        return canvas;
     }
 
     /**
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 9ddb32e..28c1058 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -213,6 +213,7 @@
     private OnDoubleTapListener mDoubleTapListener;
 
     private boolean mStillDown;
+    private boolean mDeferConfirmSingleTap;
     private boolean mInLongPress;
     private boolean mAlwaysInTapRegion;
     private boolean mAlwaysInBiggerTapRegion;
@@ -267,8 +268,12 @@
                 
             case TAP:
                 // If the user's finger is still down, do not count it as a tap
-                if (mDoubleTapListener != null && !mStillDown) {
-                    mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
+                if (mDoubleTapListener != null) {
+                    if (!mStillDown) {
+                        mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
+                    } else {
+                        mDeferConfirmSingleTap = true;
+                    }
                 }
                 break;
 
@@ -533,6 +538,7 @@
             mAlwaysInBiggerTapRegion = true;
             mStillDown = true;
             mInLongPress = false;
+            mDeferConfirmSingleTap = false;
             
             if (mIsLongpressEnabled) {
                 mHandler.removeMessages(LONG_PRESS);
@@ -586,6 +592,9 @@
                 mInLongPress = false;
             } else if (mAlwaysInTapRegion) {
                 handled = mListener.onSingleTapUp(ev);
+                if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
+                    mDoubleTapListener.onSingleTapConfirmed(ev);
+                }
             } else {
 
                 // A fling must travel the minimum tap distance
@@ -612,6 +621,7 @@
                 mVelocityTracker = null;
             }
             mIsDoubleTapping = false;
+            mDeferConfirmSingleTap = false;
             mHandler.removeMessages(SHOW_PRESS);
             mHandler.removeMessages(LONG_PRESS);
             break;
@@ -637,6 +647,7 @@
         mStillDown = false;
         mAlwaysInTapRegion = false;
         mAlwaysInBiggerTapRegion = false;
+        mDeferConfirmSingleTap = false;
         if (mInLongPress) {
             mInLongPress = false;
         }
@@ -649,6 +660,7 @@
         mIsDoubleTapping = false;
         mAlwaysInTapRegion = false;
         mAlwaysInBiggerTapRegion = false;
+        mDeferConfirmSingleTap = false;
         if (mInLongPress) {
             mInLongPress = false;
         }
@@ -671,6 +683,7 @@
 
     private void dispatchLongPress() {
         mHandler.removeMessages(TAP);
+        mDeferConfirmSingleTap = false;
         mInLongPress = true;
         mListener.onLongPress(mCurrentDownEvent);
     }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 3d19260..0dfed69 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -23,8 +23,8 @@
 
 /**
  * Hardware accelerated canvas.
- *
- * @hide 
+ * 
+ * @hide
  */
 public abstract class HardwareCanvas extends Canvas {
     private String mName;
@@ -46,6 +46,8 @@
      * @param name The name of the canvas, can be null
      *
      * @see #getName()
+     *
+     * @hide
      */
     public void setName(String name) {
         mName = name;
@@ -57,6 +59,8 @@
      * @return The name of the canvas or null
      *
      * @see #setName(String)
+     *
+     * @hide
      */
     public String getName() {
         return mName;
@@ -67,27 +71,43 @@
      * 
      * @param dirty The dirty rectangle to update, can be null.
      * @return {@link DisplayList#STATUS_DREW} if anything was drawn (such as a call to clear
-     * the canvas).
+     *         the canvas).
+     *
+     * @hide
      */
     public abstract int onPreDraw(Rect dirty);
 
     /**
      * Invoked after all drawing operation have been performed.
+     *
+     * @hide
      */
     public abstract void onPostDraw();
 
     /**
+     * Draws the specified display list onto this canvas. The display list can only
+     * be drawn if {@link android.view.DisplayList#isValid()} returns true.
+     *
+     * @param displayList The display list to replay.
+     */
+    public void drawDisplayList(DisplayList displayList) {
+        drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
+    }
+
+    /**
      * Draws the specified display list onto this canvas.
      *
      * @param displayList The display list to replay.
      * @param dirty The dirty region to redraw in the next pass, matters only
-     *        if this method returns true, can be null.
+     *        if this method returns {@link DisplayList#STATUS_DRAW}, can be null.
      * @param flags Optional flags about drawing, see {@link DisplayList} for
      *              the possible flags.
      *
      * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW}, or
      *         {@link DisplayList#STATUS_INVOKE}, or'd with {@link DisplayList#STATUS_DREW}
      *         if anything was drawn.
+     *
+     * @hide
      */
     public abstract int drawDisplayList(DisplayList displayList, Rect dirty, int flags);
 
@@ -96,6 +116,8 @@
      * tools to output display lists for selected nodes to the log.
      *
      * @param displayList The display list to be logged.
+     *
+     * @hide
      */
     abstract void outputDisplayList(DisplayList displayList);
 
@@ -106,6 +128,8 @@
      * @param x The left coordinate of the layer
      * @param y The top coordinate of the layer
      * @param paint The paint used to draw the layer
+     *
+     * @hide
      */
     abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint);
 
@@ -118,6 +142,8 @@
      *                       
      * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
      *         {@link DisplayList#STATUS_INVOKE}
+     *
+     * @hide
      */
     public int callDrawGLFunction(int drawGLFunction) {
         // Noop - this is done in the display list recorder subclass
@@ -131,6 +157,8 @@
      *              
      * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
      *         {@link DisplayList#STATUS_INVOKE}
+     *
+     * @hide
      */
     public int invokeFunctors(Rect dirty) {
         return DisplayList.STATUS_DONE;
@@ -143,7 +171,9 @@
      *
      * @see #invokeFunctors(android.graphics.Rect)
      * @see #callDrawGLFunction(int)
-     * @see #detachFunctor(int) 
+     * @see #detachFunctor(int)
+     *
+     * @hide
      */
     abstract void detachFunctor(int functor);
 
@@ -154,7 +184,9 @@
      *
      * @see #invokeFunctors(android.graphics.Rect)
      * @see #callDrawGLFunction(int)
-     * @see #detachFunctor(int) 
+     * @see #detachFunctor(int)
+     *
+     * @hide
      */
     abstract void attachFunctor(int functor);
 
@@ -164,13 +196,17 @@
      * @param layer The layer to update
      *
      * @see #clearLayerUpdates()
+     *
+     * @hide
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
      * Removes all enqueued layer updates.
      * 
-     * @see #pushLayerUpdate(HardwareLayer) 
+     * @see #pushLayerUpdate(HardwareLayer)
+     *
+     * @hide
      */
     abstract void clearLayerUpdates();
 }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index d3bc35a..18b838b 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -24,7 +24,7 @@
 
 /**
  * A hardware layer can be used to render graphics operations into a hardware
- * friendly buffer. For instance, with an OpenGL backend, a hardware layer
+ * friendly buffer. For instance, with an OpenGL backend a hardware layer
  * would use a Frame Buffer Object (FBO.) The hardware layer can be used as
  * a drawing cache when a complex set of graphics operations needs to be
  * drawn several times.
@@ -68,7 +68,7 @@
      * @param paint The paint used when the layer is drawn into the destination canvas.
      * @see View#setLayerPaint(android.graphics.Paint)
      */
-    void setLayerPaint(Paint paint) {}
+    void setLayerPaint(Paint paint) { }
 
     /**
      * Returns the minimum width of the layer.
@@ -144,6 +144,9 @@
      * this layer.
      * 
      * @return A hardware canvas, or null if a canvas cannot be created
+     *
+     * @see #start(android.graphics.Canvas)
+     * @see #end(android.graphics.Canvas)
      */
     abstract HardwareCanvas getCanvas();
 
@@ -154,12 +157,14 @@
 
     /**
      * This must be invoked before drawing onto this layer.
+     *
      * @param currentCanvas
      */
     abstract HardwareCanvas start(Canvas currentCanvas);
-    
+
     /**
      * This must be invoked after drawing onto this layer.
+     *
      * @param currentCanvas
      */
     abstract void end(Canvas currentCanvas);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 7c4bcfd..7929112 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -49,7 +49,7 @@
 
 /**
  * Interface for rendering a view hierarchy using hardware acceleration.
- * 
+ *
  * @hide
  */
 public abstract class HardwareRenderer {
@@ -63,9 +63,9 @@
     /**
      * Turn on to only refresh the parts of the screen that need updating.
      * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
-     * must also have the value "true". 
+     * must also have the value "true".
      */
-    public static final boolean RENDER_DIRTY_REGIONS = true;
+    static final boolean RENDER_DIRTY_REGIONS = true;
 
     /**
      * System property used to enable or disable dirty regions invalidation.
@@ -353,6 +353,8 @@
      * resources.
      * 
      * @param cacheDir A directory the current process can write to
+     *
+     * @hide
      */
     public static void setupDiskCache(File cacheDir) {
         nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
@@ -443,10 +445,11 @@
      * Creates a new display list that can be used to record batches of
      * drawing operations.
      * 
-     * @param name The name of the display list, used for debugging purpose.
-     *             May be null
+     * @param name The name of the display list, used for debugging purpose. May be null.
      * 
      * @return A new display list.
+     *
+     * @hide
      */
     public abstract DisplayList createDisplayList(String name);
 
@@ -474,7 +477,6 @@
     /**
      * Creates a new {@link SurfaceTexture} that can be used to render into the
      * specified hardware layer.
-     * 
      *
      * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
      * 
@@ -1344,31 +1346,25 @@
 
                     dirty = beginFrame(canvas, dirty, surfaceState);
 
+                    DisplayList displayList = buildDisplayList(view, canvas);
+
                     int saveCount = 0;
                     int status = DisplayList.STATUS_DONE;
 
                     try {
-                        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
-                                == View.PFLAG_INVALIDATED;
-                        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
-                        long buildDisplayListStartTime = startBuildDisplayListProfiling();
-                        canvas.clearLayerUpdates();
-
-                        DisplayList displayList = buildDisplayList(view);
                         status = prepareFrame(dirty);
 
                         saveCount = canvas.save();
                         callbacks.onHardwarePreDraw(canvas);
 
-                        endBuildDisplayListProfiling(buildDisplayListStartTime);
-
                         if (displayList != null) {
                             status = drawDisplayList(attachInfo, canvas, displayList, status);
                         } else {
                             // Shouldn't reach here
                             view.draw(canvas);
                         }
+                    } catch (Exception e) {
+                        Log.e(LOG_TAG, "An error has occurred while drawing:", e);
                     } finally {
                         callbacks.onHardwarePostDraw(canvas);
                         canvas.restoreToCount(saveCount);
@@ -1396,6 +1392,23 @@
             return false;
         }
 
+        private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
+            view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
+                    == View.PFLAG_INVALIDATED;
+            view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
+
+            long buildDisplayListStartTime = startBuildDisplayListProfiling();
+            canvas.clearLayerUpdates();
+
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+            DisplayList displayList = view.getDisplayList();
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
+            endBuildDisplayListProfiling(buildDisplayListStartTime);
+
+            return displayList;
+        }
+
         abstract void drawProfileData(View.AttachInfo attachInfo);
 
         private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
@@ -1443,17 +1456,6 @@
             }
         }
 
-        private static DisplayList buildDisplayList(View view) {
-            DisplayList displayList;
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-            try {
-                displayList = view.getDisplayList();
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-            }
-            return displayList;
-        }
-
         private int prepareFrame(Rect dirty) {
             int status;
             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
@@ -1971,12 +1973,12 @@
         }
 
         @Override
-        HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+        public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
             return new GLES20RenderLayer(width, height, isOpaque);
         }
 
         @Override
-        SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
+        public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
             return ((GLES20TextureLayer) layer).getSurfaceTexture();
         }
 
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a9ad97f..e4ecb5c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,6 +65,8 @@
     void setForcedDisplayDensity(int displayId, int density);
     void clearForcedDisplayDensity(int displayId);
 
+    void setOverscan(int displayId, int left, int top, int right, int bottom);
+
     // Is the device configured to have a full system bar for larger screens?
     boolean hasSystemNavBar();
 
@@ -97,9 +99,6 @@
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
     void removeAppToken(IBinder token);
-    void moveAppToken(int index, IBinder token);
-    void moveAppTokensToTop(in List<IBinder> tokens);
-    void moveAppTokensToBottom(in List<IBinder> tokens);
 
     // Re-evaluate the current orientation from the caller's state.
     // If there is a change, the new Configuration is returned and the
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index c10f287..de64e14 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -16,20 +16,15 @@
 
 package android.view;
 
-import dalvik.system.CloseGuard;
-
 import android.content.res.CompatibilityInfo.Translator;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.SurfaceTexture;
-import android.os.IBinder;
-import android.os.Parcelable;
 import android.os.Parcel;
-import android.os.SystemProperties;
+import android.os.Parcelable;
 import android.util.Log;
+import dalvik.system.CloseGuard;
 
 /**
  * Handle onto a raw buffer that is being managed by the screen compositor.
@@ -37,8 +32,19 @@
 public class Surface implements Parcelable {
     private static final String TAG = "Surface";
 
-    private static final boolean HEADLESS = "1".equals(
-        SystemProperties.get("ro.config.headless", "0"));
+    private static native int nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
+            throws OutOfResourcesException;
+
+    private native Canvas nativeLockCanvas(int nativeObject, Rect dirty);
+    private native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas);
+
+    private static native void nativeRelease(int nativeObject);
+    private static native void nativeDestroy(int nativeObject);
+    private static native boolean nativeIsValid(int nativeObject);
+    private static native boolean nativeIsConsumerRunningBehind(int nativeObject);
+    private static native int nativeCopyFrom(int nativeObject, int surfaceControlNativeObject);
+    private static native int nativeReadFromParcel(int nativeObject, Parcel source);
+    private static native void nativeWriteToParcel(int nativeObject, Parcel dest);
 
     public static final Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
@@ -52,12 +58,34 @@
                 return null;
             }
         }
-
         public Surface[] newArray(int size) {
             return new Surface[size];
         }
     };
 
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private String mName;
+
+    // Note: These fields are accessed by native code.
+    // The mSurfaceControl will only be present for Surfaces used by the window
+    // server or system processes. When this class is parceled we defer to the
+    // mSurfaceControl to do the parceling. Otherwise we parcel the
+    // mNativeSurface.
+    int mNativeObject; // package scope only for SurfaceControl access
+
+    private int mGenerationId; // incremented each time mNativeSurface changes
+    private final Canvas mCanvas = new CompatibleCanvas();
+    private int mCanvasSaveCount; // Canvas save count at time of lockCanvas()
+
+    // The Translator for density compatibility mode.  This is used for scaling
+    // the canvas to perform the appropriate density transformation.
+    private Translator mCompatibilityTranslator;
+
+    // A matrix to scale the matrix set by application. This is set to null for
+    // non compatibility mode.
+    private Matrix mCompatibleMatrix;
+
+
     /**
      * Rotation constant: 0 degree rotation (natural orientation)
      */
@@ -78,201 +106,6 @@
      */
     public static final int ROTATION_270 = 3;
 
-    /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
-     * these are different from the logical display ids used elsewhere in the framework */
-
-    /**
-     * Built-in physical display id: Main display.
-     * Use only with {@link #getBuiltInDisplay()}.
-     * @hide
-     */
-    public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
-
-    /**
-     * Built-in physical display id: Attached HDMI display.
-     * Use only with {@link #getBuiltInDisplay()}.
-     * @hide
-     */
-    public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
-
-    /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
-
-    /**
-     * Surface creation flag: Surface is created hidden
-     * @hide */
-    public static final int HIDDEN = 0x00000004;
-
-    /**
-     * Surface creation flag: The surface contains secure content, special
-     * measures will be taken to disallow the surface's content to be copied
-     * from another process. In particular, screenshots and VNC servers will
-     * be disabled, but other measures can take place, for instance the
-     * surface might not be hardware accelerated. 
-     * @hide
-     */
-    public static final int SECURE = 0x00000080;
-
-    /**
-     * Surface creation flag: Creates a surface where color components are interpreted
-     * as "non pre-multiplied" by their alpha channel. Of course this flag is
-     * meaningless for surfaces without an alpha channel. By default
-     * surfaces are pre-multiplied, which means that each color component is
-     * already multiplied by its alpha value. In this case the blending
-     * equation used is:
-     *
-     *    DEST = SRC + DEST * (1-SRC_ALPHA)
-     *
-     * By contrast, non pre-multiplied surfaces use the following equation:
-     *
-     *    DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)
-     *
-     * pre-multiplied surfaces must always be used if transparent pixels are
-     * composited on top of each-other into the surface. A pre-multiplied
-     * surface can never lower the value of the alpha component of a given
-     * pixel.
-     *
-     * In some rare situations, a non pre-multiplied surface is preferable.
-     * @hide
-     */
-    public static final int NON_PREMULTIPLIED = 0x00000100;
-
-    /**
-     * Surface creation flag: Indicates that the surface must be considered opaque,
-     * even if its pixel format is set to translucent. This can be useful if an
-     * application needs full RGBA 8888 support for instance but will
-     * still draw every pixel opaque.
-     * @hide
-     */
-    public static final int OPAQUE = 0x00000400;
-
-    /**
-     * Surface creation flag: Application requires a hardware-protected path to an
-     * external display sink. If a hardware-protected path is not available,
-     * then this surface will not be displayed on the external sink.
-     * @hide
-     */
-    public static final int PROTECTED_APP = 0x00000800;
-
-    // 0x1000 is reserved for an independent DRM protected flag in framework
-
-    /**
-     * Surface creation flag: Creates a normal surface.
-     * This is the default.
-     * @hide
-     */
-    public static final int FX_SURFACE_NORMAL   = 0x00000000;
-
-    /**
-     * Surface creation flag: Creates a Blur surface.
-     * Everything behind this surface is blurred by some amount.
-     * The quality and refresh speed of the blur effect is not settable or guaranteed.
-     * It is an error to lock a Blur surface, since it doesn't have a backing store.
-     * @hide
-     * @deprecated
-     */
-    @Deprecated
-    public static final int FX_SURFACE_BLUR = 0x00010000;
-
-    /**
-     * Surface creation flag: Creates a Dim surface.
-     * Everything behind this surface is dimmed by the amount specified
-     * in {@link #setAlpha}.  It is an error to lock a Dim surface, since it
-     * doesn't have a backing store.
-     * @hide
-     */
-    public static final int FX_SURFACE_DIM = 0x00020000;
-
-    /**
-     * @hide
-     */
-    public static final int FX_SURFACE_SCREENSHOT = 0x00030000;
-
-    /**
-     * Mask used for FX values above.
-     * @hide
-     */
-    public static final int FX_SURFACE_MASK = 0x000F0000;
-
-    /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */
-    
-    /**
-     * Surface flag: Hide the surface.
-     * Equivalent to calling hide().
-     * @hide
-     */
-    public static final int SURFACE_HIDDEN = 0x01;
-
-
-    private final CloseGuard mCloseGuard = CloseGuard.get();
-    private String mName;
-
-    // Note: These fields are accessed by native code.
-    // The mSurfaceControl will only be present for Surfaces used by the window
-    // server or system processes. When this class is parceled we defer to the
-    // mSurfaceControl to do the parceling. Otherwise we parcel the
-    // mNativeSurface.
-    private int mNativeSurface; // Surface*
-    private int mNativeSurfaceControl; // SurfaceControl*
-    private int mGenerationId; // incremented each time mNativeSurface changes
-    private final Canvas mCanvas = new CompatibleCanvas();
-
-    // The Translator for density compatibility mode.  This is used for scaling
-    // the canvas to perform the appropriate density transformation.
-    private Translator mCompatibilityTranslator;
-
-    // A matrix to scale the matrix set by application. This is set to null for
-    // non compatibility mode.
-    private Matrix mCompatibleMatrix;
-
-    private native void nativeCreate(SurfaceSession session, String name,
-            int w, int h, int format, int flags)
-            throws OutOfResourcesException;
-    private native void nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
-            throws OutOfResourcesException;
-    private native void nativeRelease();
-    private native void nativeDestroy();
-
-    private native boolean nativeIsValid();
-    private native int nativeGetIdentity();
-    private native boolean nativeIsConsumerRunningBehind();
-
-    private native Canvas nativeLockCanvas(Rect dirty);
-    private native void nativeUnlockCanvasAndPost(Canvas canvas);
-
-    private static native Bitmap nativeScreenshot(IBinder displayToken,
-            int width, int height, int minLayer, int maxLayer, boolean allLayers);
-
-    private static native void nativeOpenTransaction();
-    private static native void nativeCloseTransaction();
-    private static native void nativeSetAnimationTransaction();
-
-    private native void nativeSetLayer(int zorder);
-    private native void nativeSetPosition(float x, float y);
-    private native void nativeSetSize(int w, int h);
-    private native void nativeSetTransparentRegionHint(Region region);
-    private native void nativeSetAlpha(float alpha);
-    private native void nativeSetMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
-    private native void nativeSetFlags(int flags, int mask);
-    private native void nativeSetWindowCrop(Rect crop);
-    private native void nativeSetLayerStack(int layerStack);
-
-    private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
-    private static native IBinder nativeCreateDisplay(String name, boolean secure);
-    private static native void nativeSetDisplaySurface(
-            IBinder displayToken, Surface surface);
-    private static native void nativeSetDisplayLayerStack(
-            IBinder displayToken, int layerStack);
-    private static native void nativeSetDisplayProjection(
-            IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect);
-    private static native boolean nativeGetDisplayInfo(
-            IBinder displayToken, PhysicalDisplayInfo outInfo);
-    private static native void nativeBlankDisplay(IBinder displayToken);
-    private static native void nativeUnblankDisplay(IBinder displayToken);
-
-    private native void nativeCopyFrom(Surface other);
-    private native void nativeTransferFrom(Surface other);
-    private native void nativeReadFromParcel(Parcel source);
-    private native void nativeWriteToParcel(Parcel dest);
 
 
     /**
@@ -280,57 +113,6 @@
      * @hide
      */
     public Surface() {
-        checkHeadless();
-
-        mCloseGuard.open("release");
-    }
-
-    /**
-     * Create a surface with a name.
-     *
-     * The surface creation flags specify what kind of surface to create and
-     * certain options such as whether the surface can be assumed to be opaque
-     * and whether it should be initially hidden.  Surfaces should always be
-     * created with the {@link #HIDDEN} flag set to ensure that they are not
-     * made visible prematurely before all of the surface's properties have been
-     * configured.
-     *
-     * Good practice is to first create the surface with the {@link #HIDDEN} flag
-     * specified, open a transaction, set the surface layer, layer stack, alpha,
-     * and position, call {@link #show} if appropriate, and close the transaction.
-     *
-     * @param session The surface session, must not be null.
-     * @param name The surface name, must not be null.
-     * @param w The surface initial width.
-     * @param h The surface initial height.
-     * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
-     * in the creation flags.
-     * @hide
-     */
-    public Surface(SurfaceSession session,
-            String name, int w, int h, int format, int flags)
-            throws OutOfResourcesException {
-        if (session == null) {
-            throw new IllegalArgumentException("session must not be null");
-        }
-        if (name == null) {
-            throw new IllegalArgumentException("name must not be null");
-        }
-
-        if ((flags & HIDDEN) == 0) {
-            Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set "
-                    + "to ensure that they are not made visible prematurely before "
-                    + "all of the surface's properties have been configured.  "
-                    + "Set the other properties and make the surface visible within "
-                    + "a transaction.  New surface name: " + name,
-                    new Throwable());
-        }
-
-        checkHeadless();
-
-        mName = name;
-        nativeCreate(session, name, w, h, format, flags);
-
         mCloseGuard.open("release");
     }
 
@@ -349,11 +131,9 @@
             throw new IllegalArgumentException("surfaceTexture must not be null");
         }
 
-        checkHeadless();
-
         mName = surfaceTexture.toString();
         try {
-            nativeCreateFromSurfaceTexture(surfaceTexture);
+            mNativeObject = nativeCreateFromSurfaceTexture(surfaceTexture);
         } catch (OutOfResourcesException ex) {
             // We can't throw OutOfResourcesException because it would be an API change.
             throw new RuntimeException(ex);
@@ -362,13 +142,20 @@
         mCloseGuard.open("release");
     }
 
+    private Surface(int nativeObject) {
+        mNativeObject = nativeObject;
+        mCloseGuard.open("release");
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
             if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
             }
-            nativeRelease();
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
+            }
         } finally {
             super.finalize();
         }
@@ -380,7 +167,10 @@
      * This will make the surface invalid.
      */
     public void release() {
-        nativeRelease();
+        if (mNativeObject != 0) {
+            nativeRelease(mNativeObject);
+            mNativeObject = 0;
+        }
         mCloseGuard.close();
     }
 
@@ -391,7 +181,10 @@
      * @hide
      */
     public void destroy() {
-        nativeDestroy();
+        if (mNativeObject != 0) {
+            nativeDestroy(mNativeObject);
+            mNativeObject = 0;
+        }
         mCloseGuard.close();
     }
 
@@ -402,7 +195,8 @@
      * Otherwise returns false.
      */
     public boolean isValid() {
-        return nativeIsValid();
+        if (mNativeObject == 0) return false;
+        return nativeIsValid(mNativeObject);
     }
 
     /**
@@ -423,7 +217,8 @@
      * @hide
      */
     public boolean isConsumerRunningBehind() {
-        return nativeIsConsumerRunningBehind();
+        checkNotReleased();
+        return nativeIsConsumerRunningBehind(mNativeObject);
     }
 
     /**
@@ -432,7 +227,7 @@
      * After drawing into the provided {@link Canvas}, the caller should
      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
      *
-     * @param dirty A rectangle that represents the dirty region that the caller wants
+     * @param inOutDirty A rectangle that represents the dirty region that the caller wants
      * to redraw.  This function may choose to expand the dirty rectangle if for example
      * the surface has been resized or if the previous contents of the surface were
      * not available.  The caller should redraw the entire dirty region as represented
@@ -441,9 +236,10 @@
      * entire surface should be redrawn.
      * @return A canvas for drawing into the surface.
      */
-    public Canvas lockCanvas(Rect dirty)
+    public Canvas lockCanvas(Rect inOutDirty)
             throws OutOfResourcesException, IllegalArgumentException {
-        return nativeLockCanvas(dirty);
+        checkNotReleased();
+        return nativeLockCanvas(mNativeObject, inOutDirty);
     }
 
     /**
@@ -453,7 +249,8 @@
      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
      */
     public void unlockCanvasAndPost(Canvas canvas) {
-        nativeUnlockCanvasAndPost(canvas);
+        checkNotReleased();
+        nativeUnlockCanvasAndPost(mNativeObject, canvas);
     }
 
     /** 
@@ -476,190 +273,6 @@
         }
     }
 
-    /**
-     * Like {@link #screenshot(int, int, int, int)} but includes all
-     * Surfaces in the screenshot.
-     *
-     * @hide
-     */
-    public static Bitmap screenshot(int width, int height) {
-        // TODO: should take the display as a parameter
-        IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshot(displayToken, width, height, 0, 0, true);
-    }
-
-    /**
-     * Copy the current screen contents into a bitmap and return it.
-     *
-     * @param width The desired width of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param height The desired height of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param minLayer The lowest (bottom-most Z order) surface layer to
-     * include in the screenshot.
-     * @param maxLayer The highest (top-most Z order) surface layer to
-     * include in the screenshot.
-     * @return Returns a Bitmap containing the screen contents, or null
-     * if an error occurs.
-     *
-     * @hide
-     */
-    public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
-        // TODO: should take the display as a parameter
-        IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
-    }
-
-    /*
-     * set surface parameters.
-     * needs to be inside open/closeTransaction block
-     */
-
-    /** start a transaction @hide */
-    public static void openTransaction() {
-        nativeOpenTransaction();
-    }
-
-    /** end a transaction @hide */
-    public static void closeTransaction() {
-        nativeCloseTransaction();
-    }
-
-    /** flag the transaction as an animation @hide */
-    public static void setAnimationTransaction() {
-        nativeSetAnimationTransaction();
-    }
-
-    /** @hide */
-    public void setLayer(int zorder) {
-        nativeSetLayer(zorder);
-    }
-
-    /** @hide */
-    public void setPosition(int x, int y) {
-        nativeSetPosition((float)x, (float)y);
-    }
-
-    /** @hide */
-    public void setPosition(float x, float y) {
-        nativeSetPosition(x, y);
-    }
-
-    /** @hide */
-    public void setSize(int w, int h) {
-        nativeSetSize(w, h);
-    }
-
-    /** @hide */
-    public void hide() {
-        nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN);
-    }
-
-    /** @hide */
-    public void show() {
-        nativeSetFlags(0, SURFACE_HIDDEN);
-    }
-
-    /** @hide */
-    public void setTransparentRegionHint(Region region) {
-        nativeSetTransparentRegionHint(region);
-    }
-
-    /** @hide */
-    public void setAlpha(float alpha) {
-        nativeSetAlpha(alpha);
-    }
-
-    /** @hide */
-    public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-        nativeSetMatrix(dsdx, dtdx, dsdy, dtdy);
-    }
-
-    /** @hide */
-    public void setFlags(int flags, int mask) {
-        nativeSetFlags(flags, mask);
-    }
-
-    /** @hide */
-    public void setWindowCrop(Rect crop) {
-        nativeSetWindowCrop(crop);
-    }
-
-    /** @hide */
-    public void setLayerStack(int layerStack) {
-        nativeSetLayerStack(layerStack);
-    }
-
-    /** @hide */
-    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
-        return nativeGetBuiltInDisplay(builtInDisplayId);
-    }
-
-    /** @hide */
-    public static IBinder createDisplay(String name, boolean secure) {
-        if (name == null) {
-            throw new IllegalArgumentException("name must not be null");
-        }
-        return nativeCreateDisplay(name, secure);
-    }
-
-    /** @hide */
-    public static void setDisplaySurface(IBinder displayToken, Surface surface) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeSetDisplaySurface(displayToken, surface);
-    }
-
-    /** @hide */
-    public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeSetDisplayLayerStack(displayToken, layerStack);
-    }
-
-    /** @hide */
-    public static void setDisplayProjection(IBinder displayToken,
-            int orientation, Rect layerStackRect, Rect displayRect) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        if (layerStackRect == null) {
-            throw new IllegalArgumentException("layerStackRect must not be null");
-        }
-        if (displayRect == null) {
-            throw new IllegalArgumentException("displayRect must not be null");
-        }
-        nativeSetDisplayProjection(displayToken, orientation, layerStackRect, displayRect);
-    }
-
-    /** @hide */
-    public static boolean getDisplayInfo(IBinder displayToken, PhysicalDisplayInfo outInfo) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        if (outInfo == null) {
-            throw new IllegalArgumentException("outInfo must not be null");
-        }
-        return nativeGetDisplayInfo(displayToken, outInfo);
-    }
-
-    /** @hide */
-    public static void blankDisplay(IBinder displayToken) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeBlankDisplay(displayToken);
-    }
-
-    /** @hide */
-    public static void unblankDisplay(IBinder displayToken) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeUnblankDisplay(displayToken);
-    }
 
     /**
      * Copy another surface to this one.  This surface now holds a reference
@@ -670,13 +283,15 @@
      * in to it.
      * @hide
      */
-    public void copyFrom(Surface other) {
+    public void copyFrom(SurfaceControl other) {
         if (other == null) {
             throw new IllegalArgumentException("other must not be null");
         }
-        if (other != this) {
-            nativeCopyFrom(other);
+        if (other.mNativeObject == 0) {
+            throw new NullPointerException(
+                    "SurfaceControl native object is null. Are you using a released SurfaceControl?");
         }
+        mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject);
     }
 
     /**
@@ -692,7 +307,13 @@
             throw new IllegalArgumentException("other must not be null");
         }
         if (other != this) {
-            nativeTransferFrom(other);
+            if (mNativeObject != 0) {
+                // release our reference to our native object
+                nativeRelease(mNativeObject);
+            }
+            // transfer the reference from other to us
+            mNativeObject = other.mNativeObject;
+            other.mNativeObject = 0;
         }
     }
 
@@ -705,9 +326,8 @@
         if (source == null) {
             throw new IllegalArgumentException("source must not be null");
         }
-
         mName = source.readString();
-        nativeReadFromParcel(source);
+        mNativeObject = nativeReadFromParcel(mNativeObject, source);
     }
 
     @Override
@@ -715,9 +335,8 @@
         if (dest == null) {
             throw new IllegalArgumentException("dest must not be null");
         }
-
         dest.writeString(mName);
-        nativeWriteToParcel(dest);
+        nativeWriteToParcel(mNativeObject, dest);
         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
             release();
         }
@@ -725,13 +344,7 @@
 
     @Override
     public String toString() {
-        return "Surface(name=" + mName + ", identity=" + nativeGetIdentity() + ")";
-    }
-
-    private static void checkHeadless() {
-        if (HEADLESS) {
-            throw new UnsupportedOperationException("Device is headless");
-        }
+        return "Surface(name=" + mName + ")";
     }
 
     /**
@@ -740,73 +353,12 @@
     public static class OutOfResourcesException extends Exception {
         public OutOfResourcesException() {
         }
-
         public OutOfResourcesException(String name) {
             super(name);
         }
     }
 
     /**
-     * Describes the properties of a physical display known to surface flinger.
-     * @hide
-     */
-    public static final class PhysicalDisplayInfo {
-        public int width;
-        public int height;
-        public float refreshRate;
-        public float density;
-        public float xDpi;
-        public float yDpi;
-        public boolean secure;
-
-        public PhysicalDisplayInfo() {
-        }
-
-        public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
-            copyFrom(other);
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
-        }
-
-        public boolean equals(PhysicalDisplayInfo other) {
-            return other != null
-                    && width == other.width
-                    && height == other.height
-                    && refreshRate == other.refreshRate
-                    && density == other.density
-                    && xDpi == other.xDpi
-                    && yDpi == other.yDpi
-                    && secure == other.secure;
-        }
-
-        @Override
-        public int hashCode() {
-            return 0; // don't care
-        }
-
-        public void copyFrom(PhysicalDisplayInfo other) {
-            width = other.width;
-            height = other.height;
-            refreshRate = other.refreshRate;
-            density = other.density;
-            xDpi = other.xDpi;
-            yDpi = other.yDpi;
-            secure = other.secure;
-        }
-
-        // For debugging purposes
-        @Override
-        public String toString() {
-            return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
-                    + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
-                    + "}";
-        }
-    }
-
-    /**
      * Returns a human readable representation of a rotation.
      *
      * @param rotation The rotation.
@@ -893,4 +445,9 @@
             mOrigMatrix.set(m);
         }
     }
+
+    private void checkNotReleased() {
+        if (mNativeObject == 0) throw new NullPointerException(
+                "mNativeObject is null. Have you called release() already?");
+    }
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
new file mode 100644
index 0000000..9f50065
--- /dev/null
+++ b/core/java/android/view/SurfaceControl.java
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import dalvik.system.CloseGuard;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * SurfaceControl
+ *  @hide
+ */
+public class SurfaceControl {
+    private static final String TAG = "SurfaceControl";
+
+    private static native int nativeCreate(SurfaceSession session, String name,
+            int w, int h, int format, int flags)
+            throws OutOfResourcesException;
+    private static native void nativeRelease(int nativeObject);
+    private static native void nativeDestroy(int nativeObject);
+
+    private static native Bitmap nativeScreenshot(IBinder displayToken,
+            int width, int height, int minLayer, int maxLayer, boolean allLayers);
+
+    private static native void nativeOpenTransaction();
+    private static native void nativeCloseTransaction();
+    private static native void nativeSetAnimationTransaction();
+
+    private static native void nativeSetLayer(int nativeObject, int zorder);
+    private static native void nativeSetPosition(int nativeObject, float x, float y);
+    private static native void nativeSetSize(int nativeObject, int w, int h);
+    private static native void nativeSetTransparentRegionHint(int nativeObject, Region region);
+    private static native void nativeSetAlpha(int nativeObject, float alpha);
+    private static native void nativeSetMatrix(int nativeObject, float dsdx, float dtdx, float dsdy, float dtdy);
+    private static native void nativeSetFlags(int nativeObject, int flags, int mask);
+    private static native void nativeSetWindowCrop(int nativeObject, int l, int t, int r, int b);
+    private static native void nativeSetLayerStack(int nativeObject, int layerStack);
+
+    private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
+    private static native IBinder nativeCreateDisplay(String name, boolean secure);
+    private static native void nativeSetDisplaySurface(
+            IBinder displayToken, int nativeSurfaceObject);
+    private static native void nativeSetDisplayLayerStack(
+            IBinder displayToken, int layerStack);
+    private static native void nativeSetDisplayProjection(
+            IBinder displayToken, int orientation,
+            int l, int t, int r, int b, 
+            int L, int T, int R, int B);
+    private static native boolean nativeGetDisplayInfo(
+            IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
+    private static native void nativeBlankDisplay(IBinder displayToken);
+    private static native void nativeUnblankDisplay(IBinder displayToken);
+
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private String mName;
+    int mNativeObject; // package visibility only for Surface.java access
+
+    private static final boolean HEADLESS = "1".equals(
+        SystemProperties.get("ro.config.headless", "0"));
+
+    /**
+     * Exception thrown when a surface couldn't be created or resized.
+     */
+    public static class OutOfResourcesException extends Exception {
+        public OutOfResourcesException() {
+        }
+        public OutOfResourcesException(String name) {
+            super(name);
+        }
+    }
+
+    /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
+
+    /**
+     * Surface creation flag: Surface is created hidden
+     */
+    public static final int HIDDEN = 0x00000004;
+
+    /**
+     * Surface creation flag: The surface contains secure content, special
+     * measures will be taken to disallow the surface's content to be copied
+     * from another process. In particular, screenshots and VNC servers will
+     * be disabled, but other measures can take place, for instance the
+     * surface might not be hardware accelerated. 
+     *
+     */
+    public static final int SECURE = 0x00000080;
+
+    /**
+     * Surface creation flag: Creates a surface where color components are interpreted
+     * as "non pre-multiplied" by their alpha channel. Of course this flag is
+     * meaningless for surfaces without an alpha channel. By default
+     * surfaces are pre-multiplied, which means that each color component is
+     * already multiplied by its alpha value. In this case the blending
+     * equation used is:
+     *
+     *    DEST = SRC + DEST * (1-SRC_ALPHA)
+     *
+     * By contrast, non pre-multiplied surfaces use the following equation:
+     *
+     *    DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)
+     *
+     * pre-multiplied surfaces must always be used if transparent pixels are
+     * composited on top of each-other into the surface. A pre-multiplied
+     * surface can never lower the value of the alpha component of a given
+     * pixel.
+     *
+     * In some rare situations, a non pre-multiplied surface is preferable.
+     *
+     */
+    public static final int NON_PREMULTIPLIED = 0x00000100;
+
+    /**
+     * Surface creation flag: Indicates that the surface must be considered opaque,
+     * even if its pixel format is set to translucent. This can be useful if an
+     * application needs full RGBA 8888 support for instance but will
+     * still draw every pixel opaque.
+     *
+     */
+    public static final int OPAQUE = 0x00000400;
+
+    /**
+     * Surface creation flag: Application requires a hardware-protected path to an
+     * external display sink. If a hardware-protected path is not available,
+     * then this surface will not be displayed on the external sink.
+     *
+     */
+    public static final int PROTECTED_APP = 0x00000800;
+
+    // 0x1000 is reserved for an independent DRM protected flag in framework
+
+    /**
+     * Surface creation flag: Creates a normal surface.
+     * This is the default.
+     *
+     */
+    public static final int FX_SURFACE_NORMAL   = 0x00000000;
+
+    /**
+     * Surface creation flag: Creates a Blur surface.
+     * Everything behind this surface is blurred by some amount.
+     * The quality and refresh speed of the blur effect is not settable or guaranteed.
+     * It is an error to lock a Blur surface, since it doesn't have a backing store.
+     *
+     * @deprecated
+     */
+    @Deprecated
+    public static final int FX_SURFACE_BLUR = 0x00010000;
+
+    /**
+     * Surface creation flag: Creates a Dim surface.
+     * Everything behind this surface is dimmed by the amount specified
+     * in {@link #setAlpha}.  It is an error to lock a Dim surface, since it
+     * doesn't have a backing store.
+     *
+     */
+    public static final int FX_SURFACE_DIM = 0x00020000;
+
+    /**
+     *
+     */
+    public static final int FX_SURFACE_SCREENSHOT = 0x00030000;
+
+    /**
+     * Mask used for FX values above.
+     *
+     */
+    public static final int FX_SURFACE_MASK = 0x000F0000;
+
+    /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */
+
+    /**
+     * Surface flag: Hide the surface.
+     * Equivalent to calling hide().
+     */
+    public static final int SURFACE_HIDDEN = 0x01;
+
+
+    /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
+     * these are different from the logical display ids used elsewhere in the framework */
+
+    /**
+     * Built-in physical display id: Main display.
+     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+     */
+    public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
+
+    /**
+     * Built-in physical display id: Attached HDMI display.
+     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+     */
+    public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
+
+
+
+    /**
+     * Create a surface with a name.
+     *
+     * The surface creation flags specify what kind of surface to create and
+     * certain options such as whether the surface can be assumed to be opaque
+     * and whether it should be initially hidden.  Surfaces should always be
+     * created with the {@link #HIDDEN} flag set to ensure that they are not
+     * made visible prematurely before all of the surface's properties have been
+     * configured.
+     *
+     * Good practice is to first create the surface with the {@link #HIDDEN} flag
+     * specified, open a transaction, set the surface layer, layer stack, alpha,
+     * and position, call {@link #show} if appropriate, and close the transaction.
+     *
+     * @param session The surface session, must not be null.
+     * @param name The surface name, must not be null.
+     * @param w The surface initial width.
+     * @param h The surface initial height.
+     * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
+     * in the creation flags.
+     */
+    public SurfaceControl(SurfaceSession session,
+            String name, int w, int h, int format, int flags)
+                    throws OutOfResourcesException {
+        if (session == null) {
+            throw new IllegalArgumentException("session must not be null");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null");
+        }
+
+        if ((flags & SurfaceControl.HIDDEN) == 0) {
+            Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set "
+                    + "to ensure that they are not made visible prematurely before "
+                    + "all of the surface's properties have been configured.  "
+                    + "Set the other properties and make the surface visible within "
+                    + "a transaction.  New surface name: " + name,
+                    new Throwable());
+        }
+
+        checkHeadless();
+
+        mName = name;
+        mNativeObject = nativeCreate(session, name, w, h, format, flags);
+        if (mNativeObject == 0) {
+            throw new OutOfResourcesException(
+                    "Couldn't allocate SurfaceControl native object");
+        }
+        
+        mCloseGuard.open("release");
+    }
+    
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Surface(name=" + mName + ")";
+    }
+
+    /**
+     * Release the local reference to the server-side surface.
+     * Always call release() when you're done with a Surface.
+     * This will make the surface invalid.
+     */
+    public void release() {
+        if (mNativeObject != 0) {
+            nativeRelease(mNativeObject);
+            mNativeObject = 0;
+        }
+        mCloseGuard.close();
+    }
+
+    /**
+     * Free all server-side state associated with this surface and
+     * release this object's reference.  This method can only be
+     * called from the process that created the service.
+     */
+    public void destroy() {
+        if (mNativeObject != 0) {
+            nativeDestroy(mNativeObject);
+            mNativeObject = 0;
+        }
+        mCloseGuard.close();
+    }
+
+    private void checkNotReleased() {
+        if (mNativeObject == 0) throw new NullPointerException(
+                "mNativeObject is null. Have you called release() already?");
+    }
+    
+    /*
+     * set surface parameters.
+     * needs to be inside open/closeTransaction block
+     */
+
+    /** start a transaction */
+    public static void openTransaction() {
+        nativeOpenTransaction();
+    }
+
+    /** end a transaction */
+    public static void closeTransaction() {
+        nativeCloseTransaction();
+    }
+
+    /** flag the transaction as an animation */
+    public static void setAnimationTransaction() {
+        nativeSetAnimationTransaction();
+    }
+
+    public void setLayer(int zorder) {
+        checkNotReleased();
+        nativeSetLayer(mNativeObject, zorder);
+    }
+
+    public void setPosition(int x, int y) {
+        checkNotReleased();
+        nativeSetPosition(mNativeObject, (float)x, (float)y);
+    }
+
+    public void setPosition(float x, float y) {
+        checkNotReleased();
+        nativeSetPosition(mNativeObject, x, y);
+    }
+
+    public void setSize(int w, int h) {
+        checkNotReleased();
+        nativeSetSize(mNativeObject, w, h);
+    }
+
+    public void hide() {
+        checkNotReleased();
+        nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
+    }
+
+    public void show() {
+        checkNotReleased();
+        nativeSetFlags(mNativeObject, 0, SURFACE_HIDDEN);
+    }
+
+    public void setTransparentRegionHint(Region region) {
+        checkNotReleased();
+        nativeSetTransparentRegionHint(mNativeObject, region);
+    }
+
+    public void setAlpha(float alpha) {
+        checkNotReleased();
+        nativeSetAlpha(mNativeObject, alpha);
+    }
+
+    public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+        checkNotReleased();
+        nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
+    }
+
+    public void setFlags(int flags, int mask) {
+        checkNotReleased();
+        nativeSetFlags(mNativeObject, flags, mask);
+    }
+
+    public void setWindowCrop(Rect crop) {
+        checkNotReleased();
+        if (crop != null) {
+            nativeSetWindowCrop(mNativeObject, 
+                crop.left, crop.top, crop.right, crop.bottom);
+        } else {
+            nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0);
+        }
+    }
+
+    public void setLayerStack(int layerStack) {
+        checkNotReleased();
+        nativeSetLayerStack(mNativeObject, layerStack);
+    }
+
+    /*
+     * set display parameters.
+     * needs to be inside open/closeTransaction block
+     */
+
+    /**
+     * Describes the properties of a physical display known to surface flinger.
+     */
+    public static final class PhysicalDisplayInfo {
+        public int width;
+        public int height;
+        public float refreshRate;
+        public float density;
+        public float xDpi;
+        public float yDpi;
+        public boolean secure;
+    
+        public PhysicalDisplayInfo() {
+        }
+    
+        public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
+            copyFrom(other);
+        }
+    
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
+        }
+    
+        public boolean equals(PhysicalDisplayInfo other) {
+            return other != null
+                    && width == other.width
+                    && height == other.height
+                    && refreshRate == other.refreshRate
+                    && density == other.density
+                    && xDpi == other.xDpi
+                    && yDpi == other.yDpi
+                    && secure == other.secure;
+        }
+    
+        @Override
+        public int hashCode() {
+            return 0; // don't care
+        }
+    
+        public void copyFrom(PhysicalDisplayInfo other) {
+            width = other.width;
+            height = other.height;
+            refreshRate = other.refreshRate;
+            density = other.density;
+            xDpi = other.xDpi;
+            yDpi = other.yDpi;
+            secure = other.secure;
+        }
+    
+        // For debugging purposes
+        @Override
+        public String toString() {
+            return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
+                    + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
+                    + "}";
+        }
+    }
+
+    public static void unblankDisplay(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        nativeUnblankDisplay(displayToken);
+    }
+
+    public static void blankDisplay(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        nativeBlankDisplay(displayToken);
+    }
+
+    public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        if (outInfo == null) {
+            throw new IllegalArgumentException("outInfo must not be null");
+        }
+        return nativeGetDisplayInfo(displayToken, outInfo);
+    }
+
+    public static void setDisplayProjection(IBinder displayToken,
+            int orientation, Rect layerStackRect, Rect displayRect) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        if (layerStackRect == null) {
+            throw new IllegalArgumentException("layerStackRect must not be null");
+        }
+        if (displayRect == null) {
+            throw new IllegalArgumentException("displayRect must not be null");
+        }
+        nativeSetDisplayProjection(displayToken, orientation,
+                layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, 
+                displayRect.left, displayRect.top, displayRect.right, displayRect.bottom);
+    }
+
+    public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        nativeSetDisplayLayerStack(displayToken, layerStack);
+    }
+
+    public static void setDisplaySurface(IBinder displayToken, Surface surface) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        if (surface == null) {
+            throw new IllegalArgumentException("surface must not be null");
+        }
+        if (surface.mNativeObject == 0) 
+            throw new NullPointerException("Surface native object is null. Are you using a released surface?");
+            
+        nativeSetDisplaySurface(displayToken, surface.mNativeObject);
+    }
+
+    public static IBinder createDisplay(String name, boolean secure) {
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null");
+        }
+        return nativeCreateDisplay(name, secure);
+    }
+
+    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
+        return nativeGetBuiltInDisplay(builtInDisplayId);
+    }
+
+    
+    /**
+     * Copy the current screen contents into a bitmap and return it.
+     *
+     * @param width The desired width of the returned bitmap; the raw
+     * screen will be scaled down to this size.
+     * @param height The desired height of the returned bitmap; the raw
+     * screen will be scaled down to this size.
+     * @param minLayer The lowest (bottom-most Z order) surface layer to
+     * include in the screenshot.
+     * @param maxLayer The highest (top-most Z order) surface layer to
+     * include in the screenshot.
+     * @return Returns a Bitmap containing the screen contents, or null
+     * if an error occurs.
+     *
+     */
+    public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
+        // TODO: should take the display as a parameter
+        IBinder displayToken = SurfaceControl.getBuiltInDisplay(SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
+        return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
+    }
+
+    /**
+     * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
+     * Surfaces in the screenshot.
+     *
+     */
+    public static Bitmap screenshot(int width, int height) {
+        // TODO: should take the display as a parameter
+        IBinder displayToken = SurfaceControl.getBuiltInDisplay(SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
+        return nativeScreenshot(displayToken, width, height, 0, 0, true);
+    }
+    
+    private static void checkHeadless() {
+        if (HEADLESS) {
+            throw new UnsupportedOperationException("Device is headless");
+        }
+    }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25cad87..dcf51e4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.app.ActivityThread;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -10050,7 +10049,7 @@
             mTop += offset;
             mBottom += offset;
             if (mDisplayList != null) {
-                mDisplayList.offsetTopBottom(offset);
+                mDisplayList.offsetTopAndBottom(offset);
                 invalidateViewProperty(false, false);
             } else {
                 if (!matrixIsIdentity) {
@@ -10098,7 +10097,7 @@
             mLeft += offset;
             mRight += offset;
             if (mDisplayList != null) {
-                mDisplayList.offsetLeftRight(offset);
+                mDisplayList.offsetLeftAndRight(offset);
                 invalidateViewProperty(false, false);
             } else {
                 if (!matrixIsIdentity) {
@@ -11687,7 +11686,7 @@
         }
 
         if (mDisplayList != null) {
-            mDisplayList.setDirty(false);
+            mDisplayList.clearDirty();
         }
     }
 
@@ -11966,7 +11965,7 @@
 
         if (mAttachInfo != null) {
             if (mDisplayList != null) {
-                mDisplayList.setDirty(true);
+                mDisplayList.markDirty();
                 mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList);
             }
             mAttachInfo.mViewRootImpl.cancelInvalidate(this);
@@ -12670,8 +12669,9 @@
     }
 
     /**
-     * @return The HardwareRenderer associated with that view or null if hardware rendering
-     * is not supported or this this has not been attached to a window.
+     * @return The {@link HardwareRenderer} associated with that view or null if
+     *         hardware rendering is not supported or this view is not attached
+     *         to a window.
      *
      * @hide
      */
@@ -12726,15 +12726,13 @@
             }
 
             boolean caching = false;
-            final HardwareCanvas canvas = displayList.start();
             int width = mRight - mLeft;
             int height = mBottom - mTop;
             int layerType = getLayerType();
 
+            final HardwareCanvas canvas = displayList.start(width, height);
+
             try {
-                canvas.setViewport(width, height);
-                // The dirty rect should always be null for a display list
-                canvas.onPreDraw(null);
                 if (!isLayer && layerType != LAYER_TYPE_NONE) {
                     if (layerType == LAYER_TYPE_HARDWARE) {
                         final HardwareLayer layer = getHardwareLayer();
@@ -12772,8 +12770,6 @@
                     }
                 }
             } finally {
-                canvas.onPostDraw();
-
                 displayList.end();
                 displayList.setCaching(caching);
                 if (isLayer) {
@@ -12818,7 +12814,6 @@
 
     private void clearDisplayList() {
         if (mDisplayList != null) {
-            mDisplayList.invalidate();
             mDisplayList.clear();
         }
     }
@@ -13394,7 +13389,7 @@
                             alpha = transform.getAlpha();
                         }
                         if ((transformType & Transformation.TYPE_MATRIX) != 0) {
-                            displayList.setStaticMatrix(transform.getMatrix());
+                            displayList.setMatrix(transform.getMatrix());
                         }
                     }
                 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a4898fc..5105fda 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4413,7 +4413,7 @@
             v.mTop += offset;
             v.mBottom += offset;
             if (v.mDisplayList != null) {
-                v.mDisplayList.offsetTopBottom(offset);
+                v.mDisplayList.offsetTopAndBottom(offset);
                 invalidateViewProperty(false, false);
             }
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1d86361..9b6dafb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1437,8 +1437,6 @@
                             }
                             // TODO: should handle create/resize failure
                             layerCanvas = mResizeBuffer.start(hwRendererCanvas);
-                            layerCanvas.setViewport(mWidth, mHeight);
-                            layerCanvas.onPreDraw(null);
                             final int restoreCount = layerCanvas.save();
 
                             int yoff;
@@ -1475,9 +1473,6 @@
                         } catch (OutOfMemoryError e) {
                             Log.w(TAG, "Not enough memory for content change anim buffer", e);
                         } finally {
-                            if (layerCanvas != null) {
-                                layerCanvas.onPostDraw();
-                            }
                             if (mResizeBuffer != null) {
                                 mResizeBuffer.end(hwRendererCanvas);
                                 if (!completed) {
@@ -2506,9 +2501,7 @@
         for (int i = 0; i < count; i++) {
             final DisplayList displayList = displayLists.get(i);
             if (displayList.isDirty()) {
-                displayList.invalidate();
                 displayList.clear();
-                displayList.setDirty(false);
             }
         }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6a67d8b..d236561 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -735,20 +735,20 @@
         /**
          * <p>Indicates whether this window should be hardware accelerated.
          * Requesting hardware acceleration does not guarantee it will happen.</p>
-         * 
+         *
          * <p>This flag can be controlled programmatically <em>only</em> to enable
          * hardware acceleration. To enable hardware acceleration for a given
          * window programmatically, do the following:</p>
-         * 
+         *
          * <pre>
          * Window w = activity.getWindow(); // in Activity's onCreate() for instance
          * w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
          *         WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
          * </pre>
-         * 
+         *
          * <p>It is important to remember that this flag <strong>must</strong>
          * be set before setting the content view of your activity or dialog.</p>
-         * 
+         *
          * <p>This flag cannot be used to disable hardware acceleration after it
          * was enabled in your manifest using
          * {@link android.R.attr#hardwareAccelerated}. If you need to selectively
@@ -756,13 +756,19 @@
          * for instance), make sure it is turned off in your manifest and enable it
          * on your activity or dialog when you need it instead, using the method
          * described above.</p>
-         * 
+         *
          * <p>This flag is automatically set by the system if the
          * {@link android.R.attr#hardwareAccelerated android:hardwareAccelerated}
          * XML attribute is set to true on an activity or on the application.</p>
          */
         public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
 
+        /** Window flag: allow window contents to extend in to the screen's
+         * overscan area, if there is one.  The window should still correctly
+         * position its contents to take the overscan area into account.
+         */
+        public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
+
         // ----- HIDDEN FLAGS.
         // These start at the high bit and go down.
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index b5d216a..192eded 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -458,6 +458,12 @@
     public void setInitialDisplaySize(Display display, int width, int height, int density);
 
     /**
+     * Called by window manager to set the overscan region that should be used for the
+     * given display.
+     */
+    public void setDisplayOverscan(Display display, int left, int top, int right, int bottom);
+
+    /**
      * Check permissions when adding a window.
      * 
      * @param attrs The window's LayoutParams.
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index a4347a4..3ded1cd 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1254,6 +1254,40 @@
 
         mAutoFillData = new WebViewCore.AutoFillData();
         mEditTextScroller = new Scroller(context);
+
+        // Calculate channel distance
+        calculateChannelDistance(context);
+    }
+
+    /**
+     * Calculate sChannelDistance based on the screen information.
+     * @param context A Context object used to access application assets.
+     */
+    private void calculateChannelDistance(Context context) {
+        // The channel distance is adjusted for density and screen size
+        final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        final double screenSize = Math.hypot((double)(metrics.widthPixels/metrics.densityDpi),
+                (double)(metrics.heightPixels/metrics.densityDpi));
+        if (screenSize < 3.0) {
+            sChannelDistance = 16;
+        } else if (screenSize < 5.0) {
+            sChannelDistance = 22;
+        } else if (screenSize < 7.0) {
+            sChannelDistance = 28;
+        } else {
+            sChannelDistance = 34;
+        }
+        sChannelDistance = (int)(sChannelDistance * metrics.density);
+        if (sChannelDistance < 16) sChannelDistance = 16;
+
+        if (DebugFlags.WEB_VIEW) {
+            Log.v(LOGTAG, "sChannelDistance : " + sChannelDistance
+                    + ", density : " + metrics.density
+                    + ", screenSize : " + screenSize
+                    + ", metrics.heightPixels : " + metrics.heightPixels
+                    + ", metrics.widthPixels : " + metrics.widthPixels
+                    + ", metrics.densityDpi : " + metrics.densityDpi);
+        }
     }
 
     // WebViewProvider bindings
@@ -5718,32 +5752,13 @@
         }
         return mWebViewPrivate.super_dispatchKeyEvent(event);
     }
-
-    /*
-     * Here is the snap align logic:
-     * 1. If it starts nearly horizontally or vertically, snap align;
-     * 2. If there is a dramitic direction change, let it go;
-     *
-     * Adjustable parameters. Angle is the radians on a unit circle, limited
-     * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical)
-     */
-    private static final float HSLOPE_TO_START_SNAP = .25f;
-    private static final float HSLOPE_TO_BREAK_SNAP = .4f;
-    private static final float VSLOPE_TO_START_SNAP = 1.25f;
-    private static final float VSLOPE_TO_BREAK_SNAP = .95f;
-    /*
-     *  These values are used to influence the average angle when entering
-     *  snap mode. If is is the first movement entering snap, we set the average
-     *  to the appropriate ideal. If the user is entering into snap after the
-     *  first movement, then we average the average angle with these values.
-     */
-    private static final float ANGLE_VERT = 2f;
-    private static final float ANGLE_HORIZ = 0f;
-    /*
-     *  The modified moving average weight.
-     *  Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n
-     */
-    private static final float MMA_WEIGHT_N = 5;
+    
+    private static final int SNAP_BOUND = 16;
+    private static int sChannelDistance = 16;
+    private int mFirstTouchX = -1; // the first touched point
+    private int mFirstTouchY = -1;
+    private int mDistanceX = 0;
+    private int mDistanceY = 0;
 
     private boolean inFullScreenMode() {
         return mFullScreenHolder != null;
@@ -5833,12 +5848,6 @@
         }
     }
 
-    private float calculateDragAngle(int dx, int dy) {
-        dx = Math.abs(dx);
-        dy = Math.abs(dy);
-        return (float) Math.atan2(dy, dx);
-    }
-
     /*
     * Common code for single touch and multi-touch.
     * (x, y) denotes current focus point, which is the touch point for single touch
@@ -5864,6 +5873,12 @@
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
                 mConfirmMove = false;
+
+                // Channel Scrolling
+                mFirstTouchX = x;
+                mFirstTouchY = y;
+                mDistanceX = mDistanceY = 0;
+
                 if (!mEditTextScroller.isFinished()) {
                     mEditTextScroller.abortAnimation();
                 }
@@ -6001,20 +6016,16 @@
                         break;
                     }
 
-                    // Only lock dragging to one axis if we don't have a scale in progress.
-                    // Scaling implies free-roaming movement. Note this is only ever a question
-                    // if mZoomManager.supportsPanDuringZoom() is true.
-                    mAverageAngle = calculateDragAngle(deltaX, deltaY);
-                    if (detector == null || !detector.isInProgress()) {
-                        // if it starts nearly horizontal or vertical, enforce it
-                        if (mAverageAngle < HSLOPE_TO_START_SNAP) {
-                            mSnapScrollMode = SNAP_X;
-                            mSnapPositive = deltaX > 0;
-                            mAverageAngle = ANGLE_HORIZ;
-                        } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
+                    if ((detector == null || !detector.isInProgress())
+                            && SNAP_NONE == mSnapScrollMode) {
+                        int ax = Math.abs(x - mFirstTouchX);
+                        int ay = Math.abs(y - mFirstTouchY);
+                        if (ax < SNAP_BOUND && ay < SNAP_BOUND) {
+                            break;
+                        } else if (ax < SNAP_BOUND) {
                             mSnapScrollMode = SNAP_Y;
-                            mSnapPositive = deltaY > 0;
-                            mAverageAngle = ANGLE_VERT;
+                        } else if (ay < SNAP_BOUND) {
+                            mSnapScrollMode = SNAP_X;
                         }
                     }
 
@@ -6033,31 +6044,21 @@
                 if (deltaX == 0 && deltaY == 0) {
                     keepScrollBarsVisible = true;
                 } else {
-                    mAverageAngle +=
-                        (calculateDragAngle(deltaX, deltaY) - mAverageAngle)
-                        / MMA_WEIGHT_N;
-                    if (mSnapScrollMode != SNAP_NONE) {
-                        if (mSnapScrollMode == SNAP_Y) {
-                            // radical change means getting out of snap mode
-                            if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) {
-                                mSnapScrollMode = SNAP_NONE;
-                            }
-                        }
+                    if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
+                        mDistanceX += Math.abs(deltaX);
+                        mDistanceY += Math.abs(deltaY);
                         if (mSnapScrollMode == SNAP_X) {
-                            // radical change means getting out of snap mode
-                            if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) {
+                            if (mDistanceY > sChannelDistance) {
                                 mSnapScrollMode = SNAP_NONE;
-                            }
+                            } else if (mDistanceX > sChannelDistance) {
+                                mDistanceX = mDistanceY = 0;
                         }
                     } else {
-                        if (mAverageAngle < HSLOPE_TO_START_SNAP) {
-                            mSnapScrollMode = SNAP_X;
-                            mSnapPositive = deltaX > 0;
-                            mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2;
-                        } else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
-                            mSnapScrollMode = SNAP_Y;
-                            mSnapPositive = deltaY > 0;
-                            mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2;
+                            if (mDistanceX > sChannelDistance) {
+                                mSnapScrollMode = SNAP_NONE;
+                            } else if (mDistanceY > sChannelDistance) {
+                                mDistanceX = mDistanceY = 0;
+                            }
                         }
                     }
                     if (mSnapScrollMode != SNAP_NONE) {
@@ -6092,6 +6093,7 @@
                 break;
             }
             case MotionEvent.ACTION_UP: {
+                mFirstTouchX  = mFirstTouchY = -1;
                 if (mIsEditingText && mSelectionStarted) {
                     endScrollEdit();
                     mPrivateHandler.sendEmptyMessageDelayed(SCROLL_HANDLE_INTO_VIEW,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c270e9d..dc305a5 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -20,6 +20,8 @@
 import com.android.internal.widget.EditableInputConnection;
 
 import android.R;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.ClipData;
 import android.content.ClipData.Item;
 import android.content.Context;
@@ -1314,7 +1316,7 @@
                     blockDisplayList = mTextDisplayLists[blockIndex] =
                             mTextView.getHardwareRenderer().createDisplayList("Text " + blockIndex);
                 } else {
-                    if (blockIsInvalid) blockDisplayList.invalidate();
+                    if (blockIsInvalid) blockDisplayList.clear();
                 }
 
                 final boolean blockDisplayListIsInvalid = !blockDisplayList.isValid();
@@ -1337,19 +1339,16 @@
 
                     // Rebuild display list if it is invalid
                     if (blockDisplayListIsInvalid) {
-                        final HardwareCanvas hardwareCanvas = blockDisplayList.start();
+                        final HardwareCanvas hardwareCanvas = blockDisplayList.start(
+                                right - left, bottom - top);
                         try {
-                            // Tighten the bounds of the viewport to the actual text size
-                            hardwareCanvas.setViewport(right - left, bottom - top);
-                            // The dirty rect should always be null for a display list
-                            hardwareCanvas.onPreDraw(null);
-                            // drawText is always relative to TextView's origin, this translation brings
-                            // this range of text back to the top left corner of the viewport
+                            // drawText is always relative to TextView's origin, this translation
+                            // brings this range of text back to the top left corner of the viewport
                             hardwareCanvas.translate(-left, -top);
                             layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
-                            // No need to untranslate, previous context is popped after drawDisplayList
+                            // No need to untranslate, previous context is popped after
+                            // drawDisplayList
                         } finally {
-                            hardwareCanvas.onPostDraw();
                             blockDisplayList.end();
                             // Same as drawDisplayList below, handled by our TextView's parent
                             blockDisplayList.setClipChildren(false);
@@ -1430,7 +1429,7 @@
             while (i < numberOfBlocks) {
                 final int blockIndex = blockIndices[i];
                 if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
-                    mTextDisplayLists[blockIndex].invalidate();
+                    mTextDisplayLists[blockIndex].clear();
                 }
                 if (blockEndLines[i] >= lastLine) break;
                 i++;
@@ -1441,7 +1440,7 @@
     void invalidateTextDisplayList() {
         if (mTextDisplayLists != null) {
             for (int i = 0; i < mTextDisplayLists.length; i++) {
-                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].invalidate();
+                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].clear();
             }
         }
     }
@@ -1893,10 +1892,23 @@
 
                 // Make sure there is only at most one EasyEditSpan in the text
                 if (mPopupWindow.mEasyEditSpan != null) {
-                    text.removeSpan(mPopupWindow.mEasyEditSpan);
+                    mPopupWindow.mEasyEditSpan.setDeleteEnabled(false);
                 }
 
                 mPopupWindow.setEasyEditSpan((EasyEditSpan) span);
+                mPopupWindow.setOnDeleteListener(new EasyEditDeleteListener() {
+                    @Override
+                    public void onDeleteClick(EasyEditSpan span) {
+                        Editable editable = (Editable) mTextView.getText();
+                        int start = editable.getSpanStart(span);
+                        int end = editable.getSpanEnd(span);
+                        if (start >= 0 && end >= 0) {
+                            sendNotification(EasyEditSpan.TEXT_DELETED, span);
+                            mTextView.deleteText_internal(start, end);
+                        }
+                        editable.removeSpan(span);
+                    }
+                });
 
                 if (mTextView.getWindowVisibility() != View.VISIBLE) {
                     // The window is not visible yet, ignore the text change.
@@ -1930,8 +1942,10 @@
         @Override
         public void onSpanChanged(Spannable text, Object span, int previousStart, int previousEnd,
                 int newStart, int newEnd) {
-            if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
-                text.removeSpan(mPopupWindow.mEasyEditSpan);
+            if (mPopupWindow != null && span instanceof EasyEditSpan) {
+                EasyEditSpan easyEditSpan = (EasyEditSpan) span;
+                sendNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
+                text.removeSpan(easyEditSpan);
             }
         }
 
@@ -1941,6 +1955,31 @@
                 mTextView.removeCallbacks(mHidePopup);
             }
         }
+
+        private void sendNotification(int textChangedType, EasyEditSpan span) {
+            try {
+                PendingIntent pendingIntent = span.getPendingIntent();
+                if (pendingIntent != null) {
+                    Intent intent = new Intent();
+                    intent.putExtra(EasyEditSpan.EXTRA_TEXT_CHANGED_TYPE, textChangedType);
+                    pendingIntent.send(mTextView.getContext(), 0, intent);
+                }
+            } catch (CanceledException e) {
+                // This should not happen, as we should try to send the intent only once.
+                Log.w(TAG, "PendingIntent for notification cannot be sent", e);
+            }
+        }
+    }
+
+    /**
+     * Listens for the delete event triggered by {@link EasyEditPopupWindow}.
+     */
+    private interface EasyEditDeleteListener {
+
+        /**
+         * Clicks the delete pop-up.
+         */
+        void onDeleteClick(EasyEditSpan span);
     }
 
     /**
@@ -1953,6 +1992,7 @@
                 com.android.internal.R.layout.text_edit_action_popup_text;
         private TextView mDeleteTextView;
         private EasyEditSpan mEasyEditSpan;
+        private EasyEditDeleteListener mOnDeleteListener;
 
         @Override
         protected void createPopupWindow() {
@@ -1987,19 +2027,29 @@
             mEasyEditSpan = easyEditSpan;
         }
 
+        private void setOnDeleteListener(EasyEditDeleteListener listener) {
+            mOnDeleteListener = listener;
+        }
+
         @Override
         public void onClick(View view) {
-            if (view == mDeleteTextView) {
-                Editable editable = (Editable) mTextView.getText();
-                int start = editable.getSpanStart(mEasyEditSpan);
-                int end = editable.getSpanEnd(mEasyEditSpan);
-                if (start >= 0 && end >= 0) {
-                    mTextView.deleteText_internal(start, end);
-                }
+            if (view == mDeleteTextView
+                    && mEasyEditSpan != null && mEasyEditSpan.isDeleteEnabled()
+                    && mOnDeleteListener != null) {
+                mOnDeleteListener.onDeleteClick(mEasyEditSpan);
             }
         }
 
         @Override
+        public void hide() {
+            if (mEasyEditSpan != null) {
+                mEasyEditSpan.setDeleteEnabled(false);
+            }
+            mOnDeleteListener = null;
+            super.hide();
+        }
+
+        @Override
         protected int getTextOffset() {
             // Place the pop-up at the end of the span
             Editable editable = (Editable) mTextView.getText();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cad7ae3..a1ced6e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -607,6 +607,8 @@
         int typefaceIndex = -1;
         int styleIndex = -1;
         boolean allCaps = false;
+        int shadowcolor = 0;
+        float dx = 0, dy = 0, r = 0;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -667,6 +669,22 @@
                 case com.android.internal.R.styleable.TextAppearance_textAllCaps:
                     allCaps = appearance.getBoolean(attr, false);
                     break;
+
+                case com.android.internal.R.styleable.TextAppearance_shadowColor:
+                    shadowcolor = a.getInt(attr, 0);
+                    break;
+
+                case com.android.internal.R.styleable.TextAppearance_shadowDx:
+                    dx = a.getFloat(attr, 0);
+                    break;
+
+                case com.android.internal.R.styleable.TextAppearance_shadowDy:
+                    dy = a.getFloat(attr, 0);
+                    break;
+
+                case com.android.internal.R.styleable.TextAppearance_shadowRadius:
+                    r = a.getFloat(attr, 0);
+                    break;
                 }
             }
 
@@ -690,8 +708,6 @@
         int maxlength = -1;
         CharSequence text = "";
         CharSequence hint = null;
-        int shadowcolor = 0;
-        float dx = 0, dy = 0, r = 0;
         boolean password = false;
         int inputType = EditorInfo.TYPE_NULL;
 
@@ -2331,6 +2347,19 @@
 
         setTypefaceFromAttrs(familyName, typefaceIndex, styleIndex);
 
+        final int shadowcolor = appearance.getInt(
+                com.android.internal.R.styleable.TextAppearance_shadowColor, 0);
+        if (shadowcolor != 0) {
+            final float dx = appearance.getFloat(
+                    com.android.internal.R.styleable.TextAppearance_shadowDx, 0);
+            final float dy = appearance.getFloat(
+                    com.android.internal.R.styleable.TextAppearance_shadowDy, 0);
+            final float r = appearance.getFloat(
+                    com.android.internal.R.styleable.TextAppearance_shadowRadius, 0);
+
+            setShadowLayer(r, dx, dy, shadowcolor);
+        }
+
         if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
                 false)) {
             setTransformationMethod(new AllCapsTransformationMethod(getContext()));
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index c517a68..8282d23 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -31,6 +31,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.net.ProtocolException;
 
 import libcore.io.IoUtils;
 
@@ -41,7 +42,8 @@
 public class NetworkStatsFactory {
     private static final String TAG = "NetworkStatsFactory";
 
-    // TODO: consider moving parsing to native code
+    private static final boolean USE_NATIVE_PARSING = true;
+    private static final boolean SANITY_CHECK_NATIVE = false;
 
     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
     private final File mStatsXtIfaceAll;
@@ -69,7 +71,7 @@
      *
      * @throws IllegalStateException when problem parsing stats.
      */
-    public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException {
+    public NetworkStats readNetworkStatsSummaryDev() throws IOException {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
@@ -105,11 +107,9 @@
                 reader.finishLine();
             }
         } catch (NullPointerException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
+            throw new ProtocolException("problem parsing stats", e);
         } catch (NumberFormatException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
-        } catch (IOException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
+            throw new ProtocolException("problem parsing stats", e);
         } finally {
             IoUtils.closeQuietly(reader);
             StrictMode.setThreadPolicy(savedPolicy);
@@ -124,7 +124,7 @@
      *
      * @throws IllegalStateException when problem parsing stats.
      */
-    public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException {
+    public NetworkStats readNetworkStatsSummaryXt() throws IOException {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         // return null when kernel doesn't support
@@ -154,11 +154,9 @@
                 reader.finishLine();
             }
         } catch (NullPointerException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
+            throw new ProtocolException("problem parsing stats", e);
         } catch (NumberFormatException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
-        } catch (IOException e) {
-            throw new IllegalStateException("problem parsing stats: " + e);
+            throw new ProtocolException("problem parsing stats", e);
         } finally {
             IoUtils.closeQuietly(reader);
             StrictMode.setThreadPolicy(savedPolicy);
@@ -166,17 +164,33 @@
         return stats;
     }
 
-    public NetworkStats readNetworkStatsDetail() {
+    public NetworkStats readNetworkStatsDetail() throws IOException {
         return readNetworkStatsDetail(UID_ALL);
     }
 
+    public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException {
+        if (USE_NATIVE_PARSING) {
+            final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+            if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) {
+                throw new IOException("Failed to parse network stats");
+            }
+            if (SANITY_CHECK_NATIVE) {
+                final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+                assertEquals(javaStats, stats);
+            }
+            return stats;
+        } else {
+            return javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+        }
+    }
+
     /**
-     * Parse and return {@link NetworkStats} with UID-level details. Values
-     * monotonically increase since device boot.
-     *
-     * @throws IllegalStateException when problem parsing stats.
+     * Parse and return {@link NetworkStats} with UID-level details. Values are
+     * expected to monotonically increase since device boot.
      */
-    public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException {
+    @VisibleForTesting
+    public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid)
+            throws IOException {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
@@ -188,13 +202,13 @@
         ProcFileReader reader = null;
         try {
             // open and consume header line
-            reader = new ProcFileReader(new FileInputStream(mStatsXtUid));
+            reader = new ProcFileReader(new FileInputStream(detailPath));
             reader.finishLine();
 
             while (reader.hasMoreData()) {
                 idx = reader.nextInt();
                 if (idx != lastIdx + 1) {
-                    throw new IllegalStateException(
+                    throw new ProtocolException(
                             "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
                 }
                 lastIdx = idx;
@@ -215,11 +229,9 @@
                 reader.finishLine();
             }
         } catch (NullPointerException e) {
-            throw new IllegalStateException("problem parsing idx " + idx, e);
+            throw new ProtocolException("problem parsing idx " + idx, e);
         } catch (NumberFormatException e) {
-            throw new IllegalStateException("problem parsing idx " + idx, e);
-        } catch (IOException e) {
-            throw new IllegalStateException("problem parsing idx " + idx, e);
+            throw new ProtocolException("problem parsing idx " + idx, e);
         } finally {
             IoUtils.closeQuietly(reader);
             StrictMode.setThreadPolicy(savedPolicy);
@@ -227,4 +239,30 @@
 
         return stats;
     }
+
+    public void assertEquals(NetworkStats expected, NetworkStats actual) {
+        if (expected.size() != actual.size()) {
+            throw new AssertionError(
+                    "Expected size " + expected.size() + ", actual size " + actual.size());
+        }
+
+        NetworkStats.Entry expectedRow = null;
+        NetworkStats.Entry actualRow = null;
+        for (int i = 0; i < expected.size(); i++) {
+            expectedRow = expected.getValues(i, expectedRow);
+            actualRow = actual.getValues(i, actualRow);
+            if (!expectedRow.equals(actualRow)) {
+                throw new AssertionError(
+                        "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow);
+            }
+        }
+    }
+
+    /**
+     * Parse statistics from file into given {@link NetworkStats} object. Values
+     * are expected to monotonically increase since device boot.
+     */
+    @VisibleForTesting
+    public static native int nativeReadNetworkStatsDetail(
+            NetworkStats stats, String path, int limitUid);
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4d35a6b..04b9884 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5956,7 +5956,7 @@
                 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
                     try {
                         mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummaryDev();
-                    } catch (IllegalStateException e) {
+                    } catch (IOException e) {
                         Log.wtf(TAG, "problem reading network stats", e);
                     }
                 }
@@ -5980,7 +5980,7 @@
                     try {
                         mNetworkDetailCache = mNetworkStatsFactory
                                 .readNetworkStatsDetail().groupedByUid();
-                    } catch (IllegalStateException e) {
+                    } catch (IOException e) {
                         Log.wtf(TAG, "problem reading network stats", e);
                     }
                 }
diff --git a/core/java/com/android/internal/statusbar/INotificationListener.java b/core/java/com/android/internal/statusbar/INotificationListener.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/INotificationListener.java
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 44e8757..c6b7631 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -42,6 +42,7 @@
 	android_emoji_EmojiFactory.cpp \
 	android_view_DisplayEventReceiver.cpp \
 	android_view_Surface.cpp \
+	android_view_SurfaceControl.cpp \
 	android_view_SurfaceSession.cpp \
 	android_view_TextureView.cpp \
 	android_view_InputChannel.cpp \
@@ -145,7 +146,8 @@
 	android_app_backup_FullBackup.cpp \
 	android_content_res_ObbScanner.cpp \
 	android_content_res_Configuration.cpp \
-    android_animation_PropertyValuesHolder.cpp
+	android_animation_PropertyValuesHolder.cpp \
+	com_android_internal_net_NetworkStatsFactory.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
@@ -155,13 +157,12 @@
 	$(call include-path-for, bluedroid) \
 	$(call include-path-for, libhardware)/hardware \
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
- $(TOP)/frameworks/av/include \
+	$(TOP)/frameworks/av/include \
 	external/skia/include/core \
 	external/skia/include/effects \
 	external/skia/include/images \
 	external/skia/include/ports \
-	external/skia/src/core \
-	external/skia/src/images \
+	external/skia/src/ports \
 	external/skia/include/utils \
 	external/sqlite/dist \
 	external/sqlite/android \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 94324f8..86d3cb6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -47,8 +47,6 @@
 
 using namespace android;
 
-extern void register_BindTest();
-
 extern int register_android_os_Binder(JNIEnv* env);
 extern int register_android_os_Process(JNIEnv* env);
 extern int register_android_graphics_Bitmap(JNIEnv*);
@@ -121,6 +119,7 @@
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_HardwareRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
+extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
@@ -173,6 +172,7 @@
 extern int register_android_content_res_Configuration(JNIEnv* env);
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
+extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1112,6 +1112,7 @@
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_HardwareRenderer),
     REG_JNI(register_android_view_Surface),
+    REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
     REG_JNI(register_android_view_TextureView),
     REG_JNI(register_com_google_android_gles_jni_EGLImpl),
@@ -1204,6 +1205,7 @@
 
     REG_JNI(register_android_animation_PropertyValuesHolder),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
+    REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
 };
 
 /*
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index daabce3..b7fdecf 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -231,7 +231,7 @@
     }
 
     SkAutoTDelete<SkImageDecoder> add(decoder);
-    SkAutoTDelete<SkBitmap> adb(!useExistingBitmap ? bitmap : NULL);
+    SkAutoTDelete<SkBitmap> adb(bitmap, !useExistingBitmap);
 
     decoder->setPeeker(&peeker);
     if (!isPurgeable) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 1f1f28f..886eb6e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -93,6 +93,14 @@
         return canvas->getDevice()->accessBitmap(false).height();
     }
 
+    static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas, SkBitmap* bitmap) {
+        if (bitmap) {
+            canvas->setBitmapDevice(*bitmap);
+        } else {
+            canvas->setDevice(NULL);
+        }
+    }
+ 
     static int saveAll(JNIEnv* env, jobject jcanvas) {
         NPE_CHECK_RETURN_ZERO(env, jcanvas);
         return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
@@ -270,25 +278,25 @@
         canvas->setDrawFilter(filter);
     }
     
-    static jboolean quickReject__RectF(JNIEnv* env, jobject, SkCanvas* canvas,
-                                        jobject rect) {
+    static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
+                                        jobject rect, int edgetype) {
         SkRect rect_;
         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
-        return canvas->quickReject(rect_);
+        return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
     }
-
-    static jboolean quickReject__Path(JNIEnv* env, jobject, SkCanvas* canvas,
-                                       SkPath* path) {
-        return canvas->quickReject(*path);
+ 
+    static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
+                                       SkPath* path, int edgetype) {
+        return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
     }
-
-    static jboolean quickReject__FFFF(JNIEnv* env, jobject, SkCanvas* canvas,
+ 
+    static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
                                        jfloat left, jfloat top, jfloat right,
-                                       jfloat bottom) {
+                                       jfloat bottom, int edgetype) {
         SkRect r;
         r.set(SkFloatToScalar(left), SkFloatToScalar(top),
               SkFloatToScalar(right), SkFloatToScalar(bottom));
-        return canvas->quickReject(r);
+        return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
     }
  
     static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
@@ -725,7 +733,7 @@
     }
 
 
-    static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+    static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
                                       jfloat x, jfloat y, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
@@ -733,7 +741,7 @@
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
-    static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
+    static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
                                           jfloat x, jfloat y, SkPaint* paint) {
@@ -819,10 +827,10 @@
         delete[] posPtr;
     }
 
-    static void drawTextRun___CIIIIFFIPaint(
+    static void drawTextRun___CIIIIFFPaint(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
-        jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, SkPaint* paint) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
@@ -830,10 +838,10 @@
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
-    static void drawTextRun__StringIIIIFFIPaint(
+    static void drawTextRun__StringIIIIFFPaint(
         JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
         jint end, jint contextStart, jint contextEnd,
-        jfloat x, jfloat y, jint dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, SkPaint* paint) {
 
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
@@ -922,19 +930,12 @@
                               jobject bounds) {
         SkRect   r;
         SkIRect ir;
-        bool     result = canvas->getClipBounds(&r);
+        bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
 
         if (!result) {
             r.setEmpty();
-        } else {
-            // ensure the clip is not larger than the canvas
-            SkRect canvasRect;
-            SkISize deviceSize = canvas->getDeviceSize();
-            canvasRect.iset(0, 0, deviceSize.fWidth, deviceSize.fHeight);
-            r.intersect(canvasRect);
         }
         r.round(&ir);
-
         (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
         return result;
     }
@@ -951,6 +952,7 @@
     {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
     {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
     {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
+    {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
     {"save","()I", (void*) SkCanvasGlue::saveAll},
     {"save","(I)I", (void*) SkCanvasGlue::save},
     {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
@@ -982,10 +984,10 @@
     {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
         (void*) SkCanvasGlue::getClipBounds},
     {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
-    {"native_quickReject","(ILandroid/graphics/RectF;)Z",
-        (void*) SkCanvasGlue::quickReject__RectF},
-    {"native_quickReject","(II)Z", (void*) SkCanvasGlue::quickReject__Path},
-    {"native_quickReject","(IFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF},
+    {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
+        (void*) SkCanvasGlue::quickReject__RectFI},
+    {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
+    {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
     {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
     {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
     {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
@@ -1024,13 +1026,13 @@
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
     {"native_drawText","(I[CIIFFI)V",
-        (void*) SkCanvasGlue::drawText___CIIFFIPaint},
+        (void*) SkCanvasGlue::drawText___CIIFFPaint},
     {"native_drawText","(ILjava/lang/String;IIFFI)V",
-        (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+        (void*) SkCanvasGlue::drawText__StringIIFFPaint},
     {"native_drawTextRun","(I[CIIIIFFI)V",
-        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
+        (void*) SkCanvasGlue::drawTextRun___CIIIIFFPaint},
     {"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
-        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
+        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFPaint},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index 01e7e3e..ff0eb45 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -105,7 +105,7 @@
 void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
                        const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
                        const SkPaint* paint, SkRegion** outRegion) {
-    if (canvas && canvas->quickReject(bounds)) {
+    if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
         return;
     }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e830492..07f55e0 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -548,7 +548,7 @@
     }
 
     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
-            jint count, jint flags, jint offset, jint opt) {
+            jint count, jint offset, jint opt) {
         jfloat scalarArray[count];
 
         TextLayout::getTextRunAdvances(paint, text, start, count, start + count,
@@ -592,19 +592,19 @@
     }
 
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
-            jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextCount, jint offset, jint cursorOpt) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
+        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount,
                 offset, cursorOpt);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
-            jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextEnd, jint offset, jint cursorOpt) {
         const jchar* textArray = env->GetStringChars(text, NULL);
         jint result = doTextRunCursor(env, paint, textArray, contextStart,
-                contextEnd - contextStart, flags, offset, cursorOpt);
+                contextEnd - contextStart, offset, cursorOpt);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index ded2186..ab7cf46 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -177,7 +177,7 @@
 
     SkRegion* region = new SkRegion;
     size_t size = p->readInt32();
-    region->readFromMemory(p->readInplace(size));
+    region->unflatten(p->readInplace(size));
 
     return region;
 }
@@ -190,9 +190,9 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    size_t size = region->writeToMemory(NULL);
+    size_t size = region->flatten(NULL);
     p->writeInt32(size);
-    region->writeToMemory(p->writeInplace(size));
+    region->flatten(p->writeInplace(size));
 
     return true;
 }
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index f8715fe..296d9b2 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -19,7 +19,7 @@
 #include <stdio.h>
 
 #include <gui/GLConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -86,8 +86,8 @@
         JNIEnv* env, jobject thiz)
 {
     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
-    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
-            new SurfaceTextureClient(surfaceTexture->getBufferQueue()) : NULL);
+    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ?
+            new Surface(surfaceTexture->getBufferQueue()) : NULL);
     return surfaceTextureClient;
 }
 
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1a8612e..60c6183 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -340,7 +340,7 @@
 }
 
 void TextLayoutShaper::init() {
-    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
+    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
 }
 
 void TextLayoutShaper::unrefTypefaces() {
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 29805ee..6858c0e 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -24,7 +24,6 @@
 #include <utils/String16.h>
 #include <utils/LruCache.h>
 #include <utils/KeyedVector.h>
-#include <utils/Compare.h>
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
 
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e056b61..7f4c37b 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -147,6 +147,25 @@
     return SkTypeface::CreateFromFile(str.c_str());
 }
 
+#define MIN_GAMMA   (0.1f)
+#define MAX_GAMMA   (10.0f)
+static float pinGamma(float gamma) {
+    if (gamma < MIN_GAMMA) {
+        gamma = MIN_GAMMA;
+    } else if (gamma > MAX_GAMMA) {
+        gamma = MAX_GAMMA;
+    }
+    return gamma;
+}
+
+extern void skia_set_text_gamma(float, float);
+
+static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma,
+                                     jfloat whiteGamma) {
+    // Comment this out for release builds. This is only used during development
+    skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gTypefaceMethods[] = {
@@ -158,6 +177,7 @@
                                            (void*)Typeface_createFromAsset },
     { "nativeCreateFromFile",     "(Ljava/lang/String;)I",
                                            (void*)Typeface_createFromFile },
+    { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
 };
 
 int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 0e0893b..7c65662 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -23,6 +23,7 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <android_runtime/android_view_Surface.h>
 
 #include <cutils/properties.h>
 #include <utils/Vector.h>
@@ -36,7 +37,6 @@
 
 struct fields_t {
     jfieldID    context;
-    jfieldID    surface;
     jfieldID    facing;
     jfieldID    orientation;
     jfieldID    canDisableShutterSound;
@@ -537,10 +537,8 @@
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
     if (camera == 0) return;
 
-    sp<Surface> surface = NULL;
-    if (jSurface != NULL) {
-        surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));
-    }
+    sp<Surface> surface = android_view_Surface_getSurface(env, jSurface);
+
     if (camera->setPreviewDisplay(surface) != NO_ERROR) {
         jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
     }
@@ -965,7 +963,6 @@
 {
     field fields_to_find[] = {
         { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },
-        { "android/view/Surface",    ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface },
         { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
         { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
         { "android/hardware/Camera$CameraInfo", "canDisableShutterSound",   "Z",
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index a340fa1..80d13be 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -64,7 +64,7 @@
             uint32_t width, uint32_t height, uint32_t flags) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-        jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, bufferProducer);
+        jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
         if (surfaceObj == NULL) {
             ALOGE("Could not create Surface from surface texture %p provided by media server.",
                   bufferProducer.get());
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 9e60904..0df8638 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -87,8 +87,8 @@
 
     while (fgets(buffer, sizeof(buffer), fp) != NULL) {
         int matched = sscanf(buffer, "%31s %llu %llu %llu %llu "
-                "%*llu %llu %*llu %*llu %*llu %*llu "
-                "%*llu %llu %*llu %*llu %*llu %*llu", cur_iface, &rxBytes,
+                "%*u %llu %*u %*u %*u %*u "
+                "%*u %llu %*u %*u %*u %*u", cur_iface, &rxBytes,
                 &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets);
         if (matched >= 5) {
             if (matched == 7) {
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 9c7124a..26fc261 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -29,7 +29,7 @@
 
 #include <gui/Surface.h>
 #include <gui/GLConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 
 #include <ui/ANativeObjectBase.h>
 
@@ -631,7 +631,7 @@
     if (surfaceTexture == NULL)
         goto not_valid_surface;
 
-    window = new android::SurfaceTextureClient(surfaceTexture->getBufferQueue());
+    window = new android::Surface(surfaceTexture->getBufferQueue());
 
     if (window == NULL)
         goto not_valid_surface;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index c08178d..a6bb7c7 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -41,6 +41,7 @@
 #include <SkTemplates.h>
 #include <SkXfermode.h>
 
+#include <DisplayList.h>
 #include <DisplayListRenderer.h>
 #include <LayerRenderer.h>
 #include <OpenGLRenderer.h>
@@ -269,7 +270,8 @@
 // ----------------------------------------------------------------------------
 
 static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+        SkCanvas::EdgeType edge) {
     return renderer->quickReject(left, top, right, bottom);
 }
 
@@ -715,20 +717,6 @@
     return renderer->getDisplayList(displayList);
 }
 
-static jint android_view_GLES20Canvas_getDisplayListSize(JNIEnv* env,
-        jobject clazz, DisplayList* displayList) {
-    return displayList->getSize();
-}
-
-static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
-        jobject clazz, DisplayList* displayList, jstring name) {
-    if (name != NULL) {
-        const char* textArray = env->GetStringUTFChars(name, NULL);
-        displayList->setName(textArray);
-        env->ReleaseStringUTFChars(name, textArray);
-    }
-}
-
 static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
         jobject clazz) {
     return new DisplayListRenderer;
@@ -739,11 +727,6 @@
     renderer->reset();
 }
 
-static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
-        jobject clazz, DisplayList* displayList) {
-    DisplayList::destroyDisplayListDeferred(displayList);
-}
-
 static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
         jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
         jobject dirty, jint flags) {
@@ -978,7 +961,7 @@
     { "nSaveLayerAlpha",    "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
     { "nSaveLayerAlpha",    "(III)I",          (void*) android_view_GLES20Canvas_saveLayerAlphaClip },
 
-    { "nQuickReject",       "(IFFFF)Z",        (void*) android_view_GLES20Canvas_quickReject },
+    { "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
     { "nClipRect",          "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_clipRectF },
     { "nClipRect",          "(IIIIII)Z",       (void*) android_view_GLES20Canvas_clipRect },
     { "nClipPath",          "(III)Z",          (void*) android_view_GLES20Canvas_clipPath },
@@ -1043,17 +1026,13 @@
             (void*) android_view_GLES20Canvas_getClipBounds },
 
     { "nGetDisplayList",         "(II)I",      (void*) android_view_GLES20Canvas_getDisplayList },
-    { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
-    { "nGetDisplayListSize",     "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListSize },
-    { "nSetDisplayListName",     "(ILjava/lang/String;)V",
-            (void*) android_view_GLES20Canvas_setDisplayListName },
+    { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nDrawDisplayList",        "(IILandroid/graphics/Rect;I)I",
             (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
     { "nResetDisplayListRenderer",  "(I)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
 
-    { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index c5f52df..f7a5302 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -23,6 +23,7 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <DisplayList.h>
 #include <DisplayListRenderer.h>
 
 namespace android {
@@ -36,11 +37,34 @@
  */
 #ifdef USE_OPENGL_RENDERER
 
+// ----------------------------------------------------------------------------
+// DisplayList view properties
+// ----------------------------------------------------------------------------
+
 static void android_view_GLES20DisplayList_reset(JNIEnv* env,
         jobject clazz, DisplayList* displayList) {
     displayList->reset();
 }
 
+static jint android_view_GLES20DisplayList_getDisplayListSize(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getSize();
+}
+
+static void android_view_GLES20DisplayList_setDisplayListName(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, jstring name) {
+    if (name != NULL) {
+        const char* textArray = env->GetStringUTFChars(name, NULL);
+        displayList->setName(textArray);
+        env->ReleaseStringUTFChars(name, textArray);
+    }
+}
+
+static void android_view_GLES20DisplayList_destroyDisplayList(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    DisplayList::destroyDisplayListDeferred(displayList);
+}
+
 // ----------------------------------------------------------------------------
 // DisplayList view properties
 // ----------------------------------------------------------------------------
@@ -159,27 +183,112 @@
     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) {
+static void android_view_GLES20DisplayList_offsetLeftAndRight(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float offset) {
     displayList->offsetLeftRight(offset);
 }
 
-static void android_view_GLES20DisplayList_offsetTopBottom(JNIEnv* env,
-        jobject clazz, DisplayList* displayList, int offset) {
+static void android_view_GLES20DisplayList_offsetTopAndBottom(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, float offset) {
     displayList->offsetTopBottom(offset);
 }
 
+static void android_view_GLES20DisplayList_getMatrix(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, SkMatrix* matrix) {
+    SkMatrix* source = displayList->getStaticMatrix();
+    if (source) {
+        matrix->setConcat(SkMatrix::I(), *source);
+    } else {
+        matrix->setIdentity();
+    }
+}
+
+static jboolean android_view_GLES20DisplayList_hasOverlappingRendering(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->hasOverlappingRendering();
+}
+
+static jfloat android_view_GLES20DisplayList_getAlpha(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getAlpha();
+}
+
+static jfloat android_view_GLES20DisplayList_getLeft(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getLeft();
+}
+
+static jfloat android_view_GLES20DisplayList_getTop(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getTop();
+}
+
+static jfloat android_view_GLES20DisplayList_getRight(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getRight();
+}
+
+static jfloat android_view_GLES20DisplayList_getBottom(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getBottom();
+}
+
+static jfloat android_view_GLES20DisplayList_getCameraDistance(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getCameraDistance();
+}
+
+static jfloat android_view_GLES20DisplayList_getScaleX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getScaleX();
+}
+
+static jfloat android_view_GLES20DisplayList_getScaleY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getScaleY();
+}
+
+static jfloat android_view_GLES20DisplayList_getTranslationX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getTranslationX();
+}
+
+static jfloat android_view_GLES20DisplayList_getTranslationY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getTranslationY();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotation(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getRotation();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotationX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getRotationX();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotationY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getRotationY();
+}
+
+static jfloat android_view_GLES20DisplayList_getPivotX(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getPivotX();
+}
+
+static jfloat android_view_GLES20DisplayList_getPivotY(JNIEnv* env,
+        jobject clazz, DisplayList* displayList) {
+    return displayList->getPivotY();
+}
+
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -190,6 +299,11 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
+    { "nDestroyDisplayList",   "(I)V",   (void*) android_view_GLES20DisplayList_destroyDisplayList },
+    { "nGetDisplayListSize",   "(I)I",   (void*) android_view_GLES20DisplayList_getDisplayListSize },
+    { "nSetDisplayListName",   "(ILjava/lang/String;)V",
+            (void*) android_view_GLES20DisplayList_setDisplayListName },
+
     { "nReset",                "(I)V",   (void*) android_view_GLES20DisplayList_reset },
     { "nSetCaching",           "(IZ)V",  (void*) android_view_GLES20DisplayList_setCaching },
     { "nSetStaticMatrix",      "(II)V",  (void*) android_view_GLES20DisplayList_setStaticMatrix },
@@ -214,12 +328,29 @@
     { "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 },
+    { "nOffsetLeftAndRight",   "(IF)V",  (void*) android_view_GLES20DisplayList_offsetLeftAndRight },
+    { "nOffsetTopAndBottom",   "(IF)V",  (void*) android_view_GLES20DisplayList_offsetTopAndBottom },
 
+
+    { "nGetMatrix",               "(II)V", (void*) android_view_GLES20DisplayList_getMatrix },
+    { "nHasOverlappingRendering", "(I)Z",  (void*) android_view_GLES20DisplayList_hasOverlappingRendering },
+    { "nGetAlpha",                "(I)F",  (void*) android_view_GLES20DisplayList_getAlpha },
+    { "nGetLeft",                 "(I)F",  (void*) android_view_GLES20DisplayList_getLeft },
+    { "nGetTop",                  "(I)F",  (void*) android_view_GLES20DisplayList_getTop },
+    { "nGetRight",                "(I)F",  (void*) android_view_GLES20DisplayList_getRight },
+    { "nGetBottom",               "(I)F",  (void*) android_view_GLES20DisplayList_getBottom },
+    { "nGetCameraDistance",       "(I)F",  (void*) android_view_GLES20DisplayList_getCameraDistance },
+    { "nGetScaleX",               "(I)F",  (void*) android_view_GLES20DisplayList_getScaleX },
+    { "nGetScaleY",               "(I)F",  (void*) android_view_GLES20DisplayList_getScaleY },
+    { "nGetTranslationX",         "(I)F",  (void*) android_view_GLES20DisplayList_getTranslationX },
+    { "nGetTranslationY",         "(I)F",  (void*) android_view_GLES20DisplayList_getTranslationY },
+    { "nGetRotation",             "(I)F",  (void*) android_view_GLES20DisplayList_getRotation },
+    { "nGetRotationX",            "(I)F",  (void*) android_view_GLES20DisplayList_getRotationX },
+    { "nGetRotationY",            "(I)F",  (void*) android_view_GLES20DisplayList_getRotationY },
+    { "nGetPivotX",               "(I)F",  (void*) android_view_GLES20DisplayList_getPivotX },
+    { "nGetPivotY",               "(I)F",  (void*) android_view_GLES20DisplayList_getPivotY },
 #endif
 };
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ed92e43..ab0d38e 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -18,41 +18,31 @@
 
 #include <stdio.h>
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include "android_os_Parcel.h"
-#include "android_util_Binder.h"
 #include "android/graphics/GraphicsJNI.h"
-#include "android/graphics/Region.h"
 
-#include <binder/IMemory.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 
-#include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
 #include <gui/GLConsumer.h>
 
-#include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
-#include <EGL/egl.h>
-
 #include <SkCanvas.h>
 #include <SkBitmap.h>
 #include <SkRegion.h>
-#include <SkPixelRef.h>
 
-#include "jni.h"
-#include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/android_view_Surface.h>
-#include <android_runtime/android_view_SurfaceSession.h>
-#include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <utils/misc.h>
 #include <utils/Log.h>
 
 #include <ScopedUtfChars.h>
 
-
 // ----------------------------------------------------------------------------
 
 namespace android {
@@ -62,10 +52,10 @@
 
 static struct {
     jclass clazz;
-    jfieldID mNativeSurface;
-    jfieldID mNativeSurfaceControl;
+    jfieldID mNativeObject;
     jfieldID mGenerationId;
     jfieldID mCanvas;
+    jfieldID mCanvasSaveCount;
     jmethodID ctor;
 } gSurfaceClassInfo;
 
@@ -77,179 +67,26 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
     jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
-    jfieldID width;
-    jfieldID height;
-    jfieldID refreshRate;
-    jfieldID density;
-    jfieldID xDpi;
-    jfieldID yDpi;
-    jfieldID secure;
-} gPhysicalDisplayInfoClassInfo;
-
-
-class ScreenshotPixelRef : public SkPixelRef {
-public:
-    ScreenshotPixelRef(SkColorTable* ctable) {
-        fCTable = ctable;
-        SkSafeRef(ctable);
-        setImmutable();
-    }
-
-    virtual ~ScreenshotPixelRef() {
-        SkSafeUnref(fCTable);
-    }
-
-    status_t update(const sp<IBinder>& display, int width, int height,
-            int minLayer, int maxLayer, bool allLayers) {
-        status_t res = (width > 0 && height > 0)
-                ? (allLayers
-                        ? mScreenshot.update(display, width, height)
-                        : mScreenshot.update(display, width, height, minLayer, maxLayer))
-                : mScreenshot.update(display);
-        if (res != NO_ERROR) {
-            return res;
-        }
-
-        return NO_ERROR;
-    }
-
-    uint32_t getWidth() const {
-        return mScreenshot.getWidth();
-    }
-
-    uint32_t getHeight() const {
-        return mScreenshot.getHeight();
-    }
-
-    uint32_t getStride() const {
-        return mScreenshot.getStride();
-    }
-
-    uint32_t getFormat() const {
-        return mScreenshot.getFormat();
-    }
-
-    SK_DECLARE_UNFLATTENABLE_OBJECT()
-protected:
-    // overrides from SkPixelRef
-    virtual void* onLockPixels(SkColorTable** ct) {
-        *ct = fCTable;
-        return (void*)mScreenshot.getPixels();
-    }
-
-    virtual void onUnlockPixels() {
-    }
-
-private:
-    ScreenshotClient mScreenshot;
-    SkColorTable*    fCTable;
-
-    typedef SkPixelRef INHERITED;
-};
-
-
 // ----------------------------------------------------------------------------
 
-static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject surfaceObj) {
-    return reinterpret_cast<SurfaceControl*>(
-            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
-}
-
-static void setSurfaceControl(JNIEnv* env, jobject surfaceObj,
-        const sp<SurfaceControl>& surface) {
-    SurfaceControl* const p = reinterpret_cast<SurfaceControl*>(
-            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
-    if (surface.get()) {
-        surface->incStrong(surfaceObj);
-    }
-    if (p) {
-        p->decStrong(surfaceObj);
-    }
-    env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl,
-            reinterpret_cast<jint>(surface.get()));
-}
-
-static sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
-    sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj));
-    if (result == NULL) {
-        /*
-         * if this method is called from the WindowManager's process, it means
-         * the client is is not remote, and therefore is allowed to have
-         * a Surface (data), so we create it here.
-         * If we don't have a SurfaceControl, it means we're in a different
-         * process.
-         */
-
-        SurfaceControl* const control = reinterpret_cast<SurfaceControl*>(
-                env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
-        if (control) {
-            result = control->getSurface();
-            if (result != NULL) {
-                result->incStrong(surfaceObj);
-                env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
-                        reinterpret_cast<jint>(result.get()));
-            }
-        }
-    }
-    return result;
-}
-
-sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
-    return getSurface(env, surfaceObj);
-}
-
 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
     return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
 }
 
+sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
+    return android_view_Surface_getSurface(env, surfaceObj);
+}
+
 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
-    return reinterpret_cast<Surface*>(
-            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
+    return reinterpret_cast<Surface *>(
+            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject));
 }
 
-static void setSurface(JNIEnv* env, jobject surfaceObj, const sp<Surface>& surface) {
-    Surface* const p = reinterpret_cast<Surface*>(
-            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
-    if (surface.get()) {
-        surface->incStrong(surfaceObj);
-    }
-    if (p) {
-        p->decStrong(surfaceObj);
-    }
-    env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
-            reinterpret_cast<jint>(surface.get()));
-
-    // This test is conservative and it would be better to compare the ISurfaces
-    if (p && p != surface.get()) {
-        jint generationId = env->GetIntField(surfaceObj,
-                gSurfaceClassInfo.mGenerationId);
-        generationId++;
-        env->SetIntField(surfaceObj,
-                gSurfaceClassInfo.mGenerationId, generationId);
-    }
-}
-
-static sp<IGraphicBufferProducer> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
-    if (surfaceObj) {
-        sp<Surface> surface(getSurface(env, surfaceObj));
-        if (surface != NULL) {
-            return surface->getSurfaceTexture();
-        }
-    }
-    return NULL;
-}
-
-jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
         const sp<IGraphicBufferProducer>& bufferProducer) {
     if (bufferProducer == NULL) {
         return NULL;
@@ -260,7 +97,7 @@
         return NULL;
     }
 
-    jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor);
+    jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, surface.get());
     if (surfaceObj == NULL) {
         if (env->ExceptionCheck()) {
             ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
@@ -269,96 +106,61 @@
         }
         return NULL;
     }
-
-    setSurface(env, surfaceObj, surface);
+    surface->incStrong(surfaceObj);
     return surfaceObj;
 }
 
+// ----------------------------------------------------------------------------
+
+static bool isSurfaceValid(const sp<Surface>& sur) {
+    return sur != 0 && sur->getISurfaceTexture() != 0;
+}
 
 // ----------------------------------------------------------------------------
 
-static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
-        jstring nameStr, jint w, jint h, jint format, jint flags) {
-    ScopedUtfChars name(env, nameStr);
-    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
-
-    sp<SurfaceControl> surface = client->createSurface(
-            String8(name.c_str()), w, h, format, flags);
-    if (surface == NULL) {
-        jniThrowException(env, OutOfResourcesException, NULL);
-        return;
-    }
-
-    setSurfaceControl(env, surfaceObj, surface);
-}
-
-static void nativeCreateFromSurfaceTexture(JNIEnv* env, jobject surfaceObj,
+static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
         jobject surfaceTextureObj) {
     sp<GLConsumer> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
     if (st == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                 "SurfaceTexture has already been released");
-        return;
+        return 0;
     }
 
     sp<IGraphicBufferProducer> bq = st->getBufferQueue();
-
     sp<Surface> surface(new Surface(bq));
     if (surface == NULL) {
         jniThrowException(env, OutOfResourcesException, NULL);
-        return;
+        return 0;
     }
 
-    setSurface(env, surfaceObj, surface);
+    surface->incStrong(clazz);
+    return int(surface.get());
 }
 
-static void nativeRelease(JNIEnv* env, jobject surfaceObj) {
-    setSurfaceControl(env, surfaceObj, NULL);
-    setSurface(env, surfaceObj, NULL);
+static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
+    sur->decStrong(clazz);
 }
 
-static void nativeDestroy(JNIEnv* env, jobject surfaceObj) {
-    sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
-    if (SurfaceControl::isValid(surfaceControl)) {
-        surfaceControl->clear();
-    }
-    setSurfaceControl(env, surfaceObj, NULL);
-    setSurface(env, surfaceObj, NULL);
+static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
+    sur->decStrong(clazz);
 }
 
-static jboolean nativeIsValid(JNIEnv* env, jobject surfaceObj) {
-    sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
-    if (surfaceControl != NULL) {
-        return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
-    }
-
-    sp<Surface> surface(getSurface(env, surfaceObj));
-    return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
+static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
+    return isSurfaceValid(sur) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jint nativeGetIdentity(JNIEnv* env, jobject surfaceObj) {
-    sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
-    if (control != NULL) {
-        return jint(control->getIdentity());
-    }
-
-    sp<Surface> surface(getSurface(env, surfaceObj));
-    if (surface != NULL) {
-        return jint(surface->getIdentity());
-    }
-
-    return -1;
-}
-
-static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jobject surfaceObj) {
-    sp<Surface> surface(getSurface(env, surfaceObj));
-    if (!Surface::isValid(surface)) {
+static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
+    if (!isSurfaceValid(sur)) {
         doThrowIAE(env);
         return JNI_FALSE;
     }
-
     int value = 0;
-    ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
+    ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get());
     anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
     return value;
 }
@@ -378,18 +180,10 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-  env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
-  env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
-  SkSafeUnref(previousCanvas);
-}
+static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jint nativeObject, jobject dirtyRectObj) {
+    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
 
-static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jobject dirtyRectObj) {
-    sp<Surface> surface(getSurface(env, surfaceObj));
-    if (!Surface::isValid(surface)) {
+    if (!isSurfaceValid(surface)) {
         doThrowIAE(env);
         return NULL;
     }
@@ -409,8 +203,10 @@
         dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
     }
 
-    Surface::SurfaceInfo info;
-    status_t err = surface->lock(&info, &dirtyRegion);
+    ANativeWindow_Buffer outBuffer;
+    Rect dirtyBounds(dirtyRegion.getBounds());
+    status_t err = surface->lock(&outBuffer, &dirtyBounds);
+    dirtyRegion.set(dirtyBounds);
     if (err < 0) {
         const char* const exception = (err == NO_MEMORY) ?
                 OutOfResourcesException :
@@ -421,23 +217,23 @@
 
     // Associate a SkCanvas object to this surface
     jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
-    env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, info.format);
+    env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
 
+    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
+            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
     SkBitmap bitmap;
-    ssize_t bpr = info.s * bytesPerPixel(info.format);
-    bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
-    if (info.format == PIXEL_FORMAT_RGBX_8888) {
+    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
+    bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
+    if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
         bitmap.setIsOpaque(true);
     }
-    if (info.w > 0 && info.h > 0) {
-        bitmap.setPixels(info.bits);
+    if (outBuffer.width > 0 && outBuffer.height > 0) {
+        bitmap.setPixels(outBuffer.bits);
     } else {
         // be safe with an empty bitmap.
         bitmap.setPixels(NULL);
     }
-
-    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    nativeCanvas->setBitmapDevice(bitmap);
 
     SkRegion clipReg;
     if (dirtyRegion.isRect()) { // very common case
@@ -454,6 +250,9 @@
 
     nativeCanvas->clipRegion(clipReg);
 
+    int saveCount = nativeCanvas->save();
+    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, saveCount);
+
     if (dirtyRectObj) {
         const Rect& bounds(dirtyRegion.getBounds());
         env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
@@ -465,21 +264,25 @@
     return canvasObj;
 }
 
-static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jobject canvasObj) {
+static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jint nativeObject, jobject canvasObj) {
     jobject ownCanvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
     if (!env->IsSameObject(ownCanvasObj, canvasObj)) {
         doThrowIAE(env);
         return;
     }
 
-    sp<Surface> surface(getSurface(env, surfaceObj));
-    if (!Surface::isValid(surface)) {
+    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
+    if (!isSurfaceValid(surface)) {
         return;
     }
 
     // detach the canvas from the surface
-    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
+            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
+    int saveCount = env->GetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount);
+    nativeCanvas->restoreToCount(saveCount);
+    nativeCanvas->setBitmapDevice(SkBitmap());
+    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -488,395 +291,81 @@
     }
 }
 
-static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
-        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
-    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
-    if (displayToken == NULL) {
-        return NULL;
-    }
-
-    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
-    if (pixels->update(displayToken, width, height,
-            minLayer, maxLayer, allLayers) != NO_ERROR) {
-        delete pixels;
-        return NULL;
-    }
-
-    uint32_t w = pixels->getWidth();
-    uint32_t h = pixels->getHeight();
-    uint32_t s = pixels->getStride();
-    uint32_t f = pixels->getFormat();
-    ssize_t bpr = s * android::bytesPerPixel(f);
-
-    SkBitmap* bitmap = new SkBitmap();
-    bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
-    if (f == PIXEL_FORMAT_RGBX_8888) {
-        bitmap->setIsOpaque(true);
-    }
-
-    if (w > 0 && h > 0) {
-        bitmap->setPixelRef(pixels)->unref();
-        bitmap->lockPixels();
-    } else {
-        // be safe with an empty bitmap.
-        delete pixels;
-        bitmap->setPixels(NULL);
-    }
-
-    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
-}
-
-static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient::openGlobalTransaction();
-}
-
-static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient::closeGlobalTransaction();
-}
-
-static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient::setAnimationTransaction();
-}
-
-static void nativeSetLayer(JNIEnv* env, jobject surfaceObj, jint zorder) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setLayer(zorder);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetPosition(JNIEnv* env, jobject surfaceObj, jfloat x, jfloat y) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setPosition(x, y);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetSize(JNIEnv* env, jobject surfaceObj, jint w, jint h) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setSize(w, h);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetFlags(JNIEnv* env, jobject surfaceObj, jint flags, jint mask) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setFlags(flags, mask);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetTransparentRegionHint(JNIEnv* env, jobject surfaceObj, jobject regionObj) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
-    if (!region) {
-        doThrowIAE(env);
-        return;
-    }
-
-    const SkIRect& b(region->getBounds());
-    Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
-    if (region->isComplex()) {
-        SkRegion::Iterator it(*region);
-        while (!it.done()) {
-            const SkIRect& r(it.rect());
-            reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
-            it.next();
-        }
-    }
-
-    status_t err = surface->setTransparentRegionHint(reg);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetAlpha(JNIEnv* env, jobject surfaceObj, jfloat alpha) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setAlpha(alpha);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetMatrix(JNIEnv* env, jobject surfaceObj,
-        jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetWindowCrop(JNIEnv* env, jobject surfaceObj, jobject cropObj) {
-    const sp<SurfaceControl>& surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    Rect crop;
-    if (cropObj) {
-        crop.left = env->GetIntField(cropObj, gRectClassInfo.left);
-        crop.top = env->GetIntField(cropObj, gRectClassInfo.top);
-        crop.right = env->GetIntField(cropObj, gRectClassInfo.right);
-        crop.bottom = env->GetIntField(cropObj, gRectClassInfo.bottom);
-    } else {
-        crop.left = crop.top = crop.right = crop.bottom = 0;
-    }
-
-    status_t err = surface->setCrop(crop);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static void nativeSetLayerStack(JNIEnv* env, jobject surfaceObj, jint layerStack) {
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    if (surface == NULL) return;
-
-    status_t err = surface->setLayerStack(layerStack);
-    if (err < 0 && err != NO_INIT) {
-        doThrowIAE(env);
-    }
-}
-
-static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
-    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
-    return javaObjectForIBinder(env, token);
-}
-
-static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
-        jboolean secure) {
-    ScopedUtfChars name(env, nameObj);
-    sp<IBinder> token(SurfaceComposerClient::createDisplay(
-            String8(name.c_str()), bool(secure)));
-    return javaObjectForIBinder(env, token);
-}
-
-static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject surfaceObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    sp<IGraphicBufferProducer> bufferProducer(getISurfaceTexture(env, surfaceObj));
-    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
-}
-
-static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jint layerStack) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
-}
-
-static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jint orientation, jobject layerStackRectObj, jobject displayRectObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    Rect layerStackRect;
-    layerStackRect.left = env->GetIntField(layerStackRectObj, gRectClassInfo.left);
-    layerStackRect.top = env->GetIntField(layerStackRectObj, gRectClassInfo.top);
-    layerStackRect.right = env->GetIntField(layerStackRectObj, gRectClassInfo.right);
-    layerStackRect.bottom = env->GetIntField(layerStackRectObj, gRectClassInfo.bottom);
-
-    Rect displayRect;
-    displayRect.left = env->GetIntField(displayRectObj, gRectClassInfo.left);
-    displayRect.top = env->GetIntField(displayRectObj, gRectClassInfo.top);
-    displayRect.right = env->GetIntField(displayRectObj, gRectClassInfo.right);
-    displayRect.bottom = env->GetIntField(displayRectObj, gRectClassInfo.bottom);
-
-    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
-}
-
-static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject infoObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return JNI_FALSE;
-
-    DisplayInfo info;
-    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
-        return JNI_FALSE;
-    }
-
-    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
-    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
-    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
-    return JNI_TRUE;
-}
-
-static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
-    SurfaceComposerClient::blankDisplay(token);
-}
-
-static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
-    SurfaceComposerClient::unblankDisplay(token);
-}
-
 // ----------------------------------------------------------------------------
 
-static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
+static jint nativeCopyFrom(JNIEnv* env, jclass clazz,
+        jint nativeObject, jint surfaceControlNativeObj) {
     /*
      * This is used by the WindowManagerService just after constructing
      * a Surface and is necessary for returning the Surface reference to
      * the caller. At this point, we should only have a SurfaceControl.
      */
 
-    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
-    sp<SurfaceControl> other(getSurfaceControl(env, otherObj));
-    if (!SurfaceControl::isSameSurface(surface, other)) {
-        // we reassign the surface only if it's a different one
-        // otherwise we would loose our client-side state.
-        setSurfaceControl(env, surfaceObj, other);
+    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
+    sp<Surface> other(ctrl->getSurface());
+    if (other != NULL) {
+        other->incStrong(clazz);
     }
+
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
+    if (sur != NULL) {
+        sur->decStrong(clazz);
+    }
+
+    return int(other.get());
 }
 
-static void nativeTransferFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
-    sp<SurfaceControl> control(getSurfaceControl(env, otherObj));
-    sp<Surface> surface(android_view_Surface_getSurface(env, otherObj));
-    setSurfaceControl(env, surfaceObj, control);
-    setSurface(env, surfaceObj, surface);
-    setSurfaceControl(env, otherObj, NULL);
-    setSurface(env, otherObj, NULL);
+static jint nativeReadFromParcel(JNIEnv* env, jclass clazz,
+        jint nativeObject, jobject parcelObj) {
+    Parcel* parcel = parcelForJavaObject(env, parcelObj);
+    if (parcel == NULL) {
+        doThrowNPE(env);
+        return 0;
+    }
+    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
+    if (self != NULL) {
+        self->decStrong(clazz);
+    }
+    sp<Surface> sur(Surface::readFromParcel(*parcel));
+    if (sur != NULL) {
+        sur->incStrong(clazz);
+    }
+    return int(sur.get());
 }
 
-static void nativeReadFromParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
+static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
+        jint nativeObject, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
     if (parcel == NULL) {
         doThrowNPE(env);
         return;
     }
-
-    sp<Surface> surface(Surface::readFromParcel(*parcel));
-    setSurfaceControl(env, surfaceObj, NULL);
-    setSurface(env, surfaceObj, surface);
-}
-
-static void nativeWriteToParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
-    Parcel* parcel = parcelForJavaObject(env, parcelObj);
-    if (parcel == NULL) {
-        doThrowNPE(env);
-        return;
-    }
-
-    // The Java instance may have a SurfaceControl (in the case of the
-    // WindowManager or a system app). In that case, we defer to the
-    // SurfaceControl to send its ISurface. Otherwise, if the Surface is
-    // available we let it parcel itself. Finally, if the Surface is also
-    // NULL we fall back to using the SurfaceControl path which sends an
-    // empty surface; this matches legacy behavior.
-    sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
-    if (control != NULL) {
-        SurfaceControl::writeSurfaceToParcel(control, parcel);
-    } else {
-        sp<Surface> surface(android_view_Surface_getSurface(env, surfaceObj));
-        if (surface != NULL) {
-            Surface::writeToParcel(surface, parcel);
-        } else {
-            SurfaceControl::writeSurfaceToParcel(NULL, parcel);
-        }
-    }
+    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
+    Surface::writeToParcel(self, parcel);
 }
 
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gSurfaceMethods[] = {
-    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)V",
-            (void*)nativeCreate },
-    {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V",
+    {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)I",
             (void*)nativeCreateFromSurfaceTexture },
-    {"nativeRelease", "()V",
+    {"nativeRelease", "(I)V",
             (void*)nativeRelease },
-    {"nativeDestroy", "()V",
+    {"nativeDestroy", "(I)V",
             (void*)nativeDestroy },
-    {"nativeIsValid", "()Z",
+    {"nativeIsValid", "(I)Z",
             (void*)nativeIsValid },
-    {"nativeGetIdentity", "()I",
-            (void*)nativeGetIdentity },
-    {"nativeIsConsumerRunningBehind", "()Z",
+    {"nativeIsConsumerRunningBehind", "(I)Z",
             (void*)nativeIsConsumerRunningBehind },
-    {"nativeLockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;",
+    {"nativeLockCanvas", "(ILandroid/graphics/Rect;)Landroid/graphics/Canvas;",
             (void*)nativeLockCanvas },
-    {"nativeUnlockCanvasAndPost", "(Landroid/graphics/Canvas;)V",
+    {"nativeUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
             (void*)nativeUnlockCanvasAndPost },
-    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
-            (void*)nativeScreenshot },
-    {"nativeOpenTransaction", "()V",
-            (void*)nativeOpenTransaction },
-    {"nativeCloseTransaction", "()V",
-            (void*)nativeCloseTransaction },
-    {"nativeSetAnimationTransaction", "()V",
-            (void*)nativeSetAnimationTransaction },
-    {"nativeSetLayer", "(I)V",
-            (void*)nativeSetLayer },
-    {"nativeSetPosition", "(FF)V",
-            (void*)nativeSetPosition },
-    {"nativeSetSize", "(II)V",
-            (void*)nativeSetSize },
-    {"nativeSetTransparentRegionHint", "(Landroid/graphics/Region;)V",
-            (void*)nativeSetTransparentRegionHint },
-    {"nativeSetAlpha", "(F)V",
-            (void*)nativeSetAlpha },
-    {"nativeSetMatrix", "(FFFF)V",
-            (void*)nativeSetMatrix },
-    {"nativeSetFlags", "(II)V",
-            (void*)nativeSetFlags },
-    {"nativeSetWindowCrop", "(Landroid/graphics/Rect;)V",
-            (void*)nativeSetWindowCrop },
-    {"nativeSetLayerStack", "(I)V",
-            (void*)nativeSetLayerStack },
-    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
-            (void*)nativeGetBuiltInDisplay },
-    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
-            (void*)nativeCreateDisplay },
-    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/view/Surface;)V",
-            (void*)nativeSetDisplaySurface },
-    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
-            (void*)nativeSetDisplayLayerStack },
-    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;ILandroid/graphics/Rect;Landroid/graphics/Rect;)V",
-            (void*)nativeSetDisplayProjection },
-    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
-            (void*)nativeGetDisplayInfo },
-    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
-            (void*)nativeBlankDisplay },
-    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
-            (void*)nativeUnblankDisplay },
-    {"nativeCopyFrom", "(Landroid/view/Surface;)V",
+    {"nativeCopyFrom", "(II)I",
             (void*)nativeCopyFrom },
-    {"nativeTransferFrom", "(Landroid/view/Surface;)V",
-            (void*)nativeTransferFrom },
-    {"nativeReadFromParcel", "(Landroid/os/Parcel;)V",
+    {"nativeReadFromParcel", "(ILandroid/os/Parcel;)I",
             (void*)nativeReadFromParcel },
-    {"nativeWriteToParcel", "(Landroid/os/Parcel;)V",
+    {"nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
             (void*)nativeWriteToParcel },
 };
 
@@ -887,38 +376,26 @@
 
     jclass clazz = env->FindClass("android/view/Surface");
     gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
-    gSurfaceClassInfo.mNativeSurface =
-            env->GetFieldID(gSurfaceClassInfo.clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    gSurfaceClassInfo.mNativeSurfaceControl =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeSurfaceControl", "I");
+    gSurfaceClassInfo.mNativeObject =
+            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I");
     gSurfaceClassInfo.mGenerationId =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
     gSurfaceClassInfo.mCanvas =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
-    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()V");
+    gSurfaceClassInfo.mCanvasSaveCount =
+            env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
+    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
 
     clazz = env->FindClass("android/graphics/Canvas");
-    gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
     gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
 
-    clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
-    gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
-
     clazz = env->FindClass("android/graphics/Rect");
     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
     gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
     gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
     gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
 
-    clazz = env->FindClass("android/view/Surface$PhysicalDisplayInfo");
-    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
-    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
-    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
-    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
-    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
-    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
-    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
     return err;
 }
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
new file mode 100644
index 0000000..e477e54
--- /dev/null
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceControl"
+
+#include <stdio.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "android/graphics/GraphicsJNI.h"
+#include "android/graphics/Region.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_SurfaceSession.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <utils/Log.h>
+
+#include <ScopedUtfChars.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static const char* const OutOfResourcesException =
+    "android/view/Surface$OutOfResourcesException";
+
+static struct {
+    jfieldID width;
+    jfieldID height;
+    jfieldID refreshRate;
+    jfieldID density;
+    jfieldID xDpi;
+    jfieldID yDpi;
+    jfieldID secure;
+} gPhysicalDisplayInfoClassInfo;
+
+
+class ScreenshotPixelRef : public SkPixelRef {
+public:
+    ScreenshotPixelRef(SkColorTable* ctable) {
+        fCTable = ctable;
+        SkSafeRef(ctable);
+        setImmutable();
+    }
+
+    virtual ~ScreenshotPixelRef() {
+        SkSafeUnref(fCTable);
+    }
+
+    status_t update(const sp<IBinder>& display, int width, int height,
+            int minLayer, int maxLayer, bool allLayers) {
+        status_t res = (width > 0 && height > 0)
+                ? (allLayers
+                        ? mScreenshot.update(display, width, height)
+                        : mScreenshot.update(display, width, height, minLayer, maxLayer))
+                : mScreenshot.update(display);
+        if (res != NO_ERROR) {
+            return res;
+        }
+
+        return NO_ERROR;
+    }
+
+    uint32_t getWidth() const {
+        return mScreenshot.getWidth();
+    }
+
+    uint32_t getHeight() const {
+        return mScreenshot.getHeight();
+    }
+
+    uint32_t getStride() const {
+        return mScreenshot.getStride();
+    }
+
+    uint32_t getFormat() const {
+        return mScreenshot.getFormat();
+    }
+
+protected:
+    // overrides from SkPixelRef
+    virtual void* onLockPixels(SkColorTable** ct) {
+        *ct = fCTable;
+        return (void*)mScreenshot.getPixels();
+    }
+
+    virtual void onUnlockPixels() {
+    }
+
+private:
+    ScreenshotClient mScreenshot;
+    SkColorTable*    fCTable;
+
+    typedef SkPixelRef INHERITED;
+};
+
+
+// ----------------------------------------------------------------------------
+
+static jint nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
+        jstring nameStr, jint w, jint h, jint format, jint flags) {
+    ScopedUtfChars name(env, nameStr);
+    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
+    sp<SurfaceControl> surface = client->createSurface(
+            String8(name.c_str()), w, h, format, flags);
+    if (surface == NULL) {
+        jniThrowException(env, OutOfResourcesException, NULL);
+        return 0;
+    }
+    surface->incStrong(clazz);
+    return int(surface.get());
+}
+
+static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
+    ctrl->decStrong(clazz);
+}
+
+static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
+    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
+    ctrl->clear();
+    ctrl->decStrong(clazz);
+}
+
+static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
+    /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
+        we can map to SkBitmap::kARGB_8888_Config, and optionally call
+        bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
+    */
+    switch (format) {
+    case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
+    case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
+    case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
+    case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
+    case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
+    default:                        return SkBitmap::kNo_Config;
+    }
+}
+
+static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
+        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
+    if (displayToken == NULL) {
+        return NULL;
+    }
+
+    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
+    if (pixels->update(displayToken, width, height,
+            minLayer, maxLayer, allLayers) != NO_ERROR) {
+        delete pixels;
+        return NULL;
+    }
+
+    uint32_t w = pixels->getWidth();
+    uint32_t h = pixels->getHeight();
+    uint32_t s = pixels->getStride();
+    uint32_t f = pixels->getFormat();
+    ssize_t bpr = s * android::bytesPerPixel(f);
+
+    SkBitmap* bitmap = new SkBitmap();
+    bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
+    if (f == PIXEL_FORMAT_RGBX_8888) {
+        bitmap->setIsOpaque(true);
+    }
+
+    if (w > 0 && h > 0) {
+        bitmap->setPixelRef(pixels)->unref();
+        bitmap->lockPixels();
+    } else {
+        // be safe with an empty bitmap.
+        delete pixels;
+        bitmap->setPixels(NULL);
+    }
+
+    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+}
+
+static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
+    SurfaceComposerClient::openGlobalTransaction();
+}
+
+static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
+    SurfaceComposerClient::closeGlobalTransaction();
+}
+
+static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
+    SurfaceComposerClient::setAnimationTransaction();
+}
+
+static void nativeSetLayer(JNIEnv* env, jclass clazz, jint nativeObject, jint zorder) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setLayer(zorder);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetPosition(JNIEnv* env, jclass clazz, jint nativeObject, jfloat x, jfloat y) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setPosition(x, y);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetSize(JNIEnv* env, jclass clazz, jint nativeObject, jint w, jint h) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setSize(w, h);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetFlags(JNIEnv* env, jclass clazz, jint nativeObject, jint flags, jint mask) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setFlags(flags, mask);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jint nativeObject, jobject regionObj) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+    if (!region) {
+        doThrowIAE(env);
+        return;
+    }
+
+    const SkIRect& b(region->getBounds());
+    Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
+    if (region->isComplex()) {
+        SkRegion::Iterator it(*region);
+        while (!it.done()) {
+            const SkIRect& r(it.rect());
+            reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
+            it.next();
+        }
+    }
+
+    status_t err = ctrl->setTransparentRegionHint(reg);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetAlpha(JNIEnv* env, jclass clazz, jint nativeObject, jfloat alpha) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setAlpha(alpha);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetMatrix(JNIEnv* env, jclass clazz, jint nativeObject,
+        jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jint nativeObject,
+        jint l, jint t, jint r, jint b) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    Rect crop(l, t, r, b);
+    status_t err = ctrl->setCrop(crop);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jint nativeObject, jint layerStack) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setLayerStack(layerStack);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
+static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
+    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
+    return javaObjectForIBinder(env, token);
+}
+
+static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
+        jboolean secure) {
+    ScopedUtfChars name(env, nameObj);
+    sp<IBinder> token(SurfaceComposerClient::createDisplay(
+            String8(name.c_str()), bool(secure)));
+    return javaObjectForIBinder(env, token);
+}
+
+static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jint nativeSurfaceObject) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+    sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
+    sp<IGraphicBufferProducer> bufferProducer(sur->getIGraphicBufferProducer());
+    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
+}
+
+static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jint layerStack) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+
+    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
+}
+
+static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jint orientation,
+        jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
+        jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+    Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
+    Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
+    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
+}
+
+static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jobject infoObj) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return JNI_FALSE;
+
+    DisplayInfo info;
+    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
+        return JNI_FALSE;
+    }
+
+    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
+    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
+    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
+    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
+    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
+    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
+    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+    return JNI_TRUE;
+}
+
+static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+
+    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
+    SurfaceComposerClient::blankDisplay(token);
+}
+
+static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+
+    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
+    SurfaceComposerClient::unblankDisplay(token);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod sSurfaceControlMethods[] = {
+    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)I",
+            (void*)nativeCreate },
+    {"nativeRelease", "(I)V",
+            (void*)nativeRelease },
+    {"nativeDestroy", "(I)V",
+            (void*)nativeDestroy },
+    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
+            (void*)nativeScreenshot },
+    {"nativeOpenTransaction", "()V",
+            (void*)nativeOpenTransaction },
+    {"nativeCloseTransaction", "()V",
+            (void*)nativeCloseTransaction },
+    {"nativeSetAnimationTransaction", "()V",
+            (void*)nativeSetAnimationTransaction },
+    {"nativeSetLayer", "(II)V",
+            (void*)nativeSetLayer },
+    {"nativeSetPosition", "(IFF)V",
+            (void*)nativeSetPosition },
+    {"nativeSetSize", "(III)V",
+            (void*)nativeSetSize },
+    {"nativeSetTransparentRegionHint", "(ILandroid/graphics/Region;)V",
+            (void*)nativeSetTransparentRegionHint },
+    {"nativeSetAlpha", "(IF)V",
+            (void*)nativeSetAlpha },
+    {"nativeSetMatrix", "(IFFFF)V",
+            (void*)nativeSetMatrix },
+    {"nativeSetFlags", "(III)V",
+            (void*)nativeSetFlags },
+    {"nativeSetWindowCrop", "(IIIII)V",
+            (void*)nativeSetWindowCrop },
+    {"nativeSetLayerStack", "(II)V",
+            (void*)nativeSetLayerStack },
+    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
+            (void*)nativeGetBuiltInDisplay },
+    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
+            (void*)nativeCreateDisplay },
+    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
+            (void*)nativeSetDisplaySurface },
+    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
+            (void*)nativeSetDisplayLayerStack },
+    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
+            (void*)nativeSetDisplayProjection },
+    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
+            (void*)nativeGetDisplayInfo },
+    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
+            (void*)nativeBlankDisplay },
+    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
+            (void*)nativeUnblankDisplay },
+};
+
+int register_android_view_SurfaceControl(JNIEnv* env)
+{
+    int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
+            sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
+
+    jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
+    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
+    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
+    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
+    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
+    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
+    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
+    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
+    return err;
+}
+
+};
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 64cbda3..e75a2d8 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -23,7 +23,7 @@
 #include <ui/Rect.h>
 
 #include <gui/GLConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 
 #include <SkBitmap.h>
 #include <SkCanvas.h>
@@ -43,16 +43,11 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
-    jfieldID mSurfaceFormat;
+    jfieldID nativeCanvas;
+    jfieldID surfaceFormat;
 } gCanvasClassInfo;
 
 static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -107,7 +102,7 @@
         jobject surface) {
 
     sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
-    sp<ANativeWindow> window = new SurfaceTextureClient(glConsumer->getBufferQueue());
+    sp<ANativeWindow> window = new Surface(glConsumer->getBufferQueue());
 
     window->incStrong(0);
     SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
@@ -125,15 +120,6 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-  env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
-  env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
-  SkSafeUnref(previousCanvas);
-}
-
 static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas, jobject dirtyRect) {
 
@@ -171,10 +157,9 @@
         bitmap.setPixels(NULL);
     }
 
-    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
-
-    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
+    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+    nativeCanvas->setBitmapDevice(bitmap);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -189,8 +174,8 @@
 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas) {
 
-    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+    nativeCanvas->setBitmapDevice(SkBitmap());
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -241,12 +226,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
-    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+    GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
+    GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
 
     FIND_CLASS(clazz, "android/view/TextureView");
     GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
new file mode 100644
index 0000000..0906593
--- /dev/null
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NetworkStats"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <cutils/logger.h>
+#include <jni.h>
+
+#include <ScopedUtfChars.h>
+#include <ScopedLocalRef.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+static jclass gStringClass;
+
+static struct {
+    jfieldID size;
+    jfieldID iface;
+    jfieldID uid;
+    jfieldID set;
+    jfieldID tag;
+    jfieldID rxBytes;
+    jfieldID rxPackets;
+    jfieldID txBytes;
+    jfieldID txPackets;
+    jfieldID operations;
+} gNetworkStatsClassInfo;
+
+struct stats_line {
+    int32_t idx;
+    char iface[32];
+    int32_t uid;
+    int32_t set;
+    int32_t tag;
+    int64_t rxBytes;
+    int64_t rxPackets;
+    int64_t txBytes;
+    int64_t txPackets;
+};
+
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
+        jstring path, jint limitUid) {
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return -1;
+    }
+
+    FILE *fp = fopen(path8.c_str(), "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    Vector<stats_line> lines;
+
+    int lastIdx = 1;
+    char buffer[384];
+    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+        stats_line s;
+        int64_t rawTag;
+        if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx,
+                &s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
+                &s.txBytes, &s.txPackets) == 9) {
+            if (s.idx != lastIdx + 1) {
+                ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx);
+                return -1;
+            }
+            lastIdx = s.idx;
+
+            s.tag = rawTag >> 32;
+            lines.push_back(s);
+        }
+    }
+
+    if (fclose(fp) != 0) {
+        return -1;
+    }
+
+    int size = lines.size();
+
+    ScopedLocalRef<jobjectArray> iface(env, env->NewObjectArray(size, gStringClass, NULL));
+    if (iface.get() == NULL) return -1;
+    ScopedIntArrayRW uid(env, env->NewIntArray(size));
+    if (uid.get() == NULL) return -1;
+    ScopedIntArrayRW set(env, env->NewIntArray(size));
+    if (set.get() == NULL) return -1;
+    ScopedIntArrayRW tag(env, env->NewIntArray(size));
+    if (tag.get() == NULL) return -1;
+    ScopedLongArrayRW rxBytes(env, env->NewLongArray(size));
+    if (rxBytes.get() == NULL) return -1;
+    ScopedLongArrayRW rxPackets(env, env->NewLongArray(size));
+    if (rxPackets.get() == NULL) return -1;
+    ScopedLongArrayRW txBytes(env, env->NewLongArray(size));
+    if (txBytes.get() == NULL) return -1;
+    ScopedLongArrayRW txPackets(env, env->NewLongArray(size));
+    if (txPackets.get() == NULL) return -1;
+    ScopedLongArrayRW operations(env, env->NewLongArray(size));
+    if (operations.get() == NULL) return -1;
+
+    for (int i = 0; i < size; i++) {
+        ScopedLocalRef<jstring> ifaceString(env, env->NewStringUTF(lines[i].iface));
+        env->SetObjectArrayElement(iface.get(), i, ifaceString.get());
+
+        uid[i] = lines[i].uid;
+        set[i] = lines[i].set;
+        tag[i] = lines[i].tag;
+        rxBytes[i] = lines[i].rxBytes;
+        rxPackets[i] = lines[i].rxPackets;
+        txBytes[i] = lines[i].txBytes;
+        txPackets[i] = lines[i].txPackets;
+    }
+
+    env->SetIntField(stats, gNetworkStatsClassInfo.size, size);
+    env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
+    env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
+
+    return 0;
+}
+
+static jclass findClass(JNIEnv* env, const char* name) {
+    ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
+    jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
+    if (result == NULL) {
+        ALOGE("failed to find class '%s'", name);
+        abort();
+    }
+    return result;
+}
+
+static JNINativeMethod gMethods[] = {
+        { "nativeReadNetworkStatsDetail",
+                "(Landroid/net/NetworkStats;Ljava/lang/String;I)I",
+                (void*) readNetworkStatsDetail }
+};
+
+int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
+    int err = AndroidRuntime::registerNativeMethods(env,
+            "com/android/internal/net/NetworkStatsFactory", gMethods,
+            NELEM(gMethods));
+
+    gStringClass = findClass(env, "java/lang/String");
+
+    jclass clazz = env->FindClass("android/net/NetworkStats");
+    gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
+    gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
+    gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
+    gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
+    gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I");
+    gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J");
+    gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J");
+    gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J");
+    gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J");
+    gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J");
+
+    return err;
+}
+
+}
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 199d5bf..37330ec 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -28,7 +28,7 @@
 
 #include <gui/Surface.h>
 #include <gui/GLConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
@@ -355,7 +355,7 @@
     
     sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(_env, native_window));
 
-    window = new SurfaceTextureClient(glConsumer->getBufferQueue());
+    window = new Surface(glConsumer->getBufferQueue());
     if (window == NULL)
         goto not_valid_surface;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6f8dc120..8a53cc3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -129,6 +129,7 @@
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
     <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
+    <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
 
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
@@ -644,7 +645,7 @@
         android:protectionLevel="normal"
         android:description="@string/permdesc_accessWifiState"
         android:label="@string/permlab_accessWifiState" />
-        
+
     <!-- Allows applications to change Wi-Fi connectivity state -->
     <permission android:name="android.permission.CHANGE_WIFI_STATE"
         android:permissionGroup="android.permission-group.NETWORK"
@@ -684,14 +685,14 @@
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_bluetooth"
         android:label="@string/permlab_bluetooth" />
-        
+
     <!-- Allows applications to discover and pair bluetooth devices -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
         android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_bluetoothAdmin"
         android:label="@string/permlab_bluetoothAdmin" />
-   
+
     <!-- Allows bluetooth stack to access files
          @hide This should only be used by Bluetooth apk.
     -->
@@ -722,7 +723,7 @@
     <permission android:name="android.permission.LOOP_RADIO"
 	android:permissionGroup="android.permission-group.NETWORK"
 	android:protectionLevel="signature|system" />
-    
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -1132,7 +1133,7 @@
         android:protectionLevel="signature|system"
         android:label="@string/permlab_manageUsers"
         android:description="@string/permdesc_manageUsers" />
-    
+
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
@@ -1674,7 +1675,7 @@
         android:label="@string/permlab_freezeScreen"
         android:description="@string/permdesc_freezeScreen"
         android:protectionLevel="signature" />
-    
+
     <!-- Allows an application to inject user events (keys, touch, trackball)
          into the event stream and deliver them to ANY window.  Without this
          permission, you can only deliver events to windows in your own process.
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ac422ea..4cb7888 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -618,7 +618,7 @@
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verander verrekening van netwerkgebruik"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string>
-    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings te herwin, bestudeer en te verwyder, met inbegrip van daardie kennisgewings wat deur ander programme geplaas is."</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 40fc411..5e3c56b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1291,7 +1291,7 @@
     <item quantity="one" msgid="8167147081136579439">"1 αποτέλεσμα"</item>
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> από <xliff:g id="TOTAL">%d</xliff:g>"</item>
   </plurals>
-    <string name="action_mode_done" msgid="7217581640461922289">"Ολοκληρώθηκε"</string>
+    <string name="action_mode_done" msgid="7217581640461922289">"Τέλος"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Αποσύνδεση του χώρου αποθήκευσης USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Αφαίρεση κάρτας SD..."</string>
     <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Διαγραφή χώρου αποθήκευσης USB..."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a472123..d74810a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1062,7 +1062,7 @@
     <string name="noApplications" msgid="2991814273936504689">"Egy alkalmazás sem tudja végrehajtani ezt a műveletet."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás sajnos leállt."</string>
-    <string name="aerr_process" msgid="4507058997035697579">"Sajnos a(z) <xliff:g id="PROCESS">%1$s</xliff:g> folyamat leállt."</string>
+    <string name="aerr_process" msgid="4507058997035697579">"Sajnos a <xliff:g id="PROCESS">%1$s</xliff:g> alkalmazás leállt."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"A(z) <xliff:g id="APPLICATION">%2$s</xliff:g> nem válaszol."\n\n"Szeretné bezárni?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> tevékenység nem válaszol."\n\n"Szeretné bezárni?"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 186eb3e..7f7d6d2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1054,7 +1054,7 @@
     <string name="loading" msgid="7933681260296021180">"A carregar…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
     <string name="capital_off" msgid="6815870386972805832">"Desactivar"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Concluir acção utilizando"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Concluir ação utilizando"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Limpar a predefinição nas Definições do Sistema &gt; Aplicações &gt; Transferidas."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Escolha uma ação"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e7df782..af28134 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -618,7 +618,7 @@
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
-    <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกคืน ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7f80706..ce5fdc06 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1062,7 +1062,7 @@
     <string name="noApplications" msgid="2991814273936504689">"Жодна програма не може виконати цю дію."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"На жаль, програма <xliff:g id="APPLICATION">%1$s</xliff:g> припинила роботу."</string>
-    <string name="aerr_process" msgid="4507058997035697579">"На жаль, процес <xliff:g id="PROCESS">%1$s</xliff:g> припинився."</string>
+    <string name="aerr_process" msgid="4507058997035697579">"На жаль, програма <xliff:g id="PROCESS">%1$s</xliff:g> припинила роботу."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"Програма <xliff:g id="APPLICATION">%2$s</xliff:g> не відповідає."\n\n"Закрити її?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"Дія <xliff:g id="ACTIVITY">%1$s</xliff:g> не відповідає."\n\n"Закінчити її?"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 70797cb..7edb530 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -776,7 +776,7 @@
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Thử lại"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Đã vượt quá số lần Mở khóa bằng khuôn mặt tối đa"</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="lockscreen_charged" msgid="321635745684060624">"Bị tính phí"</string>
+    <string name="lockscreen_charged" msgid="321635745684060624">"Pin đầy"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Kết nối bộ sạc của bạn."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Không có thẻ SIM nào"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0fb8a10..c73ff81 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -312,6 +312,8 @@
         <attr name="windowNoTitle" format="boolean" />
         <!-- Flag indicating whether this window should fill the entire screen. -->
         <attr name="windowFullscreen" format="boolean" />
+        <!-- Flag indicating whether this window should extend into overscan region. -->
+        <attr name="windowOverscan" format="boolean" />
         <!-- Flag indicating whether this is a floating window. -->
         <attr name="windowIsFloating" format="boolean" />
         <!-- Flag indicating whether this is a translucent window. -->
@@ -1562,6 +1564,7 @@
         <attr name="windowFrame" />
         <attr name="windowNoTitle" />
         <attr name="windowFullscreen" />
+        <attr name="windowOverscan" />
         <attr name="windowIsFloating" />
         <attr name="windowIsTranslucent" />
         <attr name="windowShowWallpaper" />
@@ -3061,6 +3064,14 @@
         <attr name="textColorLink" />
         <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
         <attr name="textAllCaps" format="boolean" />
+        <!-- Place a shadow of the specified color behind the text. -->
+        <attr name="shadowColor" format="color" />
+        <!-- Horizontal offset of the shadow. -->
+        <attr name="shadowDx" format="float" />
+        <!-- Vertical offset of the shadow. -->
+        <attr name="shadowDy" format="float" />
+        <!-- Radius of the shadow. -->
+        <attr name="shadowRadius" format="float" />
     </declare-styleable>
     <declare-styleable name="TextClock">
         <!-- Specifies the formatting pattern used to show the time and/or date
@@ -3195,13 +3206,13 @@
              specified number. -->
         <attr name="maxLength" format="integer" min="0" />
         <!-- Place a shadow of the specified color behind the text. -->
-        <attr name="shadowColor" format="color" />
+        <attr name="shadowColor" />
         <!-- Horizontal offset of the shadow. -->
-        <attr name="shadowDx" format="float" />
+        <attr name="shadowDx" />
         <!-- Vertical offset of the shadow. -->
-        <attr name="shadowDy" format="float" />
+        <attr name="shadowDy" />
         <!-- Radius of the shadow. -->
-        <attr name="shadowRadius" format="float" />
+        <attr name="shadowRadius" />
         <attr name="autoLink" />
         <!-- If set to false, keeps the movement method from being set
              to the link movement method even if autoLink causes links
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0d80082..42e5cf1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2036,4 +2036,18 @@
   <public type="attr" name="mipMap" id="0x010103cd" />
   <public type="attr" name="mirrorForRtl" id="0x010103ce" />
 
+    <!-- ===============================================================
+         Resources added in version 19 of the platform
+         =============================================================== -->
+      <eat-comment />
+
+  <public type="attr" name="windowOverscan" />
+  <public type="style" name="Theme.NoTitleBar.Overscan" />
+  <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
+  <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
+  <public type="style" name="Theme.Holo.NoActionBar.Overscan" />
+  <public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
+  <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
+  <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Overscan" />
+
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 75850dd..411419b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -166,6 +166,7 @@
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
+        <item name="windowOverscan">false</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -403,6 +404,14 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
+    <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
+        into the display overscan region. -->
+    <style name="Theme.NoTitleBar.Overscan">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Theme for a light background with dark text on top.  Set your activity
          to this theme if you would like such an appearance.  As with the
          default theme, you should try to assume little more than that the
@@ -495,6 +504,14 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
+    <!-- Variant of {@link #Theme_Light} that has no title bar and
+         no status bar and extending into the display overscan region. -->
+    <style name="Theme.Light.NoTitleBar.Overscan">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Variant on {@link #Theme} that ensures the background is
          completely black.  This is useful for things like image viewers and
          media players.   If you want the normal (dark background) theme
@@ -516,6 +533,14 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
+    <!-- Variant of {@link #Theme_Black} that has no title bar and
+         no status bar and extending into the display overscan region. -->
+    <style name="Theme.Black.NoTitleBar.Overscan">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Theme for windows that want to have the user's selected
          wallpaper appear behind them (for API level 10 and lower).  -->
     <style name="Theme.Wallpaper">
@@ -1010,6 +1035,7 @@
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
+        <item name="windowOverscan">false</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -1324,6 +1350,7 @@
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
+        <item name="windowOverscan">false</item>
         <item name="windowIsFloating">false</item>
         <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
         <item name="windowShowWallpaper">false</item>
@@ -1563,6 +1590,14 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
+    <!-- Variant of the holographic (dark) theme that has no title bar and fills
+         the entire screen and extends into the display overscan region. -->
+    <style name="Theme.Holo.NoActionBar.Overscan">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Variant of the holographic (light) theme with no action bar. -->
     <style name="Theme.Holo.Light.NoActionBar">
         <item name="android:windowActionBar">false</item>
@@ -1576,6 +1611,14 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
  
+    <!-- Variant of the holographic (light) theme that has no title bar and fills
+         the entire screen and extends into the display overscan region. -->
+    <style name="Theme.Holo.Light.NoActionBar.Overscan">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <!-- Dialog themes for Holo -->
     <eat-comment />
 
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 4178cc4..71aa5e6 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -202,12 +202,17 @@
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
     <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
-
     </style>
+
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
-
     </style>
+
+    <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
+    extending in to overscan region. -->
+    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Holo.NoActionBar.Overscan" >
+    </style>
+
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
     <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
         <!-- Text styles -->
@@ -356,11 +361,14 @@
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
-
     </style>
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
-
+    </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
+    and extending in to overscan region-->
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
+           parent="Theme.Holo.Light.NoActionBar.Overscan" >
     </style>
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
     floating (not fill the entire screen), and puts a frame around its contents. You can set this
diff --git a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
new file mode 100644
index 0000000..2174be5
--- /dev/null
+++ b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
@@ -0,0 +1,54 @@
+/*
+ * 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.internal.net;
+
+import android.net.NetworkStats;
+import android.os.SystemClock;
+
+import com.google.caliper.SimpleBenchmark;
+
+import java.io.File;
+
+public class NetworkStatsFactoryBenchmark extends SimpleBenchmark {
+    private File mStats;
+
+    // TODO: consider staging stats file with different number of rows
+
+    @Override
+    protected void setUp() {
+        mStats = new File("/proc/net/xt_qtaguid/stats");
+    }
+
+    @Override
+    protected void tearDown() {
+        mStats = null;
+    }
+
+    public void timeReadNetworkStatsDetailJava(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            NetworkStatsFactory.javaReadNetworkStatsDetail(mStats, NetworkStats.UID_ALL);
+        }
+    }
+
+    public void timeReadNetworkStatsDetailNative(int reps) {
+        for (int i = 0; i < reps; i++) {
+            final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+            NetworkStatsFactory.nativeReadNetworkStatsDetail(
+                    stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL);
+        }
+    }
+}
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 782a701..01d22ee 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -480,7 +480,7 @@
 ### Gamepad buttons ###
 
 key BUTTON_A {
-    base:                               fallback BACK
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_B {
@@ -488,7 +488,7 @@
 }
 
 key BUTTON_C {
-    base:                               fallback BACK
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_X {
@@ -496,7 +496,7 @@
 }
 
 key BUTTON_Y {
-    base:                               fallback DPAD_CENTER
+    base:                               fallback BACK
 }
 
 key BUTTON_Z {
@@ -528,7 +528,7 @@
 }
 
 key BUTTON_START {
-    base:                               fallback HOME
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_SELECT {
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index d90b790..c4647e0 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -477,7 +477,7 @@
 ### Gamepad buttons ###
 
 key BUTTON_A {
-    base:                               fallback BACK
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_B {
@@ -485,7 +485,7 @@
 }
 
 key BUTTON_C {
-    base:                               fallback BACK
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_X {
@@ -493,7 +493,7 @@
 }
 
 key BUTTON_Y {
-    base:                               fallback DPAD_CENTER
+    base:                               fallback BACK
 }
 
 key BUTTON_Z {
@@ -525,7 +525,7 @@
 }
 
 key BUTTON_START {
-    base:                               fallback HOME
+    base:                               fallback DPAD_CENTER
 }
 
 key BUTTON_SELECT {
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index 6cd6f9d..acb2538 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -331,14 +331,14 @@
 appropriate.</p>
 
 <p>For precise control over your app UI, Android 4.2 includes new APIs that let
-you manage layout direction, text direction, text alignment, gravity, and locale
-direction in View components. You can even create custom versions of layout,
-drawables, and other resources for display when a right-to-left script is in
-use.</p>
+you manage layout direction, text direction, text alignment, gravity, and 
+locale direction in View components. You can even create custom versions of
+layout, drawables, and other resources for display when a right-to-left script
+is in use.</p>
 
 <p>To help you debug and optimize your custom right-to-left layouts, the
 HierarchyViewer tool now lets you see start/end properties, layout direction,
-text direction, and text alignment for all the Views in the hierarchy,</p>
+text direction, and text alignment for all the Views in the hierarchy.</p>
 
 
 <h2 id="42-intl">Enhancements for international languages</h2>
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/googleplay/promote/badges.jd
index 23a116d..738e76b 100644
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ b/docs/html/distribute/googleplay/promote/badges.jd
@@ -86,10 +86,11 @@
 
   if (form["package"].value != "com.example.android") {
     $("#preview").show();
-    $("#snippet").show().html(linkStartCode + "apps/details?id=" + form["package"].value
+    var packageName = escapeHTML(form["package"].value);
+    $("#snippet").show().html(linkStartCode + "apps/details?id=" + packageName
             + imageStartCode + altText + imageSrcCode
             + selectedValue + imageEndCode);
-    $("#button-preview").html(linkStart + "apps/details?id=" + form["package"].value
+    $("#button-preview").html(linkStart + "apps/details?id=" + packageName
             + imageStart + altText + imageSrc
             + selectedValue + imageEnd);
             
@@ -97,10 +98,11 @@
     _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue]);
   } else if (form["publisher"].value != "Example, Inc.") {
     $("#preview").show();
-    $("#snippet").show().html(linkStartCode + "search?q=pub:" + form["publisher"].value
+    var publisherName = escapeHTML(form["publisher"].value);
+    $("#snippet").show().html(linkStartCode + "search?q=pub:" + publisherName
             + imageStartCode + altText + imageSrcCode
             + selectedValue + imageEndCode);
-    $("#button-preview").html(linkStart + "search?q=pub:" + form["publisher"].value
+    $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
             + imageStart + altText + imageSrc
             + selectedValue + imageEnd);
    
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 8b09fe6..81982a1 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -80,6 +80,9 @@
               <span class="en">Reference</span></a></li>
               </ul>
       </li>
+      <li><a href="<?cs var:toroot?>google/play/billing/billing_subscriptions.html">
+              <span class="en">Subscriptions</span></a>
+      </li>
       <li><a href="<?cs var:toroot?>google/play/billing/billing_best_practices.html">
               <span class="en">Security and Design</span></a>
       </li>
diff --git a/docs/html/google/play/billing/api.jd b/docs/html/google/play/billing/api.jd
index 9091f51..3d46715 100644
--- a/docs/html/google/play/billing/api.jd
+++ b/docs/html/google/play/billing/api.jd
@@ -11,12 +11,13 @@
     <li><a href="#producttypes">Product Types</a>
        <ol>
        <li><a href="#managed">Managed In-app Products</a><li>
+       <li><a href="#subs">Subscriptions</a><li>
        </ol>
     </li>
     <li><a href="#purchase">Purchasing Items</a></li>
-    <li><a href="#consume">Consuming Items</a>
+    <li><a href="#consume">Consuming In-app Products</a>
        <ol>
-       <li><a href="#consumetypes">Non-consumable and Consumable Items</a><li>
+       <li><a href="#consumetypes">Non-consumable and Consumable In-app Products</a><li>
        <li><a href="#managingconsumables">Managing Consumable Purchases</a><li>
        </ol>
     </li>
@@ -40,11 +41,22 @@
 
 <h2 id="producttypes">Product Types</h2>
 <p>You define your products using the Google Play Developer Console, including product type, SKU, price, description, and so on. For more information, see <a
-href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app Billing</a>. The Version 3 API only supports the managed in-app product type.</p>
+href="{@docRoot}google/play/billing/billing_admin.html">Administering In-app Billing</a>. The Version 3 API supports managed in-app products and subscriptions.</p>
 <h3 id="managed">Managed In-app Products</h3>
 <p>Managed in-app products are items that have their ownership information tracked and managed by Google Play. When a user purchases a managed in-app item, Google Play stores the purchase information for each item on a per-user basis. This enables you to later query Google Play at any time to restore the state of the items a specific user has purchased. This information is persistent on the Google Play servers even if the user uninstalls the application or if they change devices.</p>
 <p>If you are using the Version 3 API, you can also consume managed items within your application. You would typically implement consumption for items that can be purchased multiple times (such as in-game currency, fuel, or magic spells). Once purchased, a managed item cannot be purchased again until you consume the item, by sending a consumption request to Google Play. To learn more about in-app product consumption, see <a href="#consume">Consuming Items</a></p>
 
+<h3 id="subs">Subscriptions</h3>
+<p>A subscription is a product type offered in In-app Billing that lets you sell 
+content, services, or features to users from inside your app with recurring 
+monthly or annual billing. You can sell subscriptions to almost any type of 
+digital content, from any type of app or game. To understand how  
+subscriptions work, see <a href="{@docRoot}google/play/billing/billing_subscriptions.html">In-app Billing Subscriptions</a>.</p>
+<p>With the Version 3 API, you can use the same purchase flow for buying 
+subscriptions and retrieving subscription purchase information as with in-app 
+products. For a code example, see <a href="{@docRoot}google/play/billing/billing_integrate.html#Subs">Implementing Subscriptions</a>.</p>
+<p class="caution"><strong>Important</strong>: Unlike in-app products, 
+subscriptions cannot be consumed.</p>
 
 <h2 id="purchase">Purchasing Items</h2>
 
@@ -72,29 +84,38 @@
 </p>
 <p>To learn more about the Version 3 API calls and server responses, see <a href="{@docRoot}google/play/billing/billing_reference.html">In-app Billing Reference</a>.</p>
 
-<h2 id="consume">Consuming Items</h2>
-<p>You can use the consumption mechanism to track the user's ownership of in-app products.</p>
-<p>In Version 3, all in-app products are managed. This means that the user's ownership of all in-app item purchases is maintained by Google Play, and your application can query the user's purchase information when needed. When the user successfully purchases an item, that purchase is recorded in Google Play. Once an item is purchased, it is considered to be "owned". Items in the "owned" state cannot be purchased from Google Play. You must send a consumption request for the "owned" item before Google Play makes it available for purchase again. Consuming the item reverts it to the "unowned" state, and discards the previous purchase data.</p>
+<h2 id="consume">Consuming In-app Products</h2>
+<p>You can use the consumption mechanism to track the user's ownership of in-app 
+products.</p>
+<p>In Version 3, all in-app products are managed. This means that the user's 
+ownership of all in-app item purchases is maintained by Google Play, and your 
+application can query the user's purchase information when needed. When the user 
+successfully purchases an in-app product, that purchase is recorded in Google 
+Play. Once an in-app product is purchased, it is considered to be "owned". 
+In-app products in the "owned" state cannot be purchased from Google Play. You 
+must send a consumption request for the "owned" in-app product before Google 
+Play makes it available for purchase again. Consuming the in-app product reverts 
+it to the "unowned" state, and discards the previous purchase data.</p>
 <div class="figure" style="width:420px">
 <img src="{@docRoot}images/in-app-billing/v3/iab_v3_consumption_flow.png" id="figure2" height="300"/>
 <p class="img-caption">
   <strong>Figure 2.</strong> The basic sequence for a consumption request.
 </p>
 </div>
-<p>To retrieve the list of product's owned by the user, your application sends a {@code getPurchases} call to Google Play. Your application can make a consumption request by sending a {@code consumePurchase} call. In the request argument, you must specify the item's unique {@code purchaseToken} String that you obtained from Google Play when it was purchased. Google Play returns a status code indicating if the consumption was recorded successfully.</p>
+<p>To retrieve the list of product's owned by the user, your application sends a {@code getPurchases} call to Google Play. Your application can make a consumption request by sending a {@code consumePurchase} call. In the request argument, you must specify the in-app product's unique {@code purchaseToken} String that you obtained from Google Play when it was purchased. Google Play returns a status code indicating if the consumption was recorded successfully.</p>
 
-<h3 id="consumetypes">Non-consumable and Consumable Items</h3>
+<h3 id="consumetypes">Non-consumable and Consumable In-app Products</h3>
 <p>It's up to you to decide if you want to handle your in-app products as non-consumable or consumable items.</p>
 <dl>
 <dt>Non-consumable Items</dt>
-<dd>Typically, you would not implement consumption for items that can only be purchased once in your application and provide a permanent benefit. Once purchased, these items will be permanently associated to the user's Google account. An example of a non-consumable item is a premium upgrade or a level pack.</dd>
+<dd>Typically, you would not implement consumption for in-app products that can only be purchased once in your application and provide a permanent benefit. Once purchased, these items will be permanently associated to the user's Google account. An example of a non-consumable in-app product is a premium upgrade or a level pack.</dd>
 <dt>Consumable items</dt>
 <dd>In contrast, you can implement consumption for items that can be made available for purchase multiple times. Typically, these items provide certain temporary effects. For example, the user's in-game character might gain life points or gain extra gold coins in their inventory. Dispensing the benefits or effects of the purchased item in your application is called <em>provisioning</em> the in-app product. You are responsible for controlling and tracking how in-app products are provisioned to the users.
-<p class="note"><strong>Important:</strong> Before provisioning the consumable item in your application, you must send a consumption request to Google Play and receive a successful response indicating that the consumption was recorded.</p>
+<p class="note"><strong>Important:</strong> Before provisioning the consumable in-app product in your application, you must send a consumption request to Google Play and receive a successful response indicating that the consumption was recorded.</p>
 </dd>
 </dl>
 <h3 id="managingconsumables">Managing consumable purchases in your application</h3>
-<p>Here is the basic flow for purchasing a consumable item:</p>
+<p>Here is the basic flow for purchasing a consumable in-app product:</p>
 <ol>
 <li>Launch a purchase flow with a {@code getBuyIntent} call</li>
 <li>Get a response {@code Bundle}from Google Play indicating if the purchase completed successfully.</li>
@@ -102,10 +123,10 @@
 <li>Get a response code from Google Play indicating if the consumption completed successfully.</li>
 <li>If the consumption was successful, provision the product in your application.</li>
 </ol>
-<p>Subsequently, when the user starts up or logs in to your application, you should check if the user owns any outstanding consumable items; if so, make sure to consume and provision those items. Here's the recommended application startup flow if you implement consumable items in your application:</p>
+<p>Subsequently, when the user starts up or logs in to your application, you should check if the user owns any outstanding consumable in-app products; if so, make sure to consume and provision those items. Here's the recommended application startup flow if you implement consumable in-app products in your application:</p>
 <ol>
-<li>Send a {@code getPurchases} request to query the owned items for the user.</li>
-<li>If there are any consumable items, consume the items by calling {@code consumePurchase}. This step is necessary because the application might have completed the purchase order for the consumable item, but stopped or got disconnected before the application had the chance to send a consumption request.</li>
+<li>Send a {@code getPurchases} request to query the owned in-app products for the user.</li>
+<li>If there are any consumable in-app products, consume the items by calling {@code consumePurchase}. This step is necessary because the application might have completed the purchase order for the consumable item, but stopped or got disconnected before the application had the chance to send a consumption request.</li>
 <li>Get a response code from Google Play indicating if the consumption completed successfully.</li>
 <li>If the consumption was successful, provision the product in your application.</li>
 </ol>
diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
index 315befa..297e906 100644
--- a/docs/html/google/play/billing/billing_integrate.jd
+++ b/docs/html/google/play/billing/billing_integrate.jd
@@ -16,6 +16,7 @@
        <li><a href="#Purchase">Purchasing an Item</a></li>
        <li><a href="#QueryPurchases">Querying Purchased Items</a></li>
        <li><a href="#Consume">Consuming a Purchase</a><li>
+       <li><a href="#Subs">Implementing Subscriptions</a><li>
        </ol>
     </li>
   </ol>
@@ -176,7 +177,7 @@
 </pre>
 
 <h3 id="Purchase">Purchasing an Item</h3>
-<p>To start a purchase request from your app, call the {@code getBuyIntent} method on the In-app Billing service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, the product ID for the item to purchase, the purchase type (“inapp”), and a {@code developerPayload} String. The {@code developerPayload} String is used to  specify any additional arguments that you want Google Play to send back along with the purchase information.</p>
+<p>To start a purchase request from your app, call the {@code getBuyIntent} method on the In-app Billing service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, the product ID for the item to purchase, the purchase type (“inapp” or "subs"), and a {@code developerPayload} String. The {@code developerPayload} String is used to  specify any additional arguments that you want Google Play to send back along with the purchase information.</p>
 
 <pre>
 Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
@@ -238,7 +239,7 @@
 <p class="note"><strong>Security Recommendation:</strong> When you send a purchase request, create a String token that uniquely identifies this purchase request and include this token in the {@code developerPayload}.You can use a randomly generated string as the token. When you receive the purchase response from Google Play, make sure to check the returned data signature, the {@code orderId}, and the {@code developerPayload} String. For added security, you should perform the checking on your own secure server. Make sure to verify that the {@code orderId} is a unique value that you have not previously processed, and the {@code developerPayload} String matches the token that you sent previously with the purchase request.</p>
 
 <h3 id="QueryPurchases">Querying for Purchased Items</h3>
-<p>To retrieve information about purchases made by a user from your app, call the {@code getPurchases} method on the In-app Billing Version 3 service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, and the purchase type (“inapp”).</p>
+<p>To retrieve information about purchases made by a user from your app, call the {@code getPurchases} method on the In-app Billing Version 3 service. Pass in to the method the In-app Billing API version (“3”), the package name of your calling app, and the purchase type (“inapp” or "subs").</p>
 <pre>
 Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
 </pre>
@@ -273,8 +274,26 @@
 </pre>
 
 <h3 id="Consume">Consuming a Purchase</h3>
-<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased from Google Play. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or equipment). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
-<p>To record a purchase consumption, send the {@code consumePurchase} method to the In-app Billing service and pass in the {@code purchaseToken} String value that identifies the purchase to be removed. The {@code purchaseToken} is part of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google Play service following a successful purchase request. In this example, you are recording the consumption of a product that is identified with the {@code purchaseToken} in the {@code token} variable.</p>
+<p>You can use the In-app Billing Version 3 API to track the ownership of 
+purchased in-app products in Google Play. Once an in-app product is purchased, 
+it is considered to be "owned" and cannot be purchased from Google Play. You 
+must send a consumption request for the in-app product before Google Play makes 
+it available for purchase again.</p>
+<p class="caution"><strong>Important</strong>: Managed in-app products are 
+consumable, but subscriptions are not.</p>
+<p>How you use the consumption mechanism in your app is up to you. Typically, 
+you would implement consumption for in-app products with temporary benefits that 
+users may want to purchase multiple times (for example, in-game currency or 
+equipment). You would typically not want to implement consumption for in-app 
+products that are purchased once and provide a permanent effect (for example, 
+a premium upgrade).</p>
+<p>To record a purchase consumption, send the {@code consumePurchase} method to 
+the In-app Billing service and pass in the {@code purchaseToken} String value 
+that identifies the purchase to be removed. The {@code purchaseToken} is part 
+of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google 
+Play service following a successful purchase request. In this example, you are 
+recording the consumption of a product that is identified with the 
+{@code purchaseToken} in the {@code token} variable.</p>
 <pre>
 int response = mService.consumePurchase(3, getPackageName(), token);
 </pre>
@@ -282,6 +301,33 @@
 <p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
 <p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
 
+<h3 id="Subs">Implementing Subscriptions</h3>
+<p>Launching a purchase flow for a subscription is similar to launching the 
+purchase flow for a product, with the exception that the product type must be set 
+to "subs". The purchase result is delivered to your Activity's 
+{@link android.app.Activity#onActivityResult onActivityResult} method, exactly 
+as in the case of in-app products.</p>
+<pre>
+Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
+   MY_SKU, "subs", developerPayload);
+
+PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
+if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
+   // Start purchase flow (this brings up the Google Play UI).
+   // Result will be delivered through onActivityResult().
+   startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(),
+       Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
+}
+</pre>
+<p>To query for active subscriptions, use the {@code getPurchases} method, again 
+with the product type parameter set to "subs".</p>
+<pre>
+Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
+                   "subs", continueToken);
+</pre>
+<p>The call returns a {@code Bundle} with all the active subscriptions owned by 
+the user. Once a subscription expires without renewal, it will no longer appear 
+in the returned {@code Bundle}.</p>
 
 
 
diff --git a/docs/html/google/play/billing/billing_overview.jd b/docs/html/google/play/billing/billing_overview.jd
index aa48fc8..14cbfdf 100644
--- a/docs/html/google/play/billing/billing_overview.jd
+++ b/docs/html/google/play/billing/billing_overview.jd
@@ -7,9 +7,12 @@
 <div id="qv">
   <h2>Quickview</h2>
   <ul>
-    <li>Use In-app Billing to sell digital goods, including one-time items and recurring subscriptions.</li>
-    <li>Supported for any app published on Google Play. You only need a Google Play publisher account and a Google Checkout Merchant account.</li>
-    <li>Checkout processing is automatically handled by Google Play, with the same look-and-feel as for app purchases.</li>
+    <li>Use In-app Billing to sell digital goods, including one-time items and 
+recurring subscriptions.</li>
+    <li>Supported for any app published on Google Play. You only need a Google 
+Play Developer Console account and a Google Checkout Merchant account.</li>
+    <li>Checkout processing is automatically handled by Google Play, with the 
+same look-and-feel as for app purchases.</li>
   </ul>
   <h2>In this document</h2>
   <ol>
@@ -21,14 +24,12 @@
     </li>
     <li><a href="#console">Google Play Developer Console</a></li>
     <li><a href="#checkout">Google Play Purchase Flow</a></li>
-    <li><a href="#samples">Sample Apps</a></li> 
+    <li><a href="#samples">Sample App</a></li> 
     <li><a href="#migration">Migration Considerations</a></li>
   </ol>
    <h2>Related Samples</h2>
   <ol>
     <li><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">Sample Application (V3)</a></li>
-    <li><a href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">Sample
-    Application (V2)</a></li>
   </ol> 
 </div>
 </div>
@@ -51,10 +52,12 @@
 through Google Play. To complete in-app purchase requests, the Google Play app 
 must be able to access the Google Play server over the network.</p>
 
-<p>Currently, Google Play supports two versions of the In-app Billing API. 
-To determine which version you should use, see <a href="#migration">Migration 
-Considerations</a>.</p>
-<h4><a href="{@docRoot}google/play/billing/api.html">Version 3</a> (recommended)</h4>
+<p>In-app billing Version 3 is the latest version, and maintains very broad 
+compatibility across the range of Android devices. In-app Billing Version 3 is 
+supported on devices running Android 2.2 or higher that have the latest version 
+of the Google Play store installed (<a href="{@docRoot}about/dashboards/index.html">a vast majority</a> of active devices).</p>
+
+<h4>Version 3 features</h4>
 <ul>
 <li>Requests are sent through a streamlined API that allows you to easily request 
 product details from Google Play, order in-app products, and quickly restore 
@@ -66,21 +69,11 @@
 item; only one copy can be owned at any point in time</li>
 <li>Purchased items can be consumed. When consumed, the item reverts to the 
 "unowned" state and can be purchased again from Google Play</li>
+<li>Provides support for <a
+  href="{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a></li>
 </ul>
-<h4><a href="{@docRoot}google/play/billing/v2/api.html">Version 2</a></h4>
-<ul>
-<li>Requests are sent via a single API interface ({@code sendBillingRequest})</li>
-<li>Responses from Google Play are asynchronous, in the form of broadcast intents</li>
-<li>No consumption model provided. You have to implement your own solution</li>
-<li>Provides support for subscriptions and unmanaged in-app purchase items, 
-as well as managed in-app products</li>
-</ul>
-<p>Both versions offer very broad compatibility across the range of Android 
-devices. In-app Billing Version 3 is supported on devices running Android 2.2 or 
-higher that have the latest version of the Google Play store installed 
-(over 90% of active devices). Version 2 offers similar compatibility. See 
-<a href="{@docRoot}google/play/billing/versions.html">Version Notes</a> for 
-more details.</p>
+<p>For details about other versions of In-app Billing, see the 
+<a href="{@docRoot}google/play/billing/versions.html">Version Notes</a>.</p>
 
 <h2 id="products">In-app Products</h2>
 <p>In-app products are the digital goods that you offer for sale from inside your 
@@ -102,12 +95,9 @@
 how you monetize your application. In all cases, you define your products using 
 the Google Play Developer Console.</p>
 <p>You can specify these types of products for your In-app Billing application  
-— <em>managed in-app products</em>, <em>subscriptions</em>, and <em>unmanaged 
-in-app products</em>.  The term “managed” indicates that Google Play handles and 
-tracks ownership for in-app products on your application on a per user account 
-basis, while “unmanaged” indicates that you will manage the ownership  information yourself.</p>
-<p>To learn more about the product types supported by the different API versions, 
-see the related documentation for <a href="{@docRoot}google/play/billing/v2/api.html#billing-types">Version 2</a> and <a href="{@docRoot}google/play/billing/api.html#producttypes">Version 3</a>.</p>
+— <em>managed in-app products</em> and <em>subscriptions</em>. Google Play 
+handles and tracks ownership for in-app products and subscriptions on your 
+application on a per user account basis. <a href="{@docRoot}google/play/billing/api.html#producttypes">Learn more about the product types supported by In-app Billing Version 3</a>.</p>
 
 <h2 id="console">Google Play Developer Console</h2>
 <p>The Developer Console is where you can publish your 
@@ -148,70 +138,31 @@
 complete, the application resumes.
 </p>
 
-<h2 id="samples">Sample Applications</h2>
+<h2 id="samples">Sample Application</h2>
 <p>To help you integrate In-app Billing into your application, the Android SDK 
-provides two sample applications that demonstrate how to sell in-app products 
+provides a sample application that demonstrates how to sell in-app products and subscriptions 
 from inside an app.</p>
 
-<dl>
-<dt><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">TrivialDrive sample for the Version 3 API</a></dt>
-<dd>This sample shows how to use the In-app Billing Version 3 API to implement 
-in-app product purchases for a driving game. The application demonstrates how to 
-send In-app Billing requests, and handle synchronous responses from Google Play. 
-The application also shows how to record item consumption with the API. The 
-Version 3 sample includes convenience classes for processing In-app Billing 
-operations as well as perform automatic signature verification.</dd>
+<p>The <a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">TrivialDrive sample for the Version 3 API</a> sample shows how to use the In-app Billing Version 3 API 
+to implement in-app product and subscription purchases for a driving game. The 
+application demonstrates how to send In-app Billing requests, and handle 
+synchronous responses from Google Play. The application also shows how to record 
+item consumption with the API. The Version 3 sample includes convenience classes 
+for processing In-app Billing operations as well as perform automatic signature 
+verification.</p>
 
-<dt><a href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">Dungeons sample for the Version 2 API</a></dt>
-<dd>This sample demonstrates how to use the In-app Billing Version 2 API to sell 
-standard in-app products and subscriptions for an adventuring game. It also 
-contains examples of the database, user interface, and business logic you might 
-use to implement In-app Billing.</dd>
-</dl>
-<p class="caution"><strong>Important</strong>: It's <em>strongly recommended</em> 
-that you obfuscate the code in your application before you publish it. For 
-more information, see
+<p class="caution"><strong>Recommendation</strong>: Make sure to obfuscate the 
+code in your application before you publish it. For more information, see
 <a href="{@docRoot}google/play/billing/billing_best_practices.html">Security 
 and Design</a>.</p>
 
 <h2 id="migration">Migration Considerations</h2>
-<p>The following considerations may be applicable if you are planning to create a new 
-in-app biling application, or migrate your existing In-app Billing implementation 
-from the <a href="{@docRoot}google/play/billing/v2/api.html">Version 2</a> or 
-earlier API to the <a href="{@docRoot}google/play/billing/api.html">Version 3</a> API.</p>
-<p>Google Play will continue to support both the Version 2 and Version 3 APIs for 
-some time, so you can plan to migrate to Version 3 at your own pace. The Google 
-Play team will give advance notice of any upcoming changes to the support 
-status of In-app Billing Version 2.</p>
-<p>You can use the following table to decide which version of the API to use, 
-depending on the needs of your application.</p>
-<p class="table-caption" id="table1">
-  <strong>Table 1.</strong> Selecting the In-app Billing API Version for Your 
-Project</p>
+<p>If you have an existing In-app Billing implementation that uses Version 2 or
+earlier, it is strongly recommended that you migrate to <a href="{@docRoot}google/play/billing/api.html">In-app Billing Version 3</a> at your earliest convenience.</p>
 
-<table>
-<tr>
-<th scope="col">Choose Version 3 if ...</th>
-<th scope="col">Choose Version 2 if ...</th>
-</tr>
-<tr>
-<td>
-  <ul>
-  <li>You want to sell in-app products only (and not subscriptions)</li>
-  <li>You need synchronous order confirmations when purchases complete</li>
-  <li>You need to synchronously restore a user's current purchases</li>
-  </ul>
-</td>
-<td>
-  <ul>
-  <li>You want to sell subscriptions in your app</li>
-  </ul>
-</td>
-</tr>
-</table>
 <p>If you have published apps selling in-app products, note that:</p>
 <ul>
-<li>Managed items that you have previously defined in the Developer Console will 
+<li>Managed items and subscriptions that you have previously defined in the Developer Console will 
 work with Version 3 as before.</li>
 <li>Unmanaged items that you have defined for existing applications will be 
 treated as managed products if you make a purchase request for these items using 
diff --git a/docs/html/google/play/billing/billing_reference.jd b/docs/html/google/play/billing/billing_reference.jd
index 758e21d..ae41521 100644
--- a/docs/html/google/play/billing/billing_reference.jd
+++ b/docs/html/google/play/billing/billing_reference.jd
@@ -102,11 +102,13 @@
   </tr>
   <tr>
     <td>{@code type}</td>
-    <td>Value must be “inapp” for an in-app purchase type.</td>
+    <td>Value must be “inapp” for an in-app product or "subs" for 
+subscriptions.</td>
   </tr>
   <tr>
     <td>{@code price}</td>
-    <td>Formatted price of the item, including its currency sign. The price does not include tax.</td>
+    <td>Formatted price of the item, including its currency sign. The price 
+does not include tax.</td>
   </tr>
   <tr>
     <td>{@code title}</td>
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
new file mode 100644
index 0000000..c2bbb49
--- /dev/null
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -0,0 +1,433 @@
+page.title=Subscriptions
+parent.title=In-app Billing
+parent.link=index.html
+@jd:body
+
+<!--notice block -->
+    <div style="background-color:#fffbd9;width:100%;margin-bottom:1em;padding:8px 8px 1px;">
+      <p><em>15 February 2013</em></p>
+      <p>In-app Billing V3 now supports subscriptions and you can get
+        started developing today. A small app update is currently being
+        rolled out to Android devices. This process is automatic and
+        most devices will get the update in the next few days. However,
+        if you wish to get the update today to start developing right
+        away, simply reboot your device. </p>
+
+      <p>However, we recommend that you <em>do not publish</em> an app with 
+        V3 subscriptions until all Android devices have received the update. We'll
+        notify you here that all devices have received the update and its safe
+        to publish your apps that use V3 subscriptions. </p>
+    </div>
+
+<!-- Use non-standard wrapper to support notice block. Restore standard 
+     wrapper when notice is removed. -->
+<!--<div id="qv-wrapper"> -->
+<div id="qv-wrapper" style="margin-top:.25em;">
+<div id="qv">
+  <h2>Quickview</h2>
+  <ul>
+     <li>Users purchase your subscriptions from inside your apps, rather than 
+directly from Google Play.</li>
+     <li>Subscriptions let you sell products with automated, recurring billing
+(monthly or annual).</li>
+     <li>You can offer a configurable trial period for any subscription.</li>
+
+  </ul>
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#overview">Overview</a></li>
+    <li><a href="#administering">Configuring Subscriptions Items</a></li>
+    <li><a href="#cancellation">Cancellation</a></li>
+    <li><a href="#payment">Payment Processing</a></li>
+    <li><a href="#play-dev-api">Google Play Android Developer API</a></li>
+  </ol>
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}google/play/billing/billing_integrate.html#Subs">Implementing Subscriptions (V3)</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Subscriptions let you sell content, services, or features in your app with
+automated, recurring billing. You can easily adapt an existing In-app Billing 
+implementation to sell subscriptions.</p>
+<p>This document is focused on highlighting implementation details that are 
+specific to subscriptions, along with some strategies for the associated billing 
+and business models.</p>
+
+<h2 id="overview">Overview of Subscriptions</h2>
+<p>A <em>subscription</em> is a product type offered in In-app Billing that 
+lets you sell content, services, or features to users from inside your app with 
+recurring monthly or annual billing. You can sell subscriptions to almost any 
+type of digital content, from any type of app or game.</p>
+
+<p>As with other in-app products, you configure and publish subscriptions using
+the Developer Console and then sell them from inside apps installed on 
+Android devices. In the Developer console, you create subscription
+products and add them to a product list, then set a price and optional trial
+period for each, choose a billing interval (monthly or annual), and then 
+publish. For more information about using the Developer Console, see 
+<a href="#administering">Configuring Subscription Items</a>.</p>
+
+<p>When users purchase subscriptions in your apps, Google Play handles all 
+checkout details so your apps never have to directly process any financial 
+transactions. Google Play processes all payments for subscriptions through 
+Google Checkout, just as it does for standard in-app products and app purchases. 
+This ensures a consistent and familiar purchase flow for your users.</p>
+
+<img src="{@docRoot}images/in-app-billing/v3/billing_subscription_v3.png" style="float:right; border:4px solid ddd;">
+
+<p>After users have purchase subscriptions, they can view the subscriptions and 
+cancel them from the <strong>My Apps</strong> screen in the Play Store app or 
+from the app's product details page in the Play Store app. For more information 
+about handling user cancellations, see <a href="#cancellation">Subscription Cancellation</a>.</p>
+
+<p>In adddition to client-side API calls, you can use the server-side API for 
+In-app Billing to provide subscription purchasers with extended access to 
+content (for example, from your web site or another service).
+The server-side API lets you validate the status of a subscription when users
+sign into your other services. For more information about the API, see <a
+href="#play-dev-api">Google Play Android Developer API</a>. </p>
+
+<p>You can also build on your existing external subscriber base from inside your
+Android apps.</p>
+<ul>
+<li>If you sell subscriptions on a web site, for example, you can add
+your own business logic to your Android app to determine whether the user has
+already purchased a subscription elsewhere, then allow access to your content if
+so or offer a subscription purchase from Google Play if not.</li>
+<li>You can implement your own solution for sharing subscriptions across as 
+many different apps or products as you want. For example, you could sell a 
+subscription that gives a subscriber access to an entire collection of apps, 
+games, or other content for a monthly or annual fee. To implement this solution, 
+you could add your own business logic to your app to determine whether the user 
+has already purchased a given subscription and if so, allow access to your 
+content.</li>
+</ul>
+</p>
+
+<p>In general the same basic policies and terms apply to subscriptions as to
+standard in-app products, however there are some differences. For complete
+information about the current policies and terms, please read the <a
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en
+&answer=140504">policies document</a>.</p>
+
+<p>To learn about the minimum system requirements for 
+subscriptions, see the <a href="{@docRoot}google/play/billing/versions.html#Subs">Version Notes</a>.</p>
+
+<h2 id="administering">Configuring Subscription Items</h2>
+<p>To create and manage subscriptions, use the Developer Console to set up a 
+product list for the app then configure these attributes for each subscription 
+product:</p>
+
+<ul>
+<li>Purchase Type: always set to <strong>Subscription</strong></li>
+<li>Subscription ID:  An identifier for the subscription</li>
+<li>Publishing State: Unpublished/Published</li>
+<li>Language: The default language for displaying the subscription</li>
+<li>Title: The title of the subscription product</li>
+<li>Description: Details that tell the user about the subscription</li>
+<li>Price: USD price of subscription per recurrence</li>
+<li>Recurrence: monthly or yearly</li>
+<li>Additional currency pricing (can be auto-filled)</li>
+</ul>
+
+<p>For details on how to add and configure products in the Developer Console, 
+see <a href="{@docRoot}google/play/billing/billing_admin.html">Administering
+In-app Billing</a>.</p>
+
+<h3 id="pricing">Subscription pricing</h3>
+
+<p>When you create a subscription in the Developer Console, you can set a price
+for it in any available currencies. Each subscription must have a non-zero
+price. You can price multiple subscriptions for the same content differently
+&mdash; for example you could offer a discount on an annual subscription
+relative to the monthly equivalent. </p>
+
+<p class="caution"><strong>Important</strong>: To change the price of a 
+subscription, you can publish a new subscription product ID at a new price, 
+then offer it in your app instead of the original product. Users who have 
+already purchased will continue to be charged at the 
+original price, but new users will be charged at the new price.</p>
+
+<h3 id="user-billing">User billing</h3>
+
+<p>In the Developer Console, you can configure subscription products with 
+automated recurring billing at either of two intervals:</p>
+
+<ul>
+  <li>Monthly &mdash; Google Play bills the customer’s Google Checkout account at
+  the time of purchase and monthly subsequent to the purchase date (exact billing
+  intervals can vary slightly over time)</li>
+  <li>Annually &mdash; Google Play bills the customer's Google Checkout account at
+  the time of purchase and again on the same date in subsequent years.</li>
+</ul>
+
+<p>Billing continues indefinitely at the interval and price specified for the
+subscription. At each subscription renewal, Google Play charges the user account
+automatically, then notifies the user of the charges afterward by email. Billing
+cycles will always match subscription cycles, based on the purchase date.</p>
+
+<p>Over the life of a subscription, the form of payment billed remains the same
+&mdash; Google Play always bills the same form of payment (such as credit card
+or by Direct Carrier Billing) that was originally used to purchase the
+subscription.</p>
+
+<p>When the subscription payment is approved by Google Checkout, Google Play
+provides a purchase token back to the purchasing app through the In-app Billing
+API. Your apps can store the token locally or pass it to your backend servers, 
+which can then use it to validate or cancel the subscription remotely using the <a
+href="#play-dev-api">Google Play Android Developer API</a>.</p>
+
+<p>If a recurring payment fails (for example, because the customer’s credit
+card has become invalid), the subscription does not renew. How your app is 
+notified depends on the In-app Billing API version that you are using:</p>
+<ul>
+<li>With In-app Billing Version 3, the failed or expired subscription is no longer 
+returned when you call {@code getPurchases}.</li>
+<li>With In-app Billing Version 2, Google Play notifies your app at the end of 
+the active cycle that the purchase state of the subscription is now "Expired". 
+</li>
+</ul>
+
+<p class="note"><strong>Recommendation</strong>: Include business logic in your 
+app to notify your backend servers of subscription purchases, tokens, and any 
+billing errors that may occur. Your backend servers can use the server-side API 
+to query and update your records and follow up with customers directly, if needed.</p>
+
+<h3 id="trials">Free trials</h3>
+
+<p>In the Developer Console, you can set up a free trial period that lets users
+try your subscription content before buying it. The trial period runs for the 
+period of time that you set and then automatically converts to a full 
+subscription managed according to the subscription's billing interval and 
+price.</p>
+
+<p>To take advantage of a free trial, a user must "purchase" the full
+subscription through the standard In-app Billing flow, providing a valid form of
+payment to use for billing and completing the normal purchase transaction.
+However, the user is not charged any money, since the initial period corresponds
+to the free trial. Instead, Google Play records a transaction of $0.00 and the
+subscription is marked as purchased for the duration of the trial period or
+until cancellation. When the transaction is complete, Google Play notifies users
+by email that they have purchased a subscription that includes a free trial
+period and that the initial charge was $0.00. </p>
+
+<p>When the trial period ends, Google Play automatically initiates billing
+against the credit card that the user provided during the initial purchase, at 
+the amount set
+for the full subscription, and continuing at the subscription interval. If
+necessary, the user can cancel the subscription at any time during the trial
+period. In this case, Google Play <em>marks the subscription as expired immediately</em>,
+rather than waiting until the end of the trial period. The user has not
+paid for the trial period and so is not entitled to continued access after
+cancellation.</p>
+
+<p>You can set up a trial period for a subscription in the Developer Console,
+without needing to modify or update your APK. Just locate and edit the
+subscription in your product list, set a valid number of days for the trial
+(must be 7 days or longer), and publish. You can change the period any time,
+although note that Google Play does not apply the change to users who have
+already "purchased" a trial period for the subscription. Only new subscription
+purchases will use the updated trial period. You can create one free trial
+period per subscription product.</p>
+
+<h3 id="publishing">Subscription publishing</h3>
+<p>When you have finished configuring your subscription product details in the
+Developer Console, you can publish the subscription in the app product list.</p>
+
+<p>In the product list, you can add subscriptions, in-app products, or both. You
+can add multiple subscriptions that give access to different content or
+services, or you can add multiple subscriptions that give access to the same
+content but for different intervals or different prices, such as for a
+promotion. For example, a news outlet might decide to offer both monthly and
+annual subscriptions to the same content, with annual having a discount. You can
+also offer in-app purchase equivalents for subscription products, to ensure that
+your content is available to users of older devices that do not support
+subscriptions.</p>
+
+<p>After you add a subscription or in-app product to the product list, you must
+publish the product before Google Play can make it available for purchase. Note
+that you must also publish the app itself before Google Play will make the
+products available for purchase inside the app. </p>
+
+<p class="caution"><strong>Important</strong>: You can remove the subscription 
+product from the product list offered in your app to prevent users from seeing 
+or purchasing it.</p>
+
+<h2 id="cancellation">Subscription Cancellation</h2>
+
+<p>Users can view the status of all of their subscriptions and cancel them if
+necessary from the <strong>My Apps</strong> screen in the Play Store app. 
+Currently, the In-app Billing API does not provide support for programatically 
+canceling subscriptions from inside the purchasing app.</p>
+
+<p>When the user cancels a subscription, Google Play does not offer a refund for
+the current billing cycle. Instead, it allows the user to have access to the
+cancelled subscription until the end of the current billing cycle, at which time
+it terminates the subscription. For example, if a user purchases a monthly
+subscription and cancels it on the 15th day of the cycle, Google Play will
+consider the subscription valid until the end of the 30th day (or other day,
+depending on the month).</p>
+
+<p>In some cases, the user may contact you directly to request cancellation of a
+subscription. In this and similar cases, you can use the server-side API to
+query and directly cancel the user’s subscription from your servers.
+
+<p class="caution"><strong>Important:</strong> In all cases, you must continue
+to offer the content that your subscribers have purchased through their
+subscriptions, for as long any users are able to access it. That is, you must
+not remove any subscriber’s content while any user still has an active
+subscription to it, even if that subscription will terminate at the end of the
+current billing cycle. Removing content that a subscriber is entitled to access
+will result in penalties. Please see the <a
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=140504">policies document</a> for more information. </p>
+
+<h3 id="uninstall">App uninstallation</h3>
+
+<p>When the user uninstalls an app that includes purchased subscriptions, the 
+Play Store app will notify the user that there are active subscriptions. If the 
+user chooses to continue with the uninstallation, the app is removed and the 
+subscriptions remain active and recurring billing continues. The user can return 
+to cancel the associated subscriptions at any time in the <strong>My Apps</strong> 
+screen of the Play Store app. If the user chooses to cancel the uninstallation, 
+the app and subscriptions remain as they were.</p>
+
+<h3 id="refunds">Refunds</h3>
+
+<p>With subscriptions, Google Play does not provide a refund window, so users 
+will need to contact you directly to request a refund.
+
+<p>If you receive requests for refunds, you can use the server-side API to
+cancel the subscription or verify that it is already cancelled. However, keep in
+mind that Google Play considers cancelled subscriptions valid until the end of
+their current billing cycles, so even if you grant a refund and cancel the
+subscription, the user will still have access to the content.
+
+<p class="caution"><strong>Important:</strong> Partial refunds for canceled
+subscriptions are not available at this time.</p>
+
+<h2 id="payment">Payment Processing and Policies</h2>
+
+<p>In general, the terms of Google Play allow you to sell in-app subscriptions
+only through the standard payment processor, Google Checkout. For purchases of 
+any subscription products, the transaction fee is the same as the transaction 
+fee for application purchases (30%).</p>
+
+<p>Apps published on Google Play that are selling subscriptions must use In-app
+Billing to handle the transaction and may not provide links to a purchase flow
+outside of the app and Google Play (such as to a web site).</p>
+
+<p>For complete details about terms and policies, see the <a
+href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=140504">policies
+document</a>.</p>
+
+<h3 id="orderId">Subscription order numbers</h3>
+
+<p>To help you track transactions relating to a given subscription, Google
+Checkout provides a base Merchant Order Number for all recurrences of the 
+subscription and denotes
+each recurring transaction by appending an integer as follows: </p>
+
+<p><span style="color:#777"><code style="color:#777">12999556515565155651.5565135565155651</code> (base order number)</span><br />
+<code>12999556515565155651.5565135565155651..0</code> (initial purchase orderID)<br />
+<code>12999556515565155651.5565135565155651..1</code> (first recurrence orderID)<br />
+<code>12999556515565155651.5565135565155651..2</code> (second recurrence orderID)<br />
+...<br /></p>
+
+<p>Google Play provides the order number as the value of the 
+{@code orderId} field of the {@code INAPP_PURCHASE_DATA} JSON field (in V3) 
+or the {@code PURCHASE_STATE_CHANGED} intent (in V2).</p>
+
+<h2 id="play-dev-api">Google Play Android Developer API</h2>
+
+<p>Google Play offers an HTTP-based API that you can use to remotely query the
+validity of a specific subscription at any time or cancel a subscription. The
+API is designed to be used from your backend servers as a way of securely
+managing subscriptions, as well as extending and integrating subscriptions with
+other services.</p>
+
+<h3 id="using">Using the API</h3>
+
+<p>To use the API, you must first register a project at the <a
+href="https://code.google.com/apis/console">Google APIs Console</a> and receive
+a Client ID and shared secret that  your app will present when calling the
+Google Play Android Developer API. All calls to the API are authenticated with
+OAuth 2.0.</p>
+
+<p>Once your app is registered, you can access the API directly, using standard
+HTTP methods to retrieve and manipulate resources, or you can use the Google
+APIs Client Libraries, which are extended to support the API.</p>
+
+<p>The Google Play Android Developer API is built on a RESTful design that uses
+HTTP and JSON, so any standard web stack can send requests and parse the
+responses. However, if you don’t want to send HTTP requests and parse responses
+manually, you can access the API using the client libraries, which provide
+better language integration, improved security, and support for making calls
+that require user authorization.</p>
+
+<p>For more information about the API and how to access it through the Google
+APIs Client Libraries, see the documentation at:</p> 
+
+<p style="margin-left:1.5em;"><a
+href="https://developers.google.com/android-publisher/v1/">https://developers.
+google.com/android-publisher/v1/</a></p>
+
+<h3 id="quota">Quota</h3>
+
+<p>Applications using the Google Play Android Developer API are limited to an
+initial courtesy usage quota of <strong>15000 requests per day</strong> (per
+application). This should provide enough access for normal
+subscription-validation needs, assuming that you follow the recommendation in
+this section.</p>
+
+<p>If you need to request a higher limit for your application, please use the
+“Request more” link in the <a
+href="https://code.google.com/apis/console/#:quotas">Google APIs Console</a>.
+Also, please read the section below on design best practices for minimizing your
+use of the API.</p>
+
+<h3 id="auth">Authorization</h3>
+
+<p>Calls to the Google Play Android Developer API require authorization. Google
+uses the OAuth 2.0 protocol to allow authorized applications to access user
+data. To learn more, see <a
+href="https://developers.google.com/android-publisher/authorization">Authorization</a>
+in the Google Play Android Developer API documentation.</p>
+
+<h3 id="practices">Using the API efficiently</h3>
+
+<p>Access to the Google Play Android Developer API is regulated to help ensure a
+high-performance environment for all applications that use it. While you can
+request a higher daily quota for your application, we highly recommend that you
+minimize your access using the technique(s) below. </p>
+
+<ul>
+  <li><em>Store subscription expiry on your servers</em> &mdash; your servers
+  should use the Google Play Android Developer API to query the expiration date
+  for new subscription tokens, then store the expiration date locally. This allows
+  you to check the status of subscriptions only at or after the expiration (see
+  below). </li>
+  <li><em>Cache expiration and purchaseState</em> &mdash; If your app contacts
+  your backend servers at runtime to verify subscription validity, your server
+  should cache the expiration and purchaseState to ensure the fastest possible
+  response (and best experience) for the user.</li>
+  <li><em>Query for subscription status only at expiration</em> &mdash; Once your
+  server has retrieved the expiration date of subscription tokens, it should not
+  query the Google Play servers for the subscription status again until the
+  subscription is reaching or has passed the expiration date. Typically, your
+  servers would run a batch query each day to check the status of
+  <em>expiring</em> subscriptions, then update the database. Note that: 
+  <ul>
+    <li>Your servers should not query all subscriptions every day</li>
+    <li>Your servers should never query subscription status dynamically, based on
+    individual requests from your Android application. </li>
+  </ul>
+  </li>
+</ul>
+
+<p>By following those general guidelines, your implementation will offer the
+best possible performance for users and minimize use of the Google Play Android
+Developer API.</p>
+
+
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index b0d1d13..44aa001 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -10,8 +10,8 @@
 <div class="sidebox">
   <h2><strong>New in In-App Billing</strong></h2>
   <ul>
-  <li><strong>In-app Billing Version 3</strong>&mdash;The <a href="{@docRoot}google/play/billing/api.html">latest version</a> of In-app Billing features a synchronous API that is easier to implement and lets you manage products and purchases more effectively.</li>
-  <li><strong>New order number format</strong>&mdash;Starting 5 December, orders are reported in Merchant Order Number format. See <a href="/google/play/billing/billing_admin.html#orderId">Working with Order Numbers</a> for an example.</li>
+  <li><strong>In-app Billing Version 3</strong>&mdash;The <a href="{@docRoot}google/play/billing/api.html">latest version</a> of In-app Billing features a synchronous API that is easier to implement and lets you manage in-app products and subscriptions more effectively.</li>
+  <li><strong>Subscriptions now supported in Version 3</strong>&mdash;You can query and launch purchase flows for subscription items using the V3 API.</li>
   <li><strong>Free trials</strong>&mdash;You can now offer users a configurable <a href="/google/play/billing/v2/billing_subscriptions.html#trials">free trial period</a> for your in-app subscriptions. You can set up trials with a simple change in the Developer Console&mdash;no change to your app code is needed.</li>
  </ul>
 </div>
@@ -30,7 +30,7 @@
 familiar purchase flow.</p>
 
 <p>Any application that you publish through Google Play can implement In-app Billing. No special
-account or registration is required other than an Android Market publisher account and a Google
+account or registration is required other than a Google Play Developer Console account and a Google
 Checkout merchant account.</p>
 
 <p>To help you integrate in-app billing into your application, the Android SDK
diff --git a/docs/html/google/play/billing/v2/api.jd b/docs/html/google/play/billing/v2/api.jd
index 6b3b758..9d3a045 100644
--- a/docs/html/google/play/billing/v2/api.jd
+++ b/docs/html/google/play/billing/v2/api.jd
@@ -39,15 +39,6 @@
 <p>If you do not need to sell subscriptions, you
 should implement In-app Billing Version 3 instead.</p>
 
-<div class="sidebox-wrapper">
-<div class="sidebox">
-  <h2>New in In-app Billing V2</h2>
-  <p><strong>Free trials</strong>—You can now offer users a configurable free trial period for
-  your in-app subscriptions. You can set up trials with a simple change in the Developer
-  Console—no change to your app code is needed.</p>
-</div>
-</div>
-
 <h2 id="billing-types">Product Types</h2>
 
 <p>In-app Billing Version supports three different product types
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index 82a662f..5e3bd28 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -1,4 +1,4 @@
-page.title=Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
+page.title=Implementing Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
 @jd:body
 
 <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
@@ -6,404 +6,26 @@
 <div id="qv">
   <h2>In this document</h2>
   <ol>
-    <li><a href="#overview">Overview of Subscriptions</a>
-    <!--<ol>
-        <li><a href="#publishing">Subscription publishing and unpublishing</a></li>
-        <li><a href="#pricing">Subscription pricing</a></li>
-        <li><a href="#user-billing">User billing</a></li>
-        <li><a href="#trials">Free trial period</a></li>
-        <li><a href="#cancellation">Subscription cancellation</a></li>
-        <li><a href="#uninstallation">App uninstallation</a></li>
-        <li><a href="#refunds">Refunds</a></li>
-        <li><a href="#payment">Payment processing and policies</a></li>
-        <li><a href="#requirements">System requirements for subscriptions</a></li>
-        <li><a href="#compatibility">Compatibility considerations</a></li>
-      </ol> -->
-    </li>
-    <li><a href="#implementing">Implementing Subscriptions</a>
-      <!-- <ol>
-        <li><a href="#sample">Sample application</a></li>
-        <li><a href="#model">Application model</a></li>
-        <li><a href="#token">Purchase token</a></li>
-        <li><a href="#version">Checking the In-app Billing API version</a></li>
-        <li><a href="purchase">Requesting purchase of a subscription</a></li>
-        <li><a href="#restore">Restoring transactions</a></li>
-        <li><a href="#validity">Checking subscription validity</a></li>
-        <li><a href="#viewstatus">Launching your product page to let the user cancel or view status</a></li>
-        <li><a href="#purchase-state-changes">Recurring billing and changes in purchase state</a></li>
-        <li><a href="modifying">Modifying your app for subscriptions</a></li>
-      </ol> -->
-    </li>
-    <li><a href="#administering">Administering Subscriptions</a></li>
-    
-    <li><a href="#play-dev-api">Google Play Android Developer API</a>
-      <!-- <ol>
-        <li><a href="#using">Using the API</a></li>
-        <li><a href="#quota">Quota</a></li>
-        <li><a href="#auth">Authorization</a></li>
-        <li><a href="#practices">Using the API efficiently</a></li>
-      </ol> -->
-    </li>
-</ol>
+        <li><a href="#sample">Sample Application</a></li>
+        <li><a href="#model">Application Model</a></li>
+        <li><a href="#token">Purchase Token</a></li>
+        <li><a href="#version">Checking the In-app Billing API Version</a></li>
+        <li><a href="purchase">Purchasing a Subscription</a></li>
+        <li><a href="#restore">Restoring Transactions</a></li>
+        <li><a href="#validity">Checking Subscription Validity</a></li>
+        <li><a href="#viewstatus">Letting Users Cancel or View Status</a></li>
+        <li><a href="#purchase-state-changes">Recurring Billing and Changes in Purchase State</a></li>
+        <li><a href="modifying">Modifying Your App for Subscriptions</a></li>
+   </ol>
 </div>
 </div>
 
-<p class="note"><strong>Important:</strong> This documentation describes how to implement subscriptions with the Version 2 API. Subscription support for the in-app billing <a href="{@docRoot}google/play/billing/api.html">Version 3 API</a> is coming soon.</p></li>
+<p>This document is focused on highlighting implementation details that are 
+specific to subscriptions with the Version 2 API. To understand how  
+subscriptions work, see <a href="{@docRoot}google/play/billing/billing_subscriptions.html">In-app Billing Subscriptions</a>.</p>
 
-<p>Subscriptions let you sell content, services, or features in your app with
-automated, recurring billing. Adding support for subscriptions is
-straightforward and you can easily adapt an existing In-app Billing
-implementation to sell subscriptions. </p>
 
-<p>If you have already implemented In-app Billing for one-time purchase
-products, you will find that you can add support for subscriptions with minimal
-impact on your code. If you are new to In-app Billing, you can implement
-subscriptions using the standard communication model, data structures, and user
-interactions as for other in-app products.subscriptions. Because the
-implementation of subscriptions follows the same path as for other in-app
-products, details are provided outside of this document, starting with the <a
-href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
-Overview</a>. </p>
-
-<p>This document is focused on highlighting implementation details that are
-specific to subscriptions, along with some strategies for the associated billing
-and business models.</p>
-
-<p class="note"><strong>Note:</strong> Subscriptions are supported in In-app Billing Version 2 only. Support for subscriptions will be added to Version 3 in the weeks ahead.</p>
-
-<h2 id="overview">Overview of Subscriptions</h2>
-
-<p>A <em>subscription</em> is a new product type offered in In-app Billing that lets you
-sell content, services, or features to users from inside your app with recurring
-monthly or annual billing. You can sell subscriptions to almost any type of
-digital content, from any type of app or game.</p>
-
-<p>As with other in-app products, you configure and publish subscriptions using
-the Developer Console and then sell them from inside apps installed on an
-Android-powered devices. In the Developer console, you create subscription
-products and add them to a product list, then set a price and optional trial
-period for each, choose a billing interval (monthly or annual), and then publish.</p>
-
-<p>In your apps, it’s
-straightforward to add support for subscription purchases. The implementation
-extends the standard In-app Billing API to support a new product type but uses
-the same communication model, data structures, and user interactions as for
-other in-app products.</p>
-
-<p>When users purchase subscriptions in your apps, Google Play handles all
-checkout details so your apps never have to directly process any financial
-transactions. Google Play processes all payments for subscriptions through
-Google Checkout, just as it does for standard in-app products and app purchases.
-This ensures a consistent and familiar purchase flow for your users.</p>
-
-<img src="{@docRoot}images/billing_subscription_flow.png" style="border:4px solid ddd;">
-
-
-<p>After users have purchase subscriptions, they can view the subscriptions and
-cancel them, if necessary, from the My Apps screen in the Play Store app or
-from the app's product details page in the Play Store app.</p>
-
-<!--<img src="{@docRoot}images/billing_subscription_cancel.png" style="border:4px solid ddd;">-->
-
-<p>Once users have purchased a subscription through In-app Billing, you can
-easily give them extended access to additional content on your web site (or
-other service) through the use of a server-side API provided for In-app Billing.
-The server-side API lets you validate the status of a subscription when users
-sign into your other services. For more information about the API, see <a
-href="#play-dev-api">Google Play Android Developer API</a>, below. </p>
-
-<p>You can also build on your existing external subscriber base from inside your
-Android apps. If you sell subscriptions on a web site, for example, you can add
-your own business logic to your Android app to determine whether the user has
-already purchased a subscription elsewhere, then allow access to your content if
-so or offer a subscription purchase from Google Play if not.</p>
-
-<p>With the flexibility of In-app Billing, you can even implement your own
-solution for sharing subscriptions across as many different apps or products as
-you want. For example, you could sell a subscription that gives a subscriber
-access to an entire collection of apps, games, or other content for a monthly or
-annual fee. To implement this solution, you could add your own business logic to
-your app to determine whether the user has already purchased a given
-subscription and if so, allow access to your content. </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-  <h2>Subscriptions at a glance</h2>
-  <ul>
-    <li>Subscriptions let you sell products with automated, recurring billing</li>
-    <li>You can set up subscriptions with either monthly or annual billing</li>
-    <li>You can sell multiple subscription items in an app with various billing
-    intervals or prices, such as for promotions</li>
-    <li>You can offer a configurable trial period for any subscription. <span class="new" style="font-size:.78em;">New!</span></li>
-    <li>Users purchase your subscriptions from inside your apps, rather than
-    directly from Google Play</li>
-    <li>Users manage their purchased subscriptions from the My Apps screen in
-    the Play Store app</li>
-    <li>Google Play uses the original form of payment for recurring billing</li>
-    <li>If a user cancels a subscription, Google Play considers the subscription valid
-    until the end of the current billing cycle. The user continues to enjoy the content
-    for the rest of the cycle and is not granted a refund.</li>
-  </ul>
-</div>
-</div>
-
-<p>In general the same basic policies and terms apply to subscriptions as to
-standard in-app products, however there are some differences. For complete
-information about the current policies and terms, please read the <a
-href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en
-&answer=140504">policies document</a>.</p>
-
-
-<h3 id="publishing">Subscription publishing and unpublishing</h3>
-
-<p>To sell a subscription in an app, you use the tools in the Developer Console
-to set up a product list for the app and then create and configure a new
-subscription. In the subscription, you set the price and billing interval and
-define a subscription ID, title, and description. When you are ready, you can
-then publish the subscription in the app product list.</p>
-
-<p>In the product list, you can add subscriptions, in-app products, or both. You
-can add multiple subscriptions that give access to different content or
-services, or you can add multiple subscriptions that give access to the same
-content but for different intervals or different prices, such as for a
-promotion. For example, a news outlet might decide to offer both monthly and
-annual subscriptions to the same content, with annual having a discount. You can
-also offer in-app purchase equivalents for subscription products, to ensure that
-your content is available to users of older devices that do not support
-subscriptions.</p>
-
-<p>After you add a subscription or in-app product to the product list, you must
-publish the product before Google Play can make it available for purchase. Note
-that you must also publish the app itself before Google Play will make the
-products available for purchase inside the app. </p>
-
-<p class="caution"><strong>Important:</strong> At this time, the capability to
-unpublish a subscription is not available. Support for unpublishing a
-subscription is coming to the Developer Console in the weeks ahead, so this is a
-temporary limitation. In the short term, instead of unpublishing,
-you can remove the subscription product from the product list offered in your
-app to prevent users from seeing or purchasing it.</p>
-
-<h3 id="pricing">Subscription pricing</h3>
-
-<p>When you create a subscription in the Developer Console, you can set a price
-for it in any available currencies. Each subscription must have a non-zero
-price. You can price multiple subscriptions for the same content differently
-&mdash; for example you could offer a discount on an annual subscription
-relative to the monthly equivalent. </p>
-
-<p class="caution"><strong>Important:</strong> At this time, once you publish a
-subscription product, you cannot change its price in any currency. Support for
-changing the price of published subscriptions is coming to the Developer Console
-in the weeks ahead. In the short term, you can work around this limitation by
-publishing a new subscription product ID at a new price, then offer it in your
-app instead of the original product. Users who have already purchased will
-continue to be charged at the original price, but new users will be charged at
-the new price.</p>
-
-<h3 id="user-billing">User billing</h3>
-
-<p>You can sell subscription products with automated recurring billing at
-either of two intervals:</p>
-
-<ul>
-  <li>Monthly &mdash; Google Play bills the customer’s Google Checkout account at
-  the time of purchase and monthly subsequent to the purchase date (exact billing
-  intervals can vary slightly over time)</li>
-  <li>Annually &mdash; Google Play bills the customer's Google Checkout account at
-  the time of purchase and again on the same date in subsequent years.</li>
-</ul>
-
-<p>Billing continues indefinitely at the interval and price specified for the
-subscription. At each subscription renewal, Google Play charges the user account
-automatically, then notifies the user of the charges afterward by email. Billing
-cycles will always match subscription cycles, based on the purchase date.</p>
-
-<p>Over the life of a subscription, the form of payment billed remains the same
-&mdash; Google Play always bills the same form of payment (such as credit card,
-Direct Carrier Billing) that was originally used to purchase the
-subscription.</p>
-
-<p>When the subscription payment is approved by Google Checkout, Google Play
-provides a purchase token back to the purchasing app through the In-app Billing
-API. For details, see <a href="#token">Purchase token</a>, below. Your apps can
-store the token locally or pass it to your backend servers, which can then use
-it to validate or cancel the subscription remotely using the <a
-href="#play-dev-api">Google Play Android Developer API</a>.</p>
-
-<p>If a recurring payment fails, such as could happen if the customer’s credit
-card has become invalid, the subscription does not renew. Google Play notifies your
-app at the end of the active cycle that the purchase state of the subscription is now "Expired".
-Your app does not need to grant the user further access to the subscription content.</p>
-
-<p>As a best practice, we recommend that your app includes business logic to
-notify your backend servers of subscription purchases, tokens, and any billing
-errors that may occur. Your backend servers can use the server-side API to query
-and update your records and follow up with customers directly, if needed.</p>
-
-<h3 id="trials">Free Trial Period</h3>
-
-<p>For any subscription, you can set up a free trial period that lets users
-try your subscription content before buying it. The trial period
-runs for the period of time that you set and then automatically converts to a full subscription
-managed according to the subscription's billing interval and price.</p>
-
-<p>To take advantage of a free trial, a user must "purchase" the full
-subscription through the standard In-app Billing flow, providing a valid form of
-payment to use for billing and completing the normal purchase transaction.
-However, the user is not charged any money, since the initial period corresponds
-to the free trial. Instead, Google Play records a transaction of $0.00 and the
-subscription is marked as purchased for the duration of the trial period or
-until cancellation. When the transaction is complete, Google Play notifies users
-by email that they have purchased a subscription that includes a free trial
-period and that the initial charge was $0.00. </p>
-
-<p>When the trial period ends, Google Play automatically initiates billing
-against the credit card that the user provided during the initial purchase, at the amount set
-for the full subscription, and continuing at the subscription interval. If
-necessary, the user can cancel the subscription at any time during the trial
-period. In this case, Google Play <em>marks the subscription as expired immediately</em>,
-rather than waiting until the end of the trial period. The user has not
-paid for the trial period and so is not entitled to continued access after
-cancellation.</p>
-
-<p>You can set up a trial period for a subscription in the Developer Console,
-without needing to modify or update your APK. Just locate and edit the
-subscription in your product list, set a valid number of days for the trial
-(must be 7 days or longer), and publish. You can change the period any time,
-although note that Google Play does not apply the change to users who have
-already "purchased" a trial period for the subscription. Only new subscription
-purchases will use the updated trial period. You can create one free trial
-period per subscription product.</p>
-
-<h3 id="cancellation">Subscription cancellation</h3>
-
-<p>Users can view the status of all of their subscriptions and cancel them if
-necessary from the My Apps screen in the Play Store app. Currently, the In-app
-Billing API does not provide support for canceling subscriptions direct from
-inside the purchasing app, although your app can broadcast an Intent to launch
-the Play Store app directly to the My Apps screen.</p>
-
-<p>When the user cancels a subscription, Google Play does not offer a refund for
-the current billing cycle. Instead, it allows the user to have access to the
-cancelled subscription until the end of the current billing cycle, at which time
-it terminates the subscription. For example, if a user purchases a monthly
-subscription and cancels it on the 15th day of the cycle, Google Play will
-consider the subscription valid until the end of the 30th day (or other day,
-depending on the month).</p>
-
-<p>In some cases, the user may contact you directly to request cancellation of a
-subscription. In this and similar cases, you can use the server-side API to
-query and directly cancel the user’s subscription from your servers.
-
-<p class="caution"><strong>Important:</strong> In all cases, you must continue
-to offer the content that your subscribers have purchased through their
-subscriptions, for as long any users are able to access it. That is, you must
-not remove any subscriber’s content while any user still has an active
-subscription to it, even if that subscription will terminate at the end of the
-current billing cycle. Removing content that a subscriber is entitled to access
-will result in penalties. Please see the <a
-href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=140504">policies document</a> for more information. </p>
-
-<h3 id="uninstall">App uninstallation</h3>
-
-<p>When the user uninstalls an app that includes purchased subscriptions, the Play Store app will notify the user that there are active subscriptions. If the user chooses to continue with the uninstalltion, the app is removed and the subscriptions remain active and recurring billing continues. The user can return to cancel the associated subscriptions at any time in the My Apps screen of the Play Store app. If the user chooses to cancel the uninstallation, the app and subscriptions remain as they were.</p>
-
-<h3 id="refunds">Refunds</h3>
-
-<p>As with other in-app products, Google Play does not provide a refund window
-for subscription purchases. For example, users who purchase an app can ask for a
-refund from Google Play within a 15-minute window. With subscriptions, Google
-Play does not provide a refund window, so users will need to contact you
-directly to request a refund.
-
-<p>If you receive requests for refunds, you can use the server-side API to
-cancel the subscription or verify that it is already cancelled. However, keep in
-mind that Google Play considers cancelled subscriptions valid until the end of
-their current billing cycles, so even if you grant a refund and cancel the
-subscription, the user will still have access to the content.
-
-<p class="note"><strong>Note:</strong> Partial refunds for canceled
-subscriptions are not available at this time.</p>
-
-<h3 id="payment">Payment processing and policies</h3>
-
-<p>In general, the terms of Google Play allow you to sell in-app subscriptions
-only through the standard payment processor, Google Checkout. For purchases of any
-subscription products, just as for other in-app products and apps, the
-transaction fee for subscriptions, just as for other in-app purchases, is the
-same as the transaction fee for application purchases (30%).</p>
-
-<p>Apps published on Google Play that are selling subscriptions must use In-app
-Billing to handle the transaction and may not provide links to a purchase flow
-outside of the app and Google Play (such as to a web site).</p>
-
-<p>For complete details about terms and policies, see the <a
-href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=140504">policies
-document</a>.</p>
-
-<h3 id="orderId">Subscription Order Numbers</h3>
-
-<p>To help you track transactions relating to a given subscription, Google
-Checkout provides a base Merchant Order Number for all recurrences of the subscription and denotes
-each recurring transaction by appending an integer as follows: </p>
-
-<p><span style="color:#777"><code style="color:#777">12999556515565155651.5565135565155651</code> (base order number)</span><br />
-<code>12999556515565155651.5565135565155651..0</code> (initial purchase orderID)<br />
-<code>12999556515565155651.5565135565155651..1</code> (first recurrence orderID)<br />
-<code>12999556515565155651.5565135565155651..2</code> (second recurrence orderID)<br />
-...<br /></p>
-
-<p>Google Play provides that order number to as the value of the
-<code>orderId</code> field of the <code>PURCHASE_STATE_CHANGED</code>
-intent.</p>
-
-<h3 id="requirements">System requirements for subscriptions</h3>
-
-<p>In-app purchases of subscriptions are supported only on devices that meet
-these minimum requirements:</p>
-
-<ul>
-  <li>Must run Android 2.2 or higher</li>
-  <li>Google Play Store app, Version 3.5 or higher, must be installed</li>
-</ul>
-
-<p>Google Play 3.5 and later versions include support for the In-app Billing
-v2 API or higher, which is needed to support handling of subscription
-products.</p>
-
-<h3 id="compatibility">Compatibility considerations</h3>
-
-<p>As noted in the previous section, support for subscriptions is available only
-on devices that meet the system requirements. Not all devices will receive or
-install Google Play 3.5, so not all users who install your apps will have access
-to the In-app Billing API and subscriptions.</p>
-
-<p>If you are targeting older devices that run Android 2.1 or earlier, we
-recommend that you offer those users an alternative way buy the content that is
-available through subscriptions. For example, you could create standard in-app
-products (one-time purchases) that give access to similar content as your
-subscriptions, possibly for a longer interval such as a year. </p>
-
-
-<h2 id="implementing">Implementing Subscriptions</h2>
-
-<p>Subscriptions are a standard In-app Billing product type. If you have already
-implemented In-app Billing for one-time purchase products, you will find that
-adding support for subscriptions is straightforward, with minimal impact on your
-code. If you are new to In-app Billing, you can implement subscriptions using
-the standard communication model, data structures, and user interactions as for
-other in-app products.subscriptions. </p>
-
-<p>The full implementation details for In-app Billing are provided outside of
-this document, starting with the <a
-href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
-Overview</a>. This document is focused on highlighting implementation details
-that are specific to subscriptions, along with some strategies for the
-associated billing and business models.</p>
-
-
-<h3 id="sample">Sample application</h3>
+<h2 id="sample">Sample Application</h2>
 
 <p>To help you get started with your In-app Billing implementation and
 subscriptions, an updated Version of the In-app Billing sample app is available.
@@ -412,7 +34,7 @@
 href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">
 Downloading the Sample Application</a>.</p>
 
-<h3 id="model">Application model</h3>
+<h2 id="model">Application Model</h2>
 
 <p>With subscriptions, your app uses the standard In-app Billing application
 model, sending billing requests to the Play Store application over interprocess
@@ -436,7 +58,7 @@
 responses. Inside the requests and responses are two new fields described below.
 </p>
 
-<h3 id="token">Purchase token</h3>
+<h2 id="token">Purchase Token</h2>
 
 <p>Central to the end-to-end architecture for subscriptions is the purchase
 token, a string value that uniquely identifies (and associates) a user ID and a
@@ -476,7 +98,7 @@
 Design</a> document for best practices for maintaining the security of your
 data.</p>
 
-<h3 id="version">Checking the In-app Billing API version</h3>
+<h2 id="version">Checking the In-app Billing API Version</h2>
 
 <p>Subscriptions support is available only in versions of Google Play that
 support the In-app Billing v2 API (Google Play 3.5 and higher). For your app,
@@ -555,7 +177,7 @@
    }
 </pre>
 
-<h3 id="purchase">Requesting a subscription purchase</h3>
+<h2 id="purchase">Requesting a Subscription Purchase</h2>
 
 <p>Once you’ve checked the API Version as described above and determined that
 subscriptions are supported, you can present subscription products to the user
@@ -630,7 +252,7 @@
    }
 </pre>
 
-<h3 id="restoring">Restoring transactions</h3>
+<h2 id="restoring">Restoring Transactions</h2>
 
 <p>Subscriptions always use  the <em>managed by user account</em> purchase type,
 so that you can restore a record of subscription transactions on the device when
@@ -660,7 +282,7 @@
 Design</a> document for best practices for maintaining the security of your
 data.</p>
 
-<h3 id="validity">Checking subscription validity</h3>
+<h2 id="validity">Checking Subscription Validity</h2>
 
 <p>Subscriptions are time-bound purchases that require successful billing
 recurrences over time to remain valid. Your app should check the validity of
@@ -736,7 +358,7 @@
 </table>
 
 
-<h3 id="viewstatus">Launching your product page to let the user cancel or view subscriptions</h3>
+<h2 id="viewstatus">Letting the User Cancel or View Subscriptions</h2>
 
 <p>In-app Billing does not currently provide an API to let users directly view or cancel
 subscriptions from within the purchasing app. Instead, users can launch the Play
@@ -761,7 +383,7 @@
 <p>For more information, see 
   <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>.</p>
 
-<h3 id="purchase-state-changes">Recurring billing, cancellation, and changes in purchase state</h3>
+<h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2>
 
 <p>Google Play notifies your app when the user completes the purchase of a
 subscription, but the purchase state does not change over time, provided that
@@ -786,7 +408,7 @@
 a change to the same "Expired" purchase state. Once the purchase state has become "Expired",
 your app does not need to grant further access to the subscription content.</p>
 
-<h3 id="modifying">Modifying your app for subscriptions</h3>
+<h2 id="modifying">Modifying Your App for Subscriptions</h2>
 
 <p>For subscriptions, you make the same types of modifications to your app as
 are described in <a
@@ -798,118 +420,7 @@
 them. Your UI should not present subscriptions if the user has already purchased
 them.</p>
 
-<h2 id="administering">Administering Subscriptions</h2>
-
-<p>To create and manage subscriptions, you use the tools in the Developer
-Console, just as for other in-app products.</p>
-
-<p>At the Developer Console, you can configure these attributes for each
-subscription product:</p>
-
-<ul>
-<li>Purchase Type: always set to “subscription”</li>
-<li>Subscription ID:  An identifier for the subscription</li>
-<li>Publishing State: Unpublished/Published</li>
-<li>Language: The default language for displaying the subscription</li>
-<li>Title: The title of the subscription product</li>
-<li>Description: Details that tell the user about the subscription</li>
-<li>Price: USD price of subscription per recurrence</li>
-<li>Recurrence: monthly or yearly</li>
-<li>Additional currency pricing (can be auto-filled)</li>
-</ul>
-
-<p>For details, please see <a href="{@docRoot}google/play/billing/billing_admin.html">Administering
-In-app Billing</a>.</p>
 
 
-<h2 id="play-dev-api">Google Play Android Developer API</h2>
 
-<p>Google Play offers an HTTP-based API that you can use to remotely query the
-validity of a specific subscription at any time or cancel a subscription. The
-API is designed to be used from your backend servers as a way of securely
-managing subscriptions, as well as extending and integrating subscriptions with
-other services.</p>
-
-<h3 id="using">Using the API</h3>
-
-<p>To use the API, you must first register a project at the <a
-href="https://code.google.com/apis/console">Google APIs Console</a> and receive
-a Client ID and shared secret that  your app will present when calling the
-Google Play Android Developer API. All calls to the API are authenticated with
-OAuth 2.0.</p>
-
-<p>Once your app is registered, you can access the API directly, using standard
-HTTP methods to retrieve and manipulate resources, or you can use the Google
-APIs Client Libraries, which are extended to support the API.</p>
-
-<p>The Google Play Android Developer API is built on a RESTful design that uses
-HTTP and JSON, so any standard web stack can send requests and parse the
-responses. However, if you don’t want to send HTTP requests and parse responses
-manually, you can access the API using the client libraries, which provide
-better language integration, improved security, and support for making calls
-that require user authorization.</p>
-
-<p>For more information about the API and how to access it through the Google
-APIs Client Libraries, see the documentation at:</p> 
-
-<p style="margin-left:1.5em;"><a
-href="https://developers.google.com/android-publisher/v1/">https://developers.
-google.com/android-publisher/v1/</a></p>
-
-<h3 id="quota">Quota</h3>
-
-<p>Applications using the Google Play Android Developer API are limited to an
-initial courtesy usage quota of <strong>15000 requests per day</strong> (per
-application). This should provide enough access for normal
-subscription-validation needs, assuming that you follow the recommendation in
-this section.</p>
-
-<p>If you need to request a higher limit for your application, please use the
-“Request more” link in the <a
-href="https://code.google.com/apis/console/#:quotas">Google APIs Console</a>.
-Also, please read the section below on design best practices for minimizing your
-use of the API.</p>
-
-<h3 id="auth">Authorization</h3>
-
-<p>Calls to the Google Play Android Developer API require authorization. Google
-uses the OAuth 2.0 protocol to allow authorized applications to access user
-data. To learn more, see <a
-href="https://developers.google.com/android-publisher/authorization">Authorization</a>
-in the Google Play Android Developer API documentation.</p>
-
-<h3 id="practices">Using the API efficiently</h3>
-
-<p>Access to the Google Play Android Developer API is regulated to help ensure a
-high-performance environment for all applications that use it. While you can
-request a higher daily quota for your application, we highly recommend that you
-minimize your access using the technique(s) below. </p>
-
-<ul>
-  <li><em>Store subscription expiry on your servers</em> &mdash; your servers
-  should use the Google Play Android Developer API to query the expiration date
-  for new subscription tokens, then store the expiration date locally. This allows
-  you to check the status of subscriptions only at or after the expiration (see
-  below). </li>
-  <li><em>Cache expiration and purchaseState</em> &mdash; If your app contacts
-  your backend servers at runtime to verify subscription validity, your server
-  should cache the expiration and purchaseState to ensure the fastest possible
-  response (and best experience) for the user.</li>
-  <li><em>Query for subscription status only at expiration</em> &mdash; Once your
-  server has retrieved the expiration date of subscription tokens, it should not
-  query the Google Play servers for the subscription status again until the
-  subscription is reaching or has passed the expiration date. Typically, your
-  servers would run a batch query each day to check the status of
-  <em>expiring</em> subscriptions, then update the database. Note that: 
-  <ul>
-    <li>Your servers should not query all subscriptions every day</li>
-    <li>Your servers should never query subscription status dynamically, based on
-    individual requests from your Android application. </li>
-  </ul>
-  </li>
-</ul>
-
-<p>By following those general guidelines, your implementation will offer the
-best possible performance for users and minimize use of the Google Play Android
-Developer API.</p>
 
diff --git a/docs/html/google/play/billing/versions.jd b/docs/html/google/play/billing/versions.jd
index ac7761f..1271a15 100644
--- a/docs/html/google/play/billing/versions.jd
+++ b/docs/html/google/play/billing/versions.jd
@@ -15,9 +15,12 @@
 </ul>
 
 <h3 id="version_3">In-app Billing version 3</h3>
-<p><em>December 2012</em></p>
+<p><em>February 2013</em></p>
 <ul>
-<li>Requires Google Play client version 3.9.16 or higher.
+<li>Purchasing and querying managed in-app items requires Google Play client 
+version 3.9.16 or higher.</li>
+<li>Purchasing and querying subscription items requires Google Play client 
+version 3.10.10 or higher.</li>
 <li>Provides a new Android Interface Definition Language (AIDL) file named {@code IInAppBillingService.aidl}. The new interface offers these features:
 <ul>
 <li>Provides a new API to get details of in-app items published for the app including price, type, title and description.</li>
@@ -27,7 +30,6 @@
 <li>An API to get current purchases of the user immediately. This list will not contain any consumed purchases.</li>
 </ul>
 </li>
-<li>Subscriptions are not yet supported in this version of the API.</li>
 </ul>
 
 <h3 id="version_2">In-app Billing version 2</h3>
diff --git a/docs/html/images/in-app-billing/v3/billing_subscription_v3.png b/docs/html/images/in-app-billing/v3/billing_subscription_v3.png
new file mode 100644
index 0000000..0ba472e
--- /dev/null
+++ b/docs/html/images/in-app-billing/v3/billing_subscription_v3.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index dff3a32..6307c69 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -26,19 +26,19 @@
 
 
 
-sdk.linux_download=android-sdk_r21.1.0-linux.tgz
+sdk.linux_download=android-sdk_r21.1-linux.tgz
 sdk.linux_bytes=91617112
 sdk.linux_checksum=3369a439240cf3dbe165d6b4173900a8
 
-sdk.mac_download=android-sdk_r21.1.0-macosx.zip
+sdk.mac_download=android-sdk_r21.1-macosx.zip
 sdk.mac_bytes=66077080
 sdk.mac_checksum=49903cf79e1f8e3fde54a95bd3666385
 
-sdk.win_download=android-sdk_r21.1.0-windows.zip
+sdk.win_download=android-sdk_r21.1-windows.zip
 sdk.win_bytes=99360755
 sdk.win_checksum=dbece8859da9b66a1e8e7cd47b1e647e
 
-sdk.win_installer=installer_r21.1.0-windows.exe
+sdk.win_installer=installer_r21.1-windows.exe
 sdk.win_installer_bytes=77767013
 sdk.win_installer_checksum=594d8ff8e349db9e783a5f2229561353
 
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 4baa9c3..91a018c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -32,33 +32,33 @@
 
   <li class="nav-section">
     <div class="nav-section-header">
-        <a href="/tools/workflow/index.html"><span class="en">Workflow</span></a>
+        <a href="<?cs var:toroot ?>tools/workflow/index.html"><span class="en">Workflow</span></a>
     </div>
     <ul>
       <li class="nav-section">
-        <div class="nav-section-header"><a href="/tools/devices/index.html"><span class="en">Setting Up Virtual Devices</span></a></div>
+        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/devices/index.html"><span class="en">Setting Up Virtual Devices</span></a></div>
         <ul>
-          <li><a href="/tools/devices/managing-avds.html"><span class="en">With AVD Manager</span></a></li>
-          <li><a href="/tools/devices/managing-avds-cmdline.html"><span class="en">From the Command Line</span></a></li>
-          <li><a href="/tools/devices/emulator.html"><span class="en">Using the Android Emulator</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/devices/managing-avds.html"><span class="en">With AVD Manager</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/devices/managing-avds-cmdline.html"><span class="en">From the Command Line</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/devices/emulator.html"><span class="en">Using the Android Emulator</span></a></li>
         </ul>
       </li>
-      <li><a href="/tools/device.html"><span class="en">Using Hardware Devices</span></a></li>
+      <li><a href="<?cs var:toroot ?>tools/device.html"><span class="en">Using Hardware Devices</span></a></li>
       <li class="nav-section">
-        <div class="nav-section-header"><a href="/tools/projects/index.html"><span class="en">Setting Up Projects</span></a></div>
+        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/projects/index.html"><span class="en">Setting Up Projects</span></a></div>
         <ul>
-          <li><a href="/tools/projects/projects-eclipse.html"><span class="en">From Eclipse with ADT</span></a></li>
-          <li><a href="/tools/projects/projects-cmdline.html"><span class="en">From the Command Line</span></a></li>
-          <li><a href="/tools/projects/templates.html"><span class="en">Using Code Templates</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/projects/projects-eclipse.html"><span class="en">From Eclipse with ADT</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/projects/projects-cmdline.html"><span class="en">From the Command Line</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/projects/templates.html"><span class="en">Using Code Templates</span></a></li>
         </ul>
       </li>
 
 
       <li class="nav-section">
-        <div class="nav-section-header"><a href="/tools/building/index.html"><span class="en">Building and Running</span></a></div>
+        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/building/index.html"><span class="en">Building and Running</span></a></div>
         <ul>
-          <li><a href="/tools/building/building-eclipse.html"><span class="en">From Eclipse with ADT</span></a></li>
-          <li><a href="/tools/building/building-cmdline.html"><span class="en">From the Command Line</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/building/building-eclipse.html"><span class="en">From Eclipse with ADT</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/building/building-cmdline.html"><span class="en">From the Command Line</span></a></li>
         </ul>
       </li>
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 9684f20..e94ddae 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -37,8 +37,8 @@
  * Canvas and Drawables</a> developer guide.</p></div>
  */
 public class Canvas {
-    // assigned in constructors or setBitmap, freed in finalizer
-    int mNativeCanvas;
+    // assigned in constructors, freed in finalizer
+    final int mNativeCanvas;
     
     // may be null
     private Bitmap mBitmap;
@@ -71,7 +71,7 @@
     private final CanvasFinalizer mFinalizer;
 
     private static class CanvasFinalizer {
-        private int mNativeCanvas;
+        private final int mNativeCanvas;
 
         public CanvasFinalizer(int nativeCanvas) {
             mNativeCanvas = nativeCanvas;
@@ -131,17 +131,6 @@
     }
 
     /**
-     * Replace existing canvas while ensuring that the swap has occurred before
-     * the previous native canvas is unreferenced.
-     */
-    private void safeCanvasSwap(int nativeCanvas) {
-        final int oldCanvas = mNativeCanvas;
-        mNativeCanvas = nativeCanvas;
-        mFinalizer.mNativeCanvas = nativeCanvas;
-        finalizer(oldCanvas);
-    }
-    
-    /**
      * Returns null.
      * 
      * @deprecated This method is not supported and should not be invoked.
@@ -167,11 +156,11 @@
     }
 
     /**
-     * Specify a bitmap for the canvas to draw into. As a side-effect, the
-     * canvas' target density is updated to match that of the bitmap while all
-     * other state such as the layers, filters, matrix, and clip are reset.
+     * Specify a bitmap for the canvas to draw into.  As a side-effect, also
+     * updates the canvas's target density to match that of the bitmap.
      *
      * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
+     * 
      * @see #setDensity(int)
      * @see #getDensity()
      */
@@ -180,19 +169,17 @@
             throw new RuntimeException("Can't set a bitmap device on a GL canvas");
         }
 
-        if (bitmap == null) {
-            safeCanvasSwap(initRaster(0));
-            mDensity = Bitmap.DENSITY_NONE;
-        } else {
+        int pointer = 0;
+        if (bitmap != null) {
             if (!bitmap.isMutable()) {
                 throw new IllegalStateException();
             }
             throwIfRecycled(bitmap);
-
-            safeCanvasSwap(initRaster(bitmap.ni()));
             mDensity = bitmap.mDensity;
+            pointer = bitmap.ni();
         }
 
+        native_setBitmap(mNativeCanvas, pointer);
         mBitmap = bitmap;
     }
     
@@ -707,7 +694,7 @@
      *              does not intersect with the canvas' clip
      */
     public boolean quickReject(RectF rect, EdgeType type) {
-        return native_quickReject(mNativeCanvas, rect);
+        return native_quickReject(mNativeCanvas, rect, type.nativeInt);
     }
 
     /**
@@ -727,7 +714,7 @@
      *                    does not intersect with the canvas' clip
      */
     public boolean quickReject(Path path, EdgeType type) {
-        return native_quickReject(mNativeCanvas, path.ni());
+        return native_quickReject(mNativeCanvas, path.ni(), type.nativeInt);
     }
 
     /**
@@ -750,9 +737,9 @@
      * @return            true if the rect (transformed by the canvas' matrix)
      *                    does not intersect with the canvas' clip
      */
-    public boolean quickReject(float left, float top, float right, float bottom,
-                               EdgeType type) {
-        return native_quickReject(mNativeCanvas, left, top, right, bottom);
+    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
+        return native_quickReject(mNativeCanvas, left, top, right, bottom,
+                                  type.nativeInt);
     }
 
     /**
@@ -1212,7 +1199,7 @@
      * meshHeight+1 vertices down. The verts array is accessed in row-major
      * order, so that the first meshWidth+1 vertices are distributed across the
      * top of the bitmap from left to right. A more general version of this
-     * methid is drawVertices().
+     * method is drawVertices().
      *
      * @param bitmap The bitmap to draw using the mesh
      * @param meshWidth The number of columns in the mesh. Nothing is drawn if
@@ -1221,7 +1208,7 @@
      *                   this is 0
      * @param verts Array of x,y pairs, specifying where the mesh should be
      *              drawn. There must be at least
-     *              (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values
+     *              (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values
      *              in the array
      * @param vertOffset Number of verts elements to skip before drawing
      * @param colors May be null. Specifies a color at each vertex, which is
@@ -1612,6 +1599,7 @@
     public static native void freeTextLayoutCaches();
 
     private static native int initRaster(int nativeBitmapOrZero);
+    private static native void native_setBitmap(int nativeCanvas, int bitmap);
     private static native int native_saveLayer(int nativeCanvas, RectF bounds,
                                                int paint, int layerFlags);
     private static native int native_saveLayer(int nativeCanvas, float l,
@@ -1642,12 +1630,15 @@
                                                        Rect bounds);
     private static native void native_getCTM(int canvas, int matrix);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     RectF rect);
+                                                     RectF rect,
+                                                     int native_edgeType);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     int path);
+                                                     int path,
+                                                     int native_edgeType);
     private static native boolean native_quickReject(int nativeCanvas,
                                                      float left, float top,
-                                                     float right, float bottom);
+                                                     float right, float bottom,
+                                                     int native_edgeType);
     private static native void native_drawRGB(int nativeCanvas, int r, int g,
                                               int b);
     private static native void native_drawARGB(int nativeCanvas, int a, int r,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3a83d12..7d99fec 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1849,7 +1849,7 @@
      * @hide
      */
     public int getTextRunCursor(String text, int contextStart, int contextEnd,
-            int flags, int offset, int cursorOpt) {
+            int offset, int cursorOpt) {
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 157c7d1..f6b5ffc 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -375,9 +375,9 @@
      */
     public enum Direction {
         /** clockwise */
-        CW  (1),    // must match enum in SkPath.h
+        CW  (0),    // must match enum in SkPath.h
         /** counter-clockwise */
-        CCW (2);    // must match enum in SkPath.h
+        CCW (1);    // must match enum in SkPath.h
         
         Direction(int ni) {
             nativeInt = ni;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c68c9f7..4487a3c 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -225,4 +225,16 @@
     private static native int  nativeGetStyle(int native_instance);
     private static native int  nativeCreateFromAsset(AssetManager mgr, String path);
     private static native int nativeCreateFromFile(String path);
+
+    /**
+     * Set the global gamma coefficients for black and white text. This call is
+     * usually a no-op in shipping products, and only exists for testing during
+     * development.
+     *
+     * @param blackGamma gamma coefficient for black text
+     * @param whiteGamma gamma coefficient for white text
+     *
+     * @hide - this is just for calibrating devices, not for normal apps
+     */
+    public static native void setGammaForText(float blackGamma, float whiteGamma);
 }
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index a79ce17..f6c07d1 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -906,7 +906,8 @@
               dk == DataKind.PIXEL_LA ||
               dk == DataKind.PIXEL_RGB ||
               dk == DataKind.PIXEL_RGBA ||
-              dk == DataKind.PIXEL_DEPTH)) {
+              dk == DataKind.PIXEL_DEPTH ||
+              dk == DataKind.PIXEL_YUV)) {
             throw new RSIllegalArgumentException("Unsupported DataKind");
         }
         if (!(dt == DataType.UNSIGNED_8 ||
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 50d888f..10f4daa 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -519,6 +519,8 @@
     native void rsnScriptForEach(int con, int id, int slot, int ain, int aout);
     native void rsnScriptForEachClipped(int con, int id, int slot, int ain, int aout, byte[] params,
                                         int xstart, int xend, int ystart, int yend, int zstart, int zend);
+    native void rsnScriptForEachClipped(int con, int id, int slot, int ain, int aout,
+                                        int xstart, int xend, int ystart, int yend, int zstart, int zend);
     synchronized void nScriptForEach(int id, int slot, int ain, int aout, byte[] params) {
         validate();
         if (params == null) {
@@ -531,7 +533,11 @@
     synchronized void nScriptForEachClipped(int id, int slot, int ain, int aout, byte[] params,
                                             int xstart, int xend, int ystart, int yend, int zstart, int zend) {
         validate();
-        rsnScriptForEachClipped(mContext, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend);
+        if (params == null) {
+            rsnScriptForEachClipped(mContext, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend);
+        } else {
+            rsnScriptForEachClipped(mContext, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend);
+        }
     }
 
     native void rsnScriptInvokeV(int con, int id, int slot, byte[] params);
@@ -795,6 +801,9 @@
     Sampler mSampler_WRAP_NEAREST;
     Sampler mSampler_WRAP_LINEAR;
     Sampler mSampler_WRAP_LINEAR_MIP_LINEAR;
+    Sampler mSampler_MIRRORED_REPEAT_NEAREST;
+    Sampler mSampler_MIRRORED_REPEAT_LINEAR;
+    Sampler mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR;
 
     ProgramStore mProgramStore_BLEND_NONE_DEPTH_TEST;
     ProgramStore mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH;
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
index 0df1012..057e9b5 100644
--- a/graphics/java/android/renderscript/Sampler.java
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -39,7 +39,8 @@
         LINEAR_MIP_LINEAR (2),
         LINEAR_MIP_NEAREST (5),
         WRAP (3),
-        CLAMP (4);
+        CLAMP (4),
+        MIRRORED_REPEAT (6);
 
         int mID;
         Value(int id) {
@@ -134,8 +135,8 @@
     }
 
     /**
-     * Retrieve a sampler with ag set to linear, min linear mipmap linear, and
-     * to and wrap modes set to clamp.
+     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
+     * wrap modes set to clamp.
      *
      * @param rs Context to which the sampler will belong.
      *
@@ -174,7 +175,7 @@
     }
 
     /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
      * wrap.
      *
      * @param rs Context to which the sampler will belong.
@@ -194,8 +195,8 @@
     }
 
     /**
-     * Retrieve a sampler with ag set to linear, min linear mipmap linear, and
-     * to and wrap modes set to wrap.
+     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
+     * wrap modes set to wrap.
      *
      * @param rs Context to which the sampler will belong.
      *
@@ -213,6 +214,65 @@
         return rs.mSampler_WRAP_LINEAR_MIP_LINEAR;
     }
 
+    /**
+     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
+     * mirrored repeat.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler MIRRORED_REPEAT_NEAREST(RenderScript rs) {
+        if(rs.mSampler_MIRRORED_REPEAT_NEAREST == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.NEAREST);
+            b.setMagnification(Value.NEAREST);
+            b.setWrapS(Value.MIRRORED_REPEAT);
+            b.setWrapT(Value.MIRRORED_REPEAT);
+            rs.mSampler_MIRRORED_REPEAT_NEAREST = b.create();
+        }
+        return rs.mSampler_MIRRORED_REPEAT_NEAREST;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
+     * mirrored repeat.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler MIRRORED_REPEAT_LINEAR(RenderScript rs) {
+        if(rs.mSampler_MIRRORED_REPEAT_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.MIRRORED_REPEAT);
+            b.setWrapT(Value.MIRRORED_REPEAT);
+            rs.mSampler_MIRRORED_REPEAT_LINEAR = b.create();
+        }
+        return rs.mSampler_MIRRORED_REPEAT_LINEAR;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
+     * mirrored repeat.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler MIRRORED_REPEAT_LINEAR_MIP_LINEAR(RenderScript rs) {
+        if(rs.mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR_MIP_LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.MIRRORED_REPEAT);
+            b.setWrapT(Value.MIRRORED_REPEAT);
+            rs.mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR = b.create();
+        }
+        return rs.mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR;
+    }
 
     /**
      * Builder for creating non-standard samplers.  Usefull if mix and match of
@@ -258,7 +318,7 @@
         }
 
         public void setWrapS(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP) {
+            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
                 mWrapS = v;
             } else {
                 throw new IllegalArgumentException("Invalid value");
@@ -266,7 +326,7 @@
         }
 
         public void setWrapT(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP) {
+            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
                 mWrapT = v;
             } else {
                 throw new IllegalArgumentException("Invalid value");
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index d1446f6..9507030 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9a8a6e8..5e631af 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -43,7 +43,7 @@
 #include <rsEnv.h>
 #include <gui/Surface.h>
 #include <gui/GLConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
 //#define LOG_API ALOGE
@@ -247,7 +247,7 @@
 
     } else {
         st = SurfaceTexture_getSurfaceTexture(_env, sur);
-        window = new SurfaceTextureClient(st->getBufferQueue());
+        window = new Surface(st->getBufferQueue());
     }
 
     rsContextSetSurface(con, width, height, window.get());
@@ -1055,10 +1055,30 @@
 static void
 nScriptForEachClipped(JNIEnv *_env, jobject _this, RsContext con,
                       jint script, jint slot, jint ain, jint aout,
-                      jbyteArray params, jint xstart, jint xend,
+                      jint xstart, jint xend,
                       jint ystart, jint yend, jint zstart, jint zend)
 {
     LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
+    RsScriptCall sc;
+    sc.xStart = xstart;
+    sc.xEnd = xend;
+    sc.yStart = ystart;
+    sc.yEnd = yend;
+    sc.zStart = zstart;
+    sc.zEnd = zend;
+    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
+    sc.arrayStart = 0;
+    sc.arrayEnd = 0;
+    rsScriptForEach(con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, NULL, 0, &sc, sizeof(sc));
+}
+
+static void
+nScriptForEachClippedV(JNIEnv *_env, jobject _this, RsContext con,
+                       jint script, jint slot, jint ain, jint aout,
+                       jbyteArray params, jint xstart, jint xend,
+                       jint ystart, jint yend, jint zstart, jint zend)
+{
+    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
     jint len = _env->GetArrayLength(params);
     jbyte *ptr = _env->GetByteArrayElements(params, NULL);
     RsScriptCall sc;
@@ -1536,7 +1556,8 @@
 {"rsnScriptInvokeV",                 "(III[B)V",                              (void*)nScriptInvokeV },
 {"rsnScriptForEach",                 "(IIIII)V",                              (void*)nScriptForEach },
 {"rsnScriptForEach",                 "(IIIII[B)V",                            (void*)nScriptForEachV },
-{"rsnScriptForEachClipped",          "(IIIII[BIIIIII)V",                      (void*)nScriptForEachClipped },
+{"rsnScriptForEachClipped",          "(IIIIIIIIIII)V",                        (void*)nScriptForEachClipped },
+{"rsnScriptForEachClipped",          "(IIIII[BIIIIII)V",                      (void*)nScriptForEachClippedV },
 {"rsnScriptSetVarI",                 "(IIII)V",                               (void*)nScriptSetVarI },
 {"rsnScriptSetVarJ",                 "(IIIJ)V",                               (void*)nScriptSetVarJ },
 {"rsnScriptSetVarF",                 "(IIIF)V",                               (void*)nScriptSetVarF },
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index b56aff8..53e8b49 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -37,7 +37,7 @@
 extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj);
 
 /* Creates a Surface from an IGraphicBufferProducer. */
-extern jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
         const sp<IGraphicBufferProducer>& bufferProducer);
 
 } // namespace android
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 31c38d5..d7119fff 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -336,7 +336,12 @@
         KeyChainConnection keyChainConnection = bind(context);
         try {
             IKeyChainService keyChainService = keyChainConnection.getService();
-            byte[] certificateBytes = keyChainService.getCertificate(alias);
+
+            final byte[] certificateBytes = keyChainService.getCertificate(alias);
+            if (certificateBytes == null) {
+                return null;
+            }
+
             TrustedCertificateStore store = new TrustedCertificateStore();
             List<X509Certificate> chain = store
                     .getCertificateChain(toCertificate(certificateBytes));
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ceaff37..4b69317 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -74,6 +74,10 @@
         }
     }
 
+    public boolean isUnlocked() {
+        return state() == State.UNLOCKED;
+    }
+
     public byte[] get(String key) {
         try {
             return mBinder.get(key);
@@ -85,7 +89,7 @@
 
     public boolean put(String key, byte[] value) {
         try {
-            return mBinder.insert(key, value) == NO_ERROR;
+            return mBinder.insert(key, value, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -94,7 +98,7 @@
 
     public boolean delete(String key) {
         try {
-            return mBinder.del(key) == NO_ERROR;
+            return mBinder.del(key, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -103,7 +107,7 @@
 
     public boolean contains(String key) {
         try {
-            return mBinder.exist(key) == NO_ERROR;
+            return mBinder.exist(key, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -112,7 +116,7 @@
 
     public String[] saw(String prefix) {
         try {
-            return mBinder.saw(prefix);
+            return mBinder.saw(prefix, -1);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
@@ -167,7 +171,7 @@
 
     public boolean generate(String key) {
         try {
-            return mBinder.generate(key) == NO_ERROR;
+            return mBinder.generate(key, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -176,7 +180,7 @@
 
     public boolean importKey(String keyName, byte[] key) {
         try {
-            return mBinder.import_key(keyName, key) == NO_ERROR;
+            return mBinder.import_key(keyName, key, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -194,7 +198,7 @@
 
     public boolean delKey(String key) {
         try {
-            return mBinder.del_key(key) == NO_ERROR;
+            return mBinder.del_key(key, -1) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
index d108caaa..cd031b4 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -62,11 +62,10 @@
 
         assertTrue(mAndroidKeyStore.reset());
 
-        assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+        assertFalse(mAndroidKeyStore.isUnlocked());
 
         assertTrue(mAndroidKeyStore.password("1111"));
-
-        assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+        assertTrue(mAndroidKeyStore.isUnlocked());
 
         assertEquals(0, mAndroidKeyStore.saw("").length);
 
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index c376f3d..8928e06 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -467,12 +467,10 @@
         mAndroidKeyStore = android.security.KeyStore.getInstance();
 
         assertTrue(mAndroidKeyStore.reset());
-
-        assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+        assertFalse(mAndroidKeyStore.isUnlocked());
 
         assertTrue(mAndroidKeyStore.password("1111"));
-
-        assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+        assertTrue(mAndroidKeyStore.isUnlocked());
 
         assertEquals(0, mAndroidKeyStore.saw("").length);
 
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d533fa0..5f2a4d5 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -11,6 +11,8 @@
 		FontRenderer.cpp \
 		GammaFontRenderer.cpp \
 		Caches.cpp \
+		DisplayList.cpp \
+		DeferredDisplayList.cpp \
 		DisplayListLogBuffer.cpp \
 		DisplayListRenderer.cpp \
 		Dither.cpp \
@@ -38,19 +40,23 @@
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 
+	intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+
 	LOCAL_C_INCLUDES += \
 		$(JNI_H_INCLUDE) \
 		$(LOCAL_PATH)/../../include/utils \
 		external/skia/include/core \
 		external/skia/include/effects \
 		external/skia/include/images \
-		external/skia/src/core \
 		external/skia/src/ports \
-		external/skia/include/utils
+		external/skia/include/utils \
+		$(intermediates) \
+		frameworks/rs/cpp \
+		frameworks/rs
 
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
+	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui libRS libRScpp
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
@@ -64,5 +70,5 @@
 
 	include $(BUILD_SHARED_LIBRARY)
 
-    include $(call all-makefiles-under,$(LOCAL_PATH))
+	include $(call all-makefiles-under,$(LOCAL_PATH))
 endif
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 74201d1..88f1d83 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -365,11 +365,12 @@
     }
 }
 
-void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices) {
-    if (force || vertices != mCurrentTexCoordsPointer) {
+void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
         GLuint slot = currentProgram->texCoords;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
+        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
         mCurrentTexCoordsPointer = vertices;
+        mCurrentTexCoordsStride = stride;
     }
 }
 
@@ -390,7 +391,7 @@
     }
 }
 
-void Caches::disbaleTexCoordsVertexArray() {
+void Caches::disableTexCoordsVertexArray() {
     if (mTexCoordsArrayEnabled) {
         glDisableVertexAttribArray(Program::kBindingTexCoords);
         mTexCoordsArrayEnabled = false;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index d70c0e3..0ca2ffd 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -183,7 +183,7 @@
      * Binds an attrib to the specified float vertex pointer.
      * Assumes a stride of gMeshStride and a size of 2.
      */
-    void bindTexCoordsVertexPointer(bool force, GLvoid* vertices);
+    void bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride);
 
     /**
      * Resets the vertex pointers.
@@ -192,7 +192,7 @@
     void resetTexCoordsVertexPointer();
 
     void enableTexCoordsVertexArray();
-    void disbaleTexCoordsVertexArray();
+    void disableTexCoordsVertexArray();
 
     /**
      * Activate the specified texture unit. The texture unit must
@@ -299,6 +299,7 @@
     void* mCurrentPositionPointer;
     GLsizei mCurrentPositionStride;
     void* mCurrentTexCoordsPointer;
+    GLsizei mCurrentTexCoordsStride;
 
     bool mTexCoordsArrayEnabled;
 
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 20eb5e1..9a6494f 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -74,6 +74,9 @@
 // Turn on to enable additional debugging in the font renderers
 #define DEBUG_FONT_RENDERER 0
 
+// Turn on to log draw operation batching and deferral information
+#define DEBUG_DEFER 0
+
 // Turn on to dump display list state
 #define DEBUG_DISPLAY_LIST 0
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
new file mode 100644
index 0000000..8962964
--- /dev/null
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/Trace.h>
+
+#include "Debug.h"
+#include "DisplayListOp.h"
+#include "OpenGLRenderer.h"
+
+#if DEBUG_DEFER
+    #define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+    #define DEFER_LOGD(...)
+#endif
+
+namespace android {
+namespace uirenderer {
+
+class DrawOpBatch {
+public:
+    DrawOpBatch() {
+        mOps.clear();
+    }
+
+    ~DrawOpBatch() {
+        mOps.clear();
+    }
+
+    void add(DrawOp* op) {
+        // NOTE: ignore empty bounds special case, since we don't merge across those ops
+        mBounds.unionWith(op->state.mBounds);
+        mOps.add(op);
+    }
+
+    bool intersects(Rect& rect) {
+        if (!rect.intersects(mBounds)) return false;
+        for (unsigned int i = 0; i < mOps.size(); i++) {
+            if (rect.intersects(mOps[i]->state.mBounds)) {
+#if DEBUG_DEFER
+                DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
+                        mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
+                        mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
+                mOps[i]->output(2);
+#endif
+                return true;
+            }
+        }
+        return false;
+    }
+
+    Vector<DrawOp*> mOps;
+private:
+    Rect mBounds;
+};
+
+void DeferredDisplayList::clear() {
+    for (int i = 0; i < kOpBatch_Count; i++) {
+        mBatchIndices[i] = -1;
+    }
+    for (unsigned int i = 0; i < mBatches.size(); i++) {
+        delete mBatches[i];
+    }
+    mBatches.clear();
+}
+
+void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
+    if (CC_UNLIKELY(disallowReorder)) {
+        if (!mBatches.isEmpty()) {
+            mBatches[0]->add(op);
+            return;
+        }
+        DrawOpBatch* b = new DrawOpBatch();
+        b->add(op);
+        mBatches.add(b);
+        return;
+    }
+
+    // disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
+    // the new op into it
+    DrawOpBatch* targetBatch = NULL;
+    int batchId = op->getBatchId();
+
+    if (!mBatches.isEmpty()) {
+        if (op->state.mBounds.isEmpty()) {
+            // don't know the bounds for op, so add to last batch and start from scratch on next op
+            mBatches.top()->add(op);
+            for (int i = 0; i < kOpBatch_Count; i++) {
+                mBatchIndices[i] = -1;
+            }
+#if DEBUG_DEFER
+            DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
+            op->output(2);
+#endif
+            return;
+        }
+
+        if (batchId >= 0 && mBatchIndices[batchId] != -1) {
+            int targetIndex = mBatchIndices[batchId];
+            targetBatch = mBatches[targetIndex];
+            // iterate back toward target to see if anything drawn since should overlap the new op
+            for (int i = mBatches.size() - 1; i > targetIndex; i--) {
+                DrawOpBatch* overBatch = mBatches[i];
+                if (overBatch->intersects(op->state.mBounds)) {
+                    targetBatch = NULL;
+#if DEBUG_DEFER
+                    DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
+                            targetIndex, i);
+                    op->output(2);
+#endif
+                    break;
+                }
+            }
+        }
+    }
+    if (!targetBatch) {
+        targetBatch = new DrawOpBatch();
+        mBatches.add(targetBatch);
+        if (batchId >= 0) {
+            mBatchIndices[batchId] = mBatches.size() - 1;
+        }
+    }
+    targetBatch->add(op);
+}
+
+status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
+        uint32_t level) {
+    ATRACE_CALL();
+    status_t status = DrawGlInfo::kStatusDone;
+
+    if (isEmpty()) return status; // nothing to flush
+
+    DEFER_LOGD("--flushing");
+    DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
+    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    int opCount = 0;
+    for (unsigned int i = 0; i < mBatches.size(); i++) {
+        DrawOpBatch* batch = mBatches[i];
+        for (unsigned int j = 0; j < batch->mOps.size(); j++) {
+            DrawOp* op = batch->mOps[j];
+
+            renderer.restoreDisplayState(op->state);
+
+#if DEBUG_DEFER
+            op->output(2);
+#endif
+            status |= op->applyDraw(renderer, dirty, level,
+                    op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
+            opCount++;
+        }
+    }
+
+    DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
+    renderer.restoreToCount(restoreTo);
+    renderer.setDrawModifiers(restoreDrawModifiers);
+    clear();
+    return status;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
new file mode 100644
index 0000000..4fcb297
--- /dev/null
+++ b/libs/hwui/DeferredDisplayList.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
+#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+class DrawOp;
+class DrawOpBatch;
+class OpenGLRenderer;
+class SkiaShader;
+
+class DeferredDisplayList {
+public:
+    DeferredDisplayList() { clear(); }
+    ~DeferredDisplayList() { clear(); }
+
+    enum OpBatchId {
+        kOpBatch_None = -1, // Don't batch
+        kOpBatch_Bitmap,
+        kOpBatch_Patch,
+        kOpBatch_AlphaVertices,
+        kOpBatch_Vertices,
+        kOpBatch_AlphaMaskTexture,
+        kOpBatch_Text,
+        kOpBatch_ColorText,
+
+        kOpBatch_Count, // Add other batch ids before this
+    };
+
+    bool isEmpty() { return mBatches.isEmpty(); }
+
+    /**
+     * Plays back all of the draw ops recorded into batches to the renderer.
+     * Adjusts the state of the renderer as necessary, and restores it when complete
+     */
+    status_t flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
+            uint32_t level);
+
+    /**
+     * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
+     * disallowReorder is false, respecting draw order when overlaps occur
+     */
+    void add(DrawOp* op, bool disallowReorder);
+
+private:
+    void clear();
+
+
+    Vector<DrawOpBatch*> mBatches;
+    int mBatchIndices[kOpBatch_Count];
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
new file mode 100644
index 0000000..398f719
--- /dev/null
+++ b/libs/hwui/DisplayList.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Debug.h"
+#include "DisplayList.h"
+#include "DisplayListOp.h"
+#include "DisplayListLogBuffer.h"
+
+namespace android {
+namespace uirenderer {
+
+void DisplayList::outputLogBuffer(int fd) {
+    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+    if (logBuffer.isEmpty()) {
+        return;
+    }
+
+    FILE *file = fdopen(fd, "a");
+
+    fprintf(file, "\nRecent DisplayList operations\n");
+    logBuffer.outputCommands(file);
+
+    String8 cachesLog;
+    Caches::getInstance().dumpMemoryUsage(cachesLog);
+    fprintf(file, "\nCaches:\n%s", cachesLog.string());
+    fprintf(file, "\n");
+
+    fflush(file);
+}
+
+DisplayList::DisplayList(const DisplayListRenderer& recorder) :
+    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
+    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
+
+    initFromDisplayListRenderer(recorder);
+}
+
+DisplayList::~DisplayList() {
+    clearResources();
+}
+
+void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
+    if (displayList) {
+        DISPLAY_LIST_LOGD("Deferring display list destruction");
+        Caches::getInstance().deleteDisplayListDeferred(displayList);
+    }
+}
+
+void DisplayList::clearResources() {
+    mDisplayListData = NULL;
+    delete mTransformMatrix;
+    delete mTransformCamera;
+    delete mTransformMatrix3D;
+    delete mStaticMatrix;
+    delete mAnimationMatrix;
+
+    mTransformMatrix = NULL;
+    mTransformCamera = NULL;
+    mTransformMatrix3D = NULL;
+    mStaticMatrix = NULL;
+    mAnimationMatrix = NULL;
+
+    Caches& caches = Caches::getInstance();
+    caches.unregisterFunctors(mFunctorCount);
+    caches.resourceCache.lock();
+
+    for (size_t i = 0; i < mBitmapResources.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
+    }
+
+    for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
+        SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
+        caches.resourceCache.decrementRefcountLocked(bitmap);
+        caches.resourceCache.destructorLocked(bitmap);
+    }
+
+    for (size_t i = 0; i < mFilterResources.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
+    }
+
+    for (size_t i = 0; i < mShaders.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
+        caches.resourceCache.destructorLocked(mShaders.itemAt(i));
+    }
+
+    for (size_t i = 0; i < mSourcePaths.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
+    }
+
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
+    }
+
+    caches.resourceCache.unlock();
+
+    for (size_t i = 0; i < mPaints.size(); i++) {
+        delete mPaints.itemAt(i);
+    }
+
+    for (size_t i = 0; i < mRegions.size(); i++) {
+        delete mRegions.itemAt(i);
+    }
+
+    for (size_t i = 0; i < mPaths.size(); i++) {
+        SkPath* path = mPaths.itemAt(i);
+        caches.pathCache.remove(path);
+        delete path;
+    }
+
+    for (size_t i = 0; i < mMatrices.size(); i++) {
+        delete mMatrices.itemAt(i);
+    }
+
+    mBitmapResources.clear();
+    mOwnedBitmapResources.clear();
+    mFilterResources.clear();
+    mShaders.clear();
+    mSourcePaths.clear();
+    mPaints.clear();
+    mRegions.clear();
+    mPaths.clear();
+    mMatrices.clear();
+    mLayers.clear();
+}
+
+void DisplayList::reset() {
+    clearResources();
+    init();
+}
+
+void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
+    if (reusing) {
+        // re-using display list - clear out previous allocations
+        clearResources();
+    }
+
+    init();
+
+    mDisplayListData = recorder.getDisplayListData();
+    mSize = mDisplayListData->allocator.usedSize();
+
+    if (mSize == 0) {
+        return;
+    }
+
+    mFunctorCount = recorder.getFunctorCount();
+
+    Caches& caches = Caches::getInstance();
+    caches.registerFunctors(mFunctorCount);
+    caches.resourceCache.lock();
+
+    const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
+    for (size_t i = 0; i < bitmapResources.size(); i++) {
+        SkBitmap* resource = bitmapResources.itemAt(i);
+        mBitmapResources.add(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
+    }
+
+    const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
+    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
+        SkBitmap* resource = ownedBitmapResources.itemAt(i);
+        mOwnedBitmapResources.add(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
+    }
+
+    const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
+    for (size_t i = 0; i < filterResources.size(); i++) {
+        SkiaColorFilter* resource = filterResources.itemAt(i);
+        mFilterResources.add(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
+    }
+
+    const Vector<SkiaShader*>& shaders = recorder.getShaders();
+    for (size_t i = 0; i < shaders.size(); i++) {
+        SkiaShader* resource = shaders.itemAt(i);
+        mShaders.add(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
+    }
+
+    const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
+    for (size_t i = 0; i < sourcePaths.size(); i++) {
+        mSourcePaths.add(sourcePaths.itemAt(i));
+        caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
+    }
+
+    const Vector<Layer*>& layers = recorder.getLayers();
+    for (size_t i = 0; i < layers.size(); i++) {
+        mLayers.add(layers.itemAt(i));
+        caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
+    }
+
+    caches.resourceCache.unlock();
+
+    mPaints.appendVector(recorder.getPaints());
+    mRegions.appendVector(recorder.getRegions());
+    mPaths.appendVector(recorder.getPaths());
+    mMatrices.appendVector(recorder.getMatrices());
+}
+
+void DisplayList::init() {
+    mSize = 0;
+    mIsRenderable = true;
+    mFunctorCount = 0;
+    mLeft = 0;
+    mTop = 0;
+    mRight = 0;
+    mBottom = 0;
+    mClipChildren = true;
+    mAlpha = 1;
+    mMultipliedAlpha = 255;
+    mHasOverlappingRendering = true;
+    mTranslationX = 0;
+    mTranslationY = 0;
+    mRotation = 0;
+    mRotationX = 0;
+    mRotationY= 0;
+    mScaleX = 1;
+    mScaleY = 1;
+    mPivotX = 0;
+    mPivotY = 0;
+    mCameraDistance = 0;
+    mMatrixDirty = false;
+    mMatrixFlags = 0;
+    mPrevWidth = -1;
+    mPrevHeight = -1;
+    mWidth = 0;
+    mHeight = 0;
+    mPivotExplicitlySet = false;
+    mCaching = false;
+}
+
+size_t DisplayList::getSize() {
+    return mSize;
+}
+
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void DisplayList::output(uint32_t level) {
+    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
+            mName.string(), isRenderable());
+
+    ALOGD("%*s%s %d", level * 2, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    outputViewProperties(level);
+    int flags = DisplayListOp::kOpLogFlag_Recurse;
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        mDisplayListData->displayListOps[i]->output(level, flags);
+    }
+    ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
+}
+
+float DisplayList::getPivotX() {
+    updateMatrix();
+    return mPivotX;
+}
+
+float DisplayList::getPivotY() {
+    updateMatrix();
+    return mPivotY;
+}
+
+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(uint32_t level) {
+    updateMatrix();
+    if (mLeft != 0 || mTop != 0) {
+        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
+    }
+    if (mStaticMatrix) {
+        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
+                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
+    }
+    if (mAnimationMatrix) {
+        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
+                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
+    }
+    if (mMatrixFlags != 0) {
+        if (mMatrixFlags == TRANSLATION) {
+            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
+        } else {
+            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
+                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
+        }
+    }
+    if (mAlpha < 1 && !mCaching) {
+        if (!mHasOverlappingRendering) {
+            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
+        } else {
+            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            if (mClipChildren) {
+                flags |= SkCanvas::kClipToLayer_SaveFlag;
+            }
+            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
+                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+                    mMultipliedAlpha, flags);
+        }
+    }
+    if (mClipChildren && !mCaching) {
+        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
+                (float) mRight - mLeft, (float) mBottom - mTop);
+    }
+}
+
+void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
+#if DEBUG_DISPLAYLIST
+    outputViewProperties(level);
+#endif
+    updateMatrix();
+    if (mLeft != 0 || mTop != 0) {
+        renderer.translate(mLeft, mTop);
+    }
+    if (mStaticMatrix) {
+        renderer.concatMatrix(mStaticMatrix);
+    } else if (mAnimationMatrix) {
+        renderer.concatMatrix(mAnimationMatrix);
+    }
+    if (mMatrixFlags != 0) {
+        if (mMatrixFlags == TRANSLATION) {
+            renderer.translate(mTranslationX, mTranslationY);
+        } else {
+            renderer.concatMatrix(mTransformMatrix);
+        }
+    }
+    if (mAlpha < 1 && !mCaching) {
+        if (!mHasOverlappingRendering) {
+            renderer.setAlpha(mAlpha);
+        } else {
+            // 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;
+            }
+            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
+                    mMultipliedAlpha, flags);
+        }
+    }
+    if (mClipChildren && !mCaching) {
+        renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
+                SkRegion::kIntersect_Op);
+    }
+}
+
+status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
+        DeferredDisplayList* deferredList) {
+    status_t drawGlStatus = DrawGlInfo::kStatusDone;
+
+#if DEBUG_DISPLAY_LIST
+    Rect* clipRect = renderer.getClipRect();
+    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
+            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
+            clipRect->right, clipRect->bottom);
+#endif
+
+    renderer.startMark(mName.string());
+
+    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
+
+    if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
+        // flush before a saveLayerAlpha/setAlpha
+        // TODO: make this cleaner
+        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
+    }
+    setViewProperties(renderer, level);
+
+    if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
+        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
+        renderer.restoreToCount(restoreTo);
+        renderer.endMark();
+        return drawGlStatus;
+    }
+
+    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+    int saveCount = renderer.getSaveCount() - 1;
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        DisplayListOp *op = mDisplayListData->displayListOps[i];
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+        Caches::getInstance().eventMark(strlen(op->name()), op->name());
+#endif
+
+        drawGlStatus |= op->replay(renderer, dirty, flags,
+                saveCount, level, mCaching, mMultipliedAlpha, deferredList);
+        logBuffer.writeCommand(level, op->name());
+    }
+
+    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
+    renderer.restoreToCount(restoreTo);
+    renderer.endMark();
+
+    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
+            drawGlStatus);
+
+    if (!level && CC_LIKELY(deferredList)) {
+        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
+    }
+
+    return drawGlStatus;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
new file mode 100644
index 0000000..86c9ec0
--- /dev/null
+++ b/libs/hwui/DisplayList.h
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_DISPLAY_LIST_H
+#define ANDROID_HWUI_DISPLAY_LIST_H
+
+#include <SkCamera.h>
+#include <SkMatrix.h>
+
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <cutils/compiler.h>
+
+#include "utils/LinearAllocator.h"
+
+#include "Debug.h"
+
+#define TRANSLATION 0x0001
+#define ROTATION    0x0002
+#define ROTATION_3D 0x0004
+#define SCALE       0x0008
+#define PIVOT       0x0010
+
+class SkBitmap;
+class SkPaint;
+class SkPath;
+class SkRegion;
+
+namespace android {
+namespace uirenderer {
+
+class DeferredDisplayList;
+class DisplayListOp;
+class DisplayListRenderer;
+class OpenGLRenderer;
+class Rect;
+class Layer;
+class SkiaColorFilter;
+class SkiaShader;
+
+/**
+ * Refcounted structure that holds data used in display list stream
+ */
+class DisplayListData: public LightRefBase<DisplayListData> {
+public:
+    LinearAllocator allocator;
+    Vector<DisplayListOp*> displayListOps;
+};
+
+/**
+ * Replays recorded drawing commands.
+ */
+class DisplayList {
+public:
+    DisplayList(const DisplayListRenderer& recorder);
+    ANDROID_API ~DisplayList();
+
+    // See flags defined in DisplayList.java
+    enum ReplayFlag {
+        kReplayFlag_ClipChildren = 0x1
+    };
+
+    void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
+    void outputViewProperties(uint32_t level);
+
+    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);
+
+    status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0,
+            DeferredDisplayList* deferredList = NULL);
+
+    void output(uint32_t level = 0);
+
+    ANDROID_API void reset();
+
+    void setRenderable(bool renderable) {
+        mIsRenderable = renderable;
+    }
+
+    bool isRenderable() const {
+        return mIsRenderable;
+    }
+
+    void setName(const char* name) {
+        if (name) {
+            mName.setTo(name);
+        }
+    }
+
+    const char* getName() const {
+        return mName.string();
+    }
+
+    void setClipChildren(bool clipChildren) {
+        mClipChildren = clipChildren;
+    }
+
+    void setStaticMatrix(SkMatrix* matrix) {
+        delete mStaticMatrix;
+        mStaticMatrix = new SkMatrix(*matrix);
+    }
+
+    // Can return NULL
+    SkMatrix* getStaticMatrix() {
+        return mStaticMatrix;
+    }
+
+    void setAnimationMatrix(SkMatrix* matrix) {
+        delete mAnimationMatrix;
+        if (matrix) {
+            mAnimationMatrix = new SkMatrix(*matrix);
+        } else {
+            mAnimationMatrix = NULL;
+        }
+    }
+
+    void setAlpha(float alpha) {
+        alpha = fminf(1.0f, fmaxf(0.0f, alpha));
+        if (alpha != mAlpha) {
+            mAlpha = alpha;
+            mMultipliedAlpha = (int) (255 * alpha);
+        }
+    }
+
+    float getAlpha() const {
+        return mAlpha;
+    }
+
+    void setHasOverlappingRendering(bool hasOverlappingRendering) {
+        mHasOverlappingRendering = hasOverlappingRendering;
+    }
+
+    bool hasOverlappingRendering() const {
+        return mHasOverlappingRendering;
+    }
+
+    void setTranslationX(float translationX) {
+        if (translationX != mTranslationX) {
+            mTranslationX = translationX;
+            mMatrixDirty = true;
+            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
+                mMatrixFlags &= ~TRANSLATION;
+            } else {
+                mMatrixFlags |= TRANSLATION;
+            }
+        }
+    }
+
+    float getTranslationX() const {
+        return mTranslationX;
+    }
+
+    void setTranslationY(float translationY) {
+        if (translationY != mTranslationY) {
+            mTranslationY = translationY;
+            mMatrixDirty = true;
+            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
+                mMatrixFlags &= ~TRANSLATION;
+            } else {
+                mMatrixFlags |= TRANSLATION;
+            }
+        }
+    }
+
+    float getTranslationY() const {
+        return mTranslationY;
+    }
+
+    void setRotation(float rotation) {
+        if (rotation != mRotation) {
+            mRotation = rotation;
+            mMatrixDirty = true;
+            if (mRotation == 0.0f) {
+                mMatrixFlags &= ~ROTATION;
+            } else {
+                mMatrixFlags |= ROTATION;
+            }
+        }
+    }
+
+    float getRotation() const {
+        return mRotation;
+    }
+
+    void setRotationX(float rotationX) {
+        if (rotationX != mRotationX) {
+            mRotationX = rotationX;
+            mMatrixDirty = true;
+            if (mRotationX == 0.0f && mRotationY == 0.0f) {
+                mMatrixFlags &= ~ROTATION_3D;
+            } else {
+                mMatrixFlags |= ROTATION_3D;
+            }
+        }
+    }
+
+    float getRotationX() const {
+        return mRotationX;
+    }
+
+    void setRotationY(float rotationY) {
+        if (rotationY != mRotationY) {
+            mRotationY = rotationY;
+            mMatrixDirty = true;
+            if (mRotationX == 0.0f && mRotationY == 0.0f) {
+                mMatrixFlags &= ~ROTATION_3D;
+            } else {
+                mMatrixFlags |= ROTATION_3D;
+            }
+        }
+    }
+
+    float getRotationY() const {
+        return mRotationY;
+    }
+
+    void setScaleX(float scaleX) {
+        if (scaleX != mScaleX) {
+            mScaleX = scaleX;
+            mMatrixDirty = true;
+            if (mScaleX == 1.0f && mScaleY == 1.0f) {
+                mMatrixFlags &= ~SCALE;
+            } else {
+                mMatrixFlags |= SCALE;
+            }
+        }
+    }
+
+    float getScaleX() const {
+        return mScaleX;
+    }
+
+    void setScaleY(float scaleY) {
+        if (scaleY != mScaleY) {
+            mScaleY = scaleY;
+            mMatrixDirty = true;
+            if (mScaleX == 1.0f && mScaleY == 1.0f) {
+                mMatrixFlags &= ~SCALE;
+            } else {
+                mMatrixFlags |= SCALE;
+            }
+        }
+    }
+
+    float getScaleY() const {
+        return mScaleY;
+    }
+
+    void setPivotX(float pivotX) {
+        mPivotX = pivotX;
+        mMatrixDirty = true;
+        if (mPivotX == 0.0f && mPivotY == 0.0f) {
+            mMatrixFlags &= ~PIVOT;
+        } else {
+            mMatrixFlags |= PIVOT;
+        }
+        mPivotExplicitlySet = true;
+    }
+
+    ANDROID_API float getPivotX();
+
+    void setPivotY(float pivotY) {
+        mPivotY = pivotY;
+        mMatrixDirty = true;
+        if (mPivotX == 0.0f && mPivotY == 0.0f) {
+            mMatrixFlags &= ~PIVOT;
+        } else {
+            mMatrixFlags |= PIVOT;
+        }
+        mPivotExplicitlySet = true;
+    }
+
+    ANDROID_API float getPivotY();
+
+    void setCameraDistance(float distance) {
+        if (distance != mCameraDistance) {
+            mCameraDistance = distance;
+            mMatrixDirty = true;
+            if (!mTransformCamera) {
+                mTransformCamera = new Sk3DView();
+                mTransformMatrix3D = new SkMatrix();
+            }
+            mTransformCamera->setCameraLocation(0, 0, distance);
+        }
+    }
+
+    float getCameraDistance() const {
+        return mCameraDistance;
+    }
+
+    void setLeft(int left) {
+        if (left != mLeft) {
+            mLeft = left;
+            mWidth = mRight - mLeft;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    float getLeft() const {
+        return mLeft;
+    }
+
+    void setTop(int top) {
+        if (top != mTop) {
+            mTop = top;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    float getTop() const {
+        return mTop;
+    }
+
+    void setRight(int right) {
+        if (right != mRight) {
+            mRight = right;
+            mWidth = mRight - mLeft;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    float getRight() const {
+        return mRight;
+    }
+
+    void setBottom(int bottom) {
+        if (bottom != mBottom) {
+            mBottom = bottom;
+            mHeight = mBottom - mTop;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    float getBottom() const {
+        return mBottom;
+    }
+
+    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(float offset) {
+        if (offset != 0) {
+            mLeft += offset;
+            mRight += offset;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void offsetTopBottom(float offset) {
+        if (offset != 0) {
+            mTop += offset;
+            mBottom += offset;
+            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+                mMatrixDirty = true;
+            }
+        }
+    }
+
+    void setCaching(bool caching) {
+        mCaching = caching;
+    }
+
+    int getWidth() {
+        return mWidth;
+    }
+
+    int getHeight() {
+        return mHeight;
+    }
+
+private:
+    void init();
+
+    void clearResources();
+
+    void updateMatrix();
+
+    class TextContainer {
+    public:
+        size_t length() const {
+            return mByteLength;
+        }
+
+        const char* text() const {
+            return (const char*) mText;
+        }
+
+        size_t mByteLength;
+        const char* mText;
+    };
+
+    Vector<SkBitmap*> mBitmapResources;
+    Vector<SkBitmap*> mOwnedBitmapResources;
+    Vector<SkiaColorFilter*> mFilterResources;
+
+    Vector<SkPaint*> mPaints;
+    Vector<SkPath*> mPaths;
+    SortedVector<SkPath*> mSourcePaths;
+    Vector<SkRegion*> mRegions;
+    Vector<SkMatrix*> mMatrices;
+    Vector<SkiaShader*> mShaders;
+    Vector<Layer*> mLayers;
+
+    sp<DisplayListData> mDisplayListData;
+
+    size_t mSize;
+
+    bool mIsRenderable;
+    uint32_t mFunctorCount;
+
+    String8 mName;
+
+    // View properties
+    bool mClipChildren;
+    float mAlpha;
+    int mMultipliedAlpha;
+    bool mHasOverlappingRendering;
+    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;
+    SkMatrix* mStaticMatrix;
+    SkMatrix* mAnimationMatrix;
+    bool mCaching;
+}; // class DisplayList
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_OPENGL_RENDERER_H
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 6425b43..1bae0ff 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -19,7 +19,10 @@
 
 #include <SkXfermode.h>
 
+#include <private/hwui/DrawGlInfo.h>
+
 #include "OpenGLRenderer.h"
+#include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
 #include "utils/LinearAllocator.h"
 
@@ -41,7 +44,6 @@
 #define OP_LOGS(s) OP_LOG("%s", s)
 #define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
 
-
 namespace android {
 namespace uirenderer {
 
@@ -72,10 +74,11 @@
         kOpLogFlag_JSON = 0x2 // TODO: add?
     };
 
-    //TODO: for draw batching, DrawOps should override a virtual sub-method, with
-    // DrawOps::apply deferring operations to a different list if possible
+    // If a DeferredDisplayList is supplied, DrawOps will be stored until the list is flushed
+    // NOTE: complex clips and layers prevent deferral
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha) = 0;
+            uint32_t level, bool caching, int multipliedAlpha,
+            DeferredDisplayList* deferredList) = 0;
 
     virtual void output(int level, uint32_t flags = 0) = 0;
 
@@ -90,13 +93,28 @@
 
     virtual ~StateOp() {}
 
+    /**
+     * State operations are applied directly to the renderer, but can cause the deferred drawing op
+     * list to flush
+     */
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha) {
+            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
+        status_t status = DrawGlInfo::kStatusDone;
+        if (deferredList && requiresDrawOpFlush()) {
+            // will be setting renderer state that affects ops in deferredList, so flush list first
+            status |= deferredList->flush(renderer, dirty, flags, level);
+        }
         applyState(renderer, saveCount);
-        return DrawGlInfo::kStatusDone;
+        return status;
     }
 
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
+
+    /**
+     * Returns true if it affects renderer drawing state in such a way to break deferral
+     * see OpenGLRenderer::disallowDeferral()
+     */
+    virtual bool requiresDrawOpFlush() { return false; }
 };
 
 class DrawOp : public DisplayListOp {
@@ -104,13 +122,31 @@
     DrawOp(SkPaint* paint)
             : mPaint(paint), mQuickRejected(false) {}
 
+    /** Draw operations are stored in the deferredList with information necessary for playback */
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha) {
+            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
         if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
             return DrawGlInfo::kStatusDone;
         }
 
-        return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
+        if (!deferredList || renderer.disallowDeferral()) {
+            // dispatch draw immediately, since the renderer's state is too complex for deferral
+            return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
+        }
+
+        if (!caching) multipliedAlpha = -1;
+        state.mMultipliedAlpha = multipliedAlpha;
+        if (!getLocalBounds(state.mBounds)) {
+            // empty bounds signify bounds can't be calculated
+            state.mBounds.setEmpty();
+        }
+
+        if (!renderer.storeDisplayState(state)) {
+            // op wasn't quick-rejected, so defer
+            deferredList->add(this, renderer.disallowReorder());
+        }
+
+        return DrawGlInfo::kStatusDone;
     }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -123,6 +159,18 @@
     void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
     bool getQuickRejected() { return mQuickRejected; }
 
+    /** Batching disabled by default, turned on for individual ops */
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_None;
+    }
+
+    float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
+
+    /**
+     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
+     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
+     */
+    DeferredDisplayState state;
 protected:
     SkPaint* getPaint(OpenGLRenderer& renderer) {
         return renderer.filterPaint(mPaint);
@@ -137,7 +185,20 @@
     DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
             : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
 
-    // default constructor for area, to be overridden in child constructor body
+    // Calculates bounds as smallest rect encompassing all points
+    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
+    // subclass' constructor)
+    DrawBoundedOp(const float* points, int count, SkPaint* paint)
+            : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
+        for (int i = 2; i < count; i += 2) {
+            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
+            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
+            mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
+            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
+        }
+    }
+
+    // default empty constructor for bounds, to be overridden in child constructor body
     DrawBoundedOp(SkPaint* paint)
             : DrawOp(paint) {}
 
@@ -189,6 +250,8 @@
     }
 
     virtual const char* name() { return "RestoreToCount"; }
+    // Note: don't have to return true for requiresDrawOpFlush - even though restore can create a
+    // complex clip, the clip and matrix are overridden by DeferredDisplayList::flush()
 
 private:
     int mCount;
@@ -209,6 +272,7 @@
     }
 
     virtual const char* name() { return "SaveLayer"; }
+    virtual bool requiresDrawOpFlush() { return true; }
 
 private:
     Rect mArea;
@@ -230,6 +294,8 @@
     }
 
     virtual const char* name() { return "SaveLayerAlpha"; }
+    virtual bool requiresDrawOpFlush() { return true; }
+
 private:
     Rect mArea;
     int mAlpha;
@@ -389,6 +455,7 @@
     }
 
     virtual const char* name() { return "ClipPath"; }
+    virtual bool requiresDrawOpFlush() { return true; }
 
 private:
     SkPath* mPath;
@@ -411,6 +478,7 @@
     }
 
     virtual const char* name() { return "ClipRegion"; }
+    virtual bool requiresDrawOpFlush() { return true; }
 
 private:
     SkRegion* mRegion;
@@ -580,6 +648,9 @@
     }
 
     virtual const char* name() { return "DrawBitmap"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Bitmap;
+    }
 
 protected:
     SkBitmap* mBitmap;
@@ -604,6 +675,9 @@
     }
 
     virtual const char* name() { return "DrawBitmap"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Bitmap;
+    }
 
 private:
     SkBitmap* mBitmap;
@@ -630,6 +704,9 @@
     }
 
     virtual const char* name() { return "DrawBitmapRect"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Bitmap;
+    }
 
 private:
     SkBitmap* mBitmap;
@@ -652,13 +729,17 @@
     }
 
     virtual const char* name() { return "DrawBitmapData"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Bitmap;
+    }
 };
 
-class DrawBitmapMeshOp : public DrawOp {
+class DrawBitmapMeshOp : public DrawBoundedOp {
 public:
     DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
             float* vertices, int* colors, SkPaint* paint)
-            : DrawOp(paint), mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
+            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
+            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
             mVertices(vertices), mColors(colors) {}
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -672,6 +753,9 @@
     }
 
     virtual const char* name() { return "DrawBitmapMesh"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Bitmap;
+    }
 
 private:
     SkBitmap* mBitmap;
@@ -706,6 +790,9 @@
     }
 
     virtual const char* name() { return "DrawPatch"; }
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Patch;
+    }
 
 private:
     SkBitmap* mBitmap;
@@ -746,15 +833,21 @@
             : DrawBoundedOp(left, top, right, bottom, paint) {};
 
     bool getLocalBounds(Rect& localBounds) {
+        localBounds.set(mLocalBounds);
         if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
-            float outset = mPaint->getStrokeWidth() * 0.5f;
-            localBounds.set(mLocalBounds.left - outset, mLocalBounds.top - outset,
-                    mLocalBounds.right + outset, mLocalBounds.bottom + outset);
-        } else {
-            localBounds.set(mLocalBounds);
+            localBounds.outset(strokeWidthOutset());
         }
         return true;
     }
+
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        if (mPaint->getPathEffect()) {
+            return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+        }
+        return mPaint->isAntiAlias() ?
+                DeferredDisplayList::kOpBatch_AlphaVertices :
+                DeferredDisplayList::kOpBatch_Vertices;
+    }
 };
 
 class DrawRectOp : public DrawStrokableOp {
@@ -775,10 +868,11 @@
     virtual const char* name() { return "DrawRect"; }
 };
 
-class DrawRectsOp : public DrawOp {
+class DrawRectsOp : public DrawBoundedOp {
 public:
     DrawRectsOp(const float* rects, int count, SkPaint* paint)
-            : DrawOp(paint), mRects(rects), mCount(count) {}
+            : DrawBoundedOp(rects, count, paint),
+            mRects(rects), mCount(count) {}
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
             bool caching, int multipliedAlpha) {
@@ -791,6 +885,10 @@
 
     virtual const char* name() { return "DrawRects"; }
 
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_Vertices;
+    }
+
 private:
     const float* mRects;
     int mCount;
@@ -910,22 +1008,19 @@
 
     virtual const char* name() { return "DrawPath"; }
 
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+    }
 private:
     SkPath* mPath;
 };
 
-class DrawLinesOp : public DrawOp {
+class DrawLinesOp : public DrawBoundedOp {
 public:
     DrawLinesOp(float* points, int count, SkPaint* paint)
-            : DrawOp(paint), mPoints(points), mCount(count) {
-        /* TODO: inherit from DrawBoundedOp and calculate localbounds something like:
-        for (int i = 0; i < count; i += 2) {
-            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
-            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
-            mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]);
-            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]);
-        }
-        */
+            : DrawBoundedOp(points, count, paint),
+            mPoints(points), mCount(count) {
+        mLocalBounds.outset(strokeWidthOutset());
     }
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -939,6 +1034,12 @@
 
     virtual const char* name() { return "DrawLines"; }
 
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return mPaint->isAntiAlias() ?
+                DeferredDisplayList::kOpBatch_AlphaVertices :
+                DeferredDisplayList::kOpBatch_Vertices;
+    }
+
 protected:
     float* mPoints;
     int mCount;
@@ -969,6 +1070,12 @@
     virtual void output(int level, uint32_t flags) {
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
+
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return mPaint->getColor() == 0xff000000 ?
+                DeferredDisplayList::kOpBatch_Text :
+                DeferredDisplayList::kOpBatch_ColorText;
+    }
 protected:
     const char* mText;
     int mBytesCount;
@@ -1040,6 +1147,12 @@
 
     virtual const char* name() { return "DrawText"; }
 
+    virtual DeferredDisplayList::OpBatchId getBatchId() {
+        return mPaint->getColor() == 0xff000000 ?
+                DeferredDisplayList::kOpBatch_Text :
+                DeferredDisplayList::kOpBatch_ColorText;
+    }
+
 private:
     const char* mText;
     int mBytesCount;
@@ -1077,15 +1190,24 @@
     Functor* mFunctor;
 };
 
-class DrawDisplayListOp : public DrawOp {
+class DrawDisplayListOp : public DrawBoundedOp {
 public:
     DrawDisplayListOp(DisplayList* displayList, int flags)
-            : DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
-        return renderer.drawDisplayList(mDisplayList, dirty, mFlags, level + 1);
+            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
+            mDisplayList(displayList), mFlags(flags) {}
+
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
+        if (mDisplayList && mDisplayList->isRenderable()) {
+            return mDisplayList->replay(renderer, dirty, mFlags, level + 1, deferredList);
+        }
+        return DrawGlInfo::kStatusDone;
     }
 
+    // NOT USED, since replay is overridden
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+            bool caching, int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
+
     virtual void output(int level, uint32_t flags) {
         OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
         if (mDisplayList && (flags & kOpLogFlag_Recurse)) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 17ed8ac..710f12f 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -20,6 +20,8 @@
 
 #include <private/hwui/DrawGlInfo.h>
 
+#include "DisplayList.h"
+#include "DeferredDisplayList.h"
 #include "DisplayListLogBuffer.h"
 #include "DisplayListOp.h"
 #include "DisplayListRenderer.h"
@@ -28,425 +30,6 @@
 namespace android {
 namespace uirenderer {
 
-///////////////////////////////////////////////////////////////////////////////
-// Display list
-///////////////////////////////////////////////////////////////////////////////
-
-void DisplayList::outputLogBuffer(int fd) {
-    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
-    if (logBuffer.isEmpty()) {
-        return;
-    }
-
-    FILE *file = fdopen(fd, "a");
-
-    fprintf(file, "\nRecent DisplayList operations\n");
-    logBuffer.outputCommands(file);
-
-    String8 cachesLog;
-    Caches::getInstance().dumpMemoryUsage(cachesLog);
-    fprintf(file, "\nCaches:\n%s", cachesLog.string());
-    fprintf(file, "\n");
-
-    fflush(file);
-}
-
-DisplayList::DisplayList(const DisplayListRenderer& recorder) :
-    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
-    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
-
-    initFromDisplayListRenderer(recorder);
-}
-
-DisplayList::~DisplayList() {
-    clearResources();
-}
-
-void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
-    if (displayList) {
-        DISPLAY_LIST_LOGD("Deferring display list destruction");
-        Caches::getInstance().deleteDisplayListDeferred(displayList);
-    }
-}
-
-void DisplayList::clearResources() {
-    mDisplayListData = NULL;
-    delete mTransformMatrix;
-    delete mTransformCamera;
-    delete mTransformMatrix3D;
-    delete mStaticMatrix;
-    delete mAnimationMatrix;
-
-    mTransformMatrix = NULL;
-    mTransformCamera = NULL;
-    mTransformMatrix3D = NULL;
-    mStaticMatrix = NULL;
-    mAnimationMatrix = NULL;
-
-    Caches& caches = Caches::getInstance();
-    caches.unregisterFunctors(mFunctorCount);
-    caches.resourceCache.lock();
-
-    for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
-        SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcountLocked(bitmap);
-        caches.resourceCache.destructorLocked(bitmap);
-    }
-
-    for (size_t i = 0; i < mFilterResources.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mShaders.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
-        caches.resourceCache.destructorLocked(mShaders.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mSourcePaths.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mLayers.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
-    }
-
-    caches.resourceCache.unlock();
-
-    for (size_t i = 0; i < mPaints.size(); i++) {
-        delete mPaints.itemAt(i);
-    }
-
-    for (size_t i = 0; i < mRegions.size(); i++) {
-        delete mRegions.itemAt(i);
-    }
-
-    for (size_t i = 0; i < mPaths.size(); i++) {
-        SkPath* path = mPaths.itemAt(i);
-        caches.pathCache.remove(path);
-        delete path;
-    }
-
-    for (size_t i = 0; i < mMatrices.size(); i++) {
-        delete mMatrices.itemAt(i);
-    }
-
-    mBitmapResources.clear();
-    mOwnedBitmapResources.clear();
-    mFilterResources.clear();
-    mShaders.clear();
-    mSourcePaths.clear();
-    mPaints.clear();
-    mRegions.clear();
-    mPaths.clear();
-    mMatrices.clear();
-    mLayers.clear();
-}
-
-void DisplayList::reset() {
-    clearResources();
-    init();
-}
-
-void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
-    if (reusing) {
-        // re-using display list - clear out previous allocations
-        clearResources();
-    }
-
-    init();
-
-    mDisplayListData = recorder.getDisplayListData();
-    mSize = mDisplayListData->allocator.usedSize();
-
-    if (mSize == 0) {
-        return;
-    }
-
-    mFunctorCount = recorder.getFunctorCount();
-
-    Caches& caches = Caches::getInstance();
-    caches.registerFunctors(mFunctorCount);
-    caches.resourceCache.lock();
-
-    const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
-    for (size_t i = 0; i < bitmapResources.size(); i++) {
-        SkBitmap* resource = bitmapResources.itemAt(i);
-        mBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
-    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
-        SkBitmap* resource = ownedBitmapResources.itemAt(i);
-        mOwnedBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
-    for (size_t i = 0; i < filterResources.size(); i++) {
-        SkiaColorFilter* resource = filterResources.itemAt(i);
-        mFilterResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<SkiaShader*>& shaders = recorder.getShaders();
-    for (size_t i = 0; i < shaders.size(); i++) {
-        SkiaShader* resource = shaders.itemAt(i);
-        mShaders.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
-    for (size_t i = 0; i < sourcePaths.size(); i++) {
-        mSourcePaths.add(sourcePaths.itemAt(i));
-        caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
-    }
-
-    const Vector<Layer*>& layers = recorder.getLayers();
-    for (size_t i = 0; i < layers.size(); i++) {
-        mLayers.add(layers.itemAt(i));
-        caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
-    }
-
-    caches.resourceCache.unlock();
-
-    mPaints.appendVector(recorder.getPaints());
-    mRegions.appendVector(recorder.getRegions());
-    mPaths.appendVector(recorder.getPaths());
-    mMatrices.appendVector(recorder.getMatrices());
-}
-
-void DisplayList::init() {
-    mSize = 0;
-    mIsRenderable = true;
-    mFunctorCount = 0;
-    mLeft = 0;
-    mTop = 0;
-    mRight = 0;
-    mBottom = 0;
-    mClipChildren = true;
-    mAlpha = 1;
-    mMultipliedAlpha = 255;
-    mHasOverlappingRendering = true;
-    mTranslationX = 0;
-    mTranslationY = 0;
-    mRotation = 0;
-    mRotationX = 0;
-    mRotationY= 0;
-    mScaleX = 1;
-    mScaleY = 1;
-    mPivotX = 0;
-    mPivotY = 0;
-    mCameraDistance = 0;
-    mMatrixDirty = false;
-    mMatrixFlags = 0;
-    mPrevWidth = -1;
-    mPrevHeight = -1;
-    mWidth = 0;
-    mHeight = 0;
-    mPivotExplicitlySet = false;
-    mCaching = false;
-}
-
-size_t DisplayList::getSize() {
-    return mSize;
-}
-
-/**
- * This function is a simplified version of replay(), where we simply retrieve and log the
- * display list. This function should remain in sync with the replay() function.
- */
-void DisplayList::output(uint32_t level) {
-    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
-            mName.string(), isRenderable());
-
-    ALOGD("%*s%s %d", level * 2, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    outputViewProperties(level);
-    int flags = DisplayListOp::kOpLogFlag_Recurse;
-    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
-        mDisplayListData->displayListOps[i]->output(level, flags);
-    }
-    ALOGD("%*sDone (%p, %s)", level * 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(uint32_t level) {
-    updateMatrix();
-    if (mLeft != 0 || mTop != 0) {
-        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
-    }
-    if (mStaticMatrix) {
-        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
-                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
-    }
-    if (mAnimationMatrix) {
-        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
-                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
-    }
-    if (mMatrixFlags != 0) {
-        if (mMatrixFlags == TRANSLATION) {
-            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
-        } else {
-            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
-                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
-        }
-    }
-    if (mAlpha < 1 && !mCaching) {
-        if (!mHasOverlappingRendering) {
-            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
-        } else {
-            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (mClipChildren) {
-                flags |= SkCanvas::kClipToLayer_SaveFlag;
-            }
-            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
-                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
-                    mMultipliedAlpha, flags);
-        }
-    }
-    if (mClipChildren && !mCaching) {
-        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
-                (float) mRight - mLeft, (float) mBottom - mTop);
-    }
-}
-
-void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
-#if DEBUG_DISPLAYLIST
-    outputViewProperties(level);
-#endif
-    updateMatrix();
-    if (mLeft != 0 || mTop != 0) {
-        renderer.translate(mLeft, mTop);
-    }
-    if (mStaticMatrix) {
-        renderer.concatMatrix(mStaticMatrix);
-    } else if (mAnimationMatrix) {
-        renderer.concatMatrix(mAnimationMatrix);
-    }
-    if (mMatrixFlags != 0) {
-        if (mMatrixFlags == TRANSLATION) {
-            renderer.translate(mTranslationX, mTranslationY);
-        } else {
-            renderer.concatMatrix(mTransformMatrix);
-        }
-    }
-    if (mAlpha < 1 && !mCaching) {
-        if (!mHasOverlappingRendering) {
-            renderer.setAlpha(mAlpha);
-        } else {
-            // 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;
-            }
-            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
-                    mMultipliedAlpha, flags);
-        }
-    }
-    if (mClipChildren && !mCaching) {
-        renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
-                SkRegion::kIntersect_Op);
-    }
-}
-
-status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
-    status_t drawGlStatus = DrawGlInfo::kStatusDone;
-
-#if DEBUG_DISPLAY_LIST
-    Rect* clipRect = renderer.getClipRect();
-    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
-            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
-            clipRect->right, clipRect->bottom);
-#endif
-
-    renderer.startMark(mName.string());
-
-    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
-    setViewProperties(renderer, level);
-
-    if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
-        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
-        renderer.restoreToCount(restoreTo);
-        renderer.endMark();
-        return drawGlStatus;
-    }
-
-    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
-    int saveCount = renderer.getSaveCount() - 1;
-    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
-        DisplayListOp *op = mDisplayListData->displayListOps[i];
-#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
-        Caches::getInstance().eventMark(strlen(op->name()), op->name());
-#endif
-
-        drawGlStatus |= op->replay(renderer, dirty, flags,
-                saveCount, level, mCaching, mMultipliedAlpha);
-        logBuffer.writeCommand(level, op->name());
-    }
-
-    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
-    renderer.restoreToCount(restoreTo);
-    renderer.endMark();
-
-    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
-            drawGlStatus);
-    return drawGlStatus;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Base structure
-///////////////////////////////////////////////////////////////////////////////
-
 DisplayListRenderer::DisplayListRenderer():
         mCaches(Caches::getInstance()), mDisplayListData(new DisplayListData),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false),
@@ -657,7 +240,7 @@
 }
 
 status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
-        Rect& dirty, int32_t flags, uint32_t level) {
+        Rect& dirty, int32_t flags) {
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index f3bd188..bff3b97 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -17,22 +17,14 @@
 #ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 #define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 
-#include <SkChunkAlloc.h>
-#include <SkReader32.h>
-#include <SkWriter32.h>
 #include <SkMatrix.h>
-#include <SkCamera.h>
 #include <SkPaint.h>
 #include <SkPath.h>
-#include <SkRefCnt.h>
-#include <SkTDArray.h>
-#include <SkTSearch.h>
-
 #include <cutils/compiler.h>
 
+#include "DisplayList.h"
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
-#include "utils/LinearAllocator.h"
 
 namespace android {
 namespace uirenderer {
@@ -51,390 +43,17 @@
     #define DISPLAY_LIST_LOGD(...)
 #endif
 
-#define TRANSLATION 0x0001
-#define ROTATION    0x0002
-#define ROTATION_3D 0x0004
-#define SCALE       0x0008
-#define PIVOT       0x0010
-
 ///////////////////////////////////////////////////////////////////////////////
 // Display list
 ///////////////////////////////////////////////////////////////////////////////
 
+class DeferredDisplayList;
 class DisplayListRenderer;
 class DisplayListOp;
 class DrawOp;
 class StateOp;
 
 /**
- * Refcounted structure that holds data used in display list stream
- */
-class DisplayListData: public LightRefBase<DisplayListData> {
-public:
-    LinearAllocator allocator;
-    Vector<DisplayListOp*> displayListOps;
-};
-
-/**
- * Replays recorded drawing commands.
- */
-class DisplayList {
-public:
-    DisplayList(const DisplayListRenderer& recorder);
-    ANDROID_API ~DisplayList();
-
-    // See flags defined in DisplayList.java
-    enum ReplayFlag {
-        kReplayFlag_ClipChildren = 0x1
-    };
-
-    void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
-    void outputViewProperties(uint32_t level);
-
-    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);
-
-    status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
-
-    void output(uint32_t level = 0);
-
-    ANDROID_API void reset();
-
-    void setRenderable(bool renderable) {
-        mIsRenderable = renderable;
-    }
-
-    bool isRenderable() const {
-        return mIsRenderable;
-    }
-
-    void setName(const char* name) {
-        if (name) {
-            mName.setTo(name);
-        }
-    }
-
-    void setClipChildren(bool clipChildren) {
-        mClipChildren = clipChildren;
-    }
-
-    void setStaticMatrix(SkMatrix* matrix) {
-        delete mStaticMatrix;
-        mStaticMatrix = new SkMatrix(*matrix);
-    }
-
-    void setAnimationMatrix(SkMatrix* matrix) {
-        delete mAnimationMatrix;
-        if (matrix) {
-            mAnimationMatrix = new SkMatrix(*matrix);
-        } else {
-            mAnimationMatrix = NULL;
-        }
-    }
-
-    void setAlpha(float alpha) {
-        alpha = fminf(1.0f, fmaxf(0.0f, alpha));
-        if (alpha != mAlpha) {
-            mAlpha = alpha;
-            mMultipliedAlpha = (int) (255 * alpha);
-        }
-    }
-
-    void setHasOverlappingRendering(bool hasOverlappingRendering) {
-        mHasOverlappingRendering = hasOverlappingRendering;
-    }
-
-    void setTranslationX(float translationX) {
-        if (translationX != mTranslationX) {
-            mTranslationX = translationX;
-            mMatrixDirty = true;
-            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
-                mMatrixFlags &= ~TRANSLATION;
-            } else {
-                mMatrixFlags |= TRANSLATION;
-            }
-        }
-    }
-
-    void setTranslationY(float translationY) {
-        if (translationY != mTranslationY) {
-            mTranslationY = translationY;
-            mMatrixDirty = true;
-            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
-                mMatrixFlags &= ~TRANSLATION;
-            } else {
-                mMatrixFlags |= TRANSLATION;
-            }
-        }
-    }
-
-    void setRotation(float rotation) {
-        if (rotation != mRotation) {
-            mRotation = rotation;
-            mMatrixDirty = true;
-            if (mRotation == 0.0f) {
-                mMatrixFlags &= ~ROTATION;
-            } else {
-                mMatrixFlags |= ROTATION;
-            }
-        }
-    }
-
-    void setRotationX(float rotationX) {
-        if (rotationX != mRotationX) {
-            mRotationX = rotationX;
-            mMatrixDirty = true;
-            if (mRotationX == 0.0f && mRotationY == 0.0f) {
-                mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mMatrixFlags |= ROTATION_3D;
-            }
-        }
-    }
-
-    void setRotationY(float rotationY) {
-        if (rotationY != mRotationY) {
-            mRotationY = rotationY;
-            mMatrixDirty = true;
-            if (mRotationX == 0.0f && mRotationY == 0.0f) {
-                mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mMatrixFlags |= ROTATION_3D;
-            }
-        }
-    }
-
-    void setScaleX(float scaleX) {
-        if (scaleX != mScaleX) {
-            mScaleX = scaleX;
-            mMatrixDirty = true;
-            if (mScaleX == 1.0f && mScaleY == 1.0f) {
-                mMatrixFlags &= ~SCALE;
-            } else {
-                mMatrixFlags |= SCALE;
-            }
-        }
-    }
-
-    void setScaleY(float scaleY) {
-        if (scaleY != mScaleY) {
-            mScaleY = scaleY;
-            mMatrixDirty = true;
-            if (mScaleX == 1.0f && mScaleY == 1.0f) {
-                mMatrixFlags &= ~SCALE;
-            } else {
-                mMatrixFlags |= SCALE;
-            }
-        }
-    }
-
-    void setPivotX(float pivotX) {
-        mPivotX = pivotX;
-        mMatrixDirty = true;
-        if (mPivotX == 0.0f && mPivotY == 0.0f) {
-            mMatrixFlags &= ~PIVOT;
-        } else {
-            mMatrixFlags |= PIVOT;
-        }
-        mPivotExplicitlySet = true;
-    }
-
-    void setPivotY(float pivotY) {
-        mPivotY = pivotY;
-        mMatrixDirty = true;
-        if (mPivotX == 0.0f && mPivotY == 0.0f) {
-            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;
-    }
-
-    int getWidth() {
-        return mWidth;
-    }
-
-    int getHeight() {
-        return mHeight;
-    }
-
-private:
-    void init();
-
-    void clearResources();
-
-    void updateMatrix();
-
-    class TextContainer {
-    public:
-        size_t length() const {
-            return mByteLength;
-        }
-
-        const char* text() const {
-            return (const char*) mText;
-        }
-
-        size_t mByteLength;
-        const char* mText;
-    };
-
-    Vector<SkBitmap*> mBitmapResources;
-    Vector<SkBitmap*> mOwnedBitmapResources;
-    Vector<SkiaColorFilter*> mFilterResources;
-
-    Vector<SkPaint*> mPaints;
-    Vector<SkPath*> mPaths;
-    SortedVector<SkPath*> mSourcePaths;
-    Vector<SkRegion*> mRegions;
-    Vector<SkMatrix*> mMatrices;
-    Vector<SkiaShader*> mShaders;
-    Vector<Layer*> mLayers;
-
-    sp<DisplayListData> mDisplayListData;
-
-    size_t mSize;
-
-    bool mIsRenderable;
-    uint32_t mFunctorCount;
-
-    String8 mName;
-
-    // View properties
-    bool mClipChildren;
-    float mAlpha;
-    int mMultipliedAlpha;
-    bool mHasOverlappingRendering;
-    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;
-    SkMatrix* mStaticMatrix;
-    SkMatrix* mAnimationMatrix;
-    bool mCaching;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Renderer
-///////////////////////////////////////////////////////////////////////////////
-
-/**
  * Records drawing commands in a display list for latter playback.
  */
 class DisplayListRenderer: public OpenGLRenderer {
@@ -476,8 +95,7 @@
     virtual bool clipPath(SkPath* path, SkRegion::Op op);
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
 
-    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
-            uint32_t level = 0);
+    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
     virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index d8297da..5d5e6a5 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -16,13 +16,15 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include <cutils/properties.h>
 
 #include <utils/Log.h>
 
+#include "RenderScript.h"
+
+#include "utils/Timing.h"
 #include "Caches.h"
 #include "Debug.h"
 #include "FontRenderer.h"
@@ -31,6 +33,9 @@
 namespace android {
 namespace uirenderer {
 
+// blur inputs smaller than this constant will bypass renderscript
+#define RS_MIN_INPUT_CUTOFF 10000
+
 ///////////////////////////////////////////////////////////////////////////////
 // FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
@@ -544,18 +549,22 @@
 
     uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
     uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
-    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
 
-    for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
-        dataBuffer[i] = 0;
+    // Align buffers for renderscript usage
+    if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
+        paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
     }
 
+    int size = paddedWidth * paddedHeight;
+    uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
+    memset(dataBuffer, 0, size);
+
     int penX = radius - bounds.left;
     int penY = radius - bounds.bottom;
 
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
             Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
-    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
+    blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
 
     DropShadow image;
     image.width = paddedWidth;
@@ -752,18 +761,44 @@
     }
 }
 
+void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
+    if (width * height * radius < RS_MIN_INPUT_CUTOFF) {
+        float *gaussian = new float[2 * radius + 1];
+        computeGaussianWeights(gaussian, radius);
 
-void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
-    float *gaussian = new float[2 * radius + 1];
-    computeGaussianWeights(gaussian, radius);
+        uint8_t* scratch = new uint8_t[width * height];
 
-    uint8_t* scratch = new uint8_t[width * height];
+        horizontalBlur(gaussian, radius, *image, scratch, width, height);
+        verticalBlur(gaussian, radius, scratch, *image, width, height);
 
-    horizontalBlur(gaussian, radius, image, scratch, width, height);
-    verticalBlur(gaussian, radius, scratch, image, width, height);
+        delete[] gaussian;
+        delete[] scratch;
+    }
 
-    delete[] gaussian;
-    delete[] scratch;
+    uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
+
+    if (mRs.get() == 0) {
+        mRs = new RSC::RS();
+        if (!mRs->init(true, true)) {
+            ALOGE("blur RS failed to init");
+        }
+
+        mRsElement = RSC::Element::A_8(mRs);
+        mRsScript = new RSC::ScriptIntrinsicBlur(mRs, mRsElement);
+    }
+
+    sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
+    sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
+    sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
+
+    mRsScript->setRadius(radius);
+    mRsScript->blur(ain, aout);
+
+    // replace the original image's pointer, avoiding a copy back to the original buffer
+    delete *image;
+    *image = outImage;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 3964bca..d0c44ef 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -31,6 +31,12 @@
 #include "Matrix.h"
 #include "Properties.h"
 
+namespace RSC {
+    class Element;
+    class RS;
+    class ScriptIntrinsicBlur;
+}
+
 namespace android {
 namespace uirenderer {
 
@@ -178,13 +184,19 @@
     Vector<uint32_t> mDrawCounts;
     Vector<CacheTexture*> mDrawCacheTextures;
 
-    /** We should consider multi-threading this code or using Renderscript **/
+    // RS constructs
+    sp<RSC::RS> mRs;
+    sp<const RSC::Element> mRsElement;
+    sp<RSC::ScriptIntrinsicBlur> mRsScript;
+
     static void computeGaussianWeights(float* weights, int32_t radius);
     static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
             int32_t width, int32_t height);
     static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
             int32_t width, int32_t height);
-    static void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius);
+
+    // the input image handle may have its pointer replaced (to avoid copies)
+    void blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius);
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ccf1da5..664b2f8 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -23,7 +23,6 @@
 
 #include <ui/Region.h>
 
-#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include "Rect.h"
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 79fae2b..5cec5a8 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -24,7 +24,6 @@
 
 #include <SkMatrix.h>
 
-#include "utils/Compare.h"
 #include "Matrix.h"
 
 namespace android {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2431e54..6b614a7 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -32,6 +32,7 @@
 #include <ui/Rect.h>
 
 #include "OpenGLRenderer.h"
+#include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
 #include "PathTessellator.h"
 #include "Properties.h"
@@ -80,7 +81,7 @@
     { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
 };
 
@@ -101,7 +102,7 @@
     { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
 };
 
@@ -111,16 +112,18 @@
 
 OpenGLRenderer::OpenGLRenderer():
         mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
-    mShader = NULL;
-    mColorFilter = NULL;
-    mHasShadow = false;
-    mHasDrawFilter = false;
+    mDrawModifiers.mShader = NULL;
+    mDrawModifiers.mColorFilter = NULL;
+    mDrawModifiers.mHasShadow = false;
+    mDrawModifiers.mHasDrawFilter = false;
 
     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
 
     mFirstSnapshot = new Snapshot;
 
     mScissorOptimizationDisabled = false;
+    mDrawDeferDisabled = false;
+    mDrawReorderDisabled = false;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -137,6 +140,20 @@
     } else {
         INIT_LOGD("  Scissor optimization enabled");
     }
+
+    if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
+        mDrawDeferDisabled = !strcasecmp(property, "true");
+        INIT_LOGD("  Draw defer %s", mDrawDeferDisabled ? "disabled" : "enabled");
+    } else {
+        INIT_LOGD("  Draw defer enabled");
+    }
+
+    if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
+        mDrawReorderDisabled = !strcasecmp(property, "true");
+        INIT_LOGD("  Draw reorder %s", mDrawReorderDisabled ? "disabled" : "enabled");
+    } else {
+        INIT_LOGD("  Draw reorder enabled");
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -263,7 +280,7 @@
 void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
     if (!mSuppressTiling) {
         mCaches.startTiling(clip.left, windowHeight - clip.bottom,
-                    clip.right - clip.left, clip.bottom - clip.top, opaque);
+                clip.right - clip.left, clip.bottom - clip.top, opaque);
     }
 }
 
@@ -317,7 +334,7 @@
     mCaches.unbindMeshBuffer();
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
-    mCaches.disbaleTexCoordsVertexArray();
+    mCaches.disableTexCoordsVertexArray();
     debugOverdraw(false, false);
 }
 
@@ -770,7 +787,7 @@
     layer->layer.set(bounds);
     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
             bounds.getWidth() / float(layer->getWidth()), 0.0f);
-    layer->setColorFilter(mColorFilter);
+    layer->setColorFilter(mDrawModifiers.mColorFilter);
     layer->setBlend(true);
     layer->setDirty(false);
 
@@ -1204,6 +1221,42 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// State Deferral
+///////////////////////////////////////////////////////////////////////////////
+
+bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) {
+    const Rect& currentClip = *(mSnapshot->clipRect);
+    const mat4& currentMatrix = *(mSnapshot->transform);
+
+    // state only has bounds initialized in local coordinates
+    if (!state.mBounds.isEmpty()) {
+        currentMatrix.mapRect(state.mBounds);
+        if (!state.mBounds.intersect(currentClip)) {
+            // quick rejected
+            return true;
+        }
+    } else {
+        state.mBounds.set(currentClip);
+    }
+
+    state.mClip.set(currentClip);
+    state.mMatrix.load(currentMatrix);
+    state.mDrawModifiers = mDrawModifiers;
+    return false;
+}
+
+void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
+    mSnapshot->transform->load(state.mMatrix);
+
+    // NOTE: a clip RECT will be saved and restored, but DeferredDisplayState doesn't support
+    // complex clips. In the future, we should add support for deferral of operations clipped by
+    // these. for now, we don't defer with complex clips (see OpenGLRenderer::disallowDeferral())
+    mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
+    dirtyClip();
+    mDrawModifiers = state.mDrawModifiers;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Transforms
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -1452,7 +1505,7 @@
     if (clear) clearLayerRegions();
     // Make sure setScissor & setStencil happen at the beginning of
     // this method
-    if (mDirtyClip) {
+    if (mDirtyClip && mCaches.scissorEnabled) {
         setScissorFromClip();
         setStencilFromClip();
     }
@@ -1469,12 +1522,18 @@
     mDescription.hasAlpha8Texture = isAlpha8;
 }
 
+void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
+    mDescription.hasTexture = true;
+    mDescription.hasColors = true;
+    mDescription.hasAlpha8Texture = isAlpha8;
+}
+
 void OpenGLRenderer::setupDrawWithExternalTexture() {
     mDescription.hasExternalTexture = true;
 }
 
 void OpenGLRenderer::setupDrawNoTexture() {
-    mCaches.disbaleTexCoordsVertexArray();
+    mCaches.disableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawAA() {
@@ -1518,14 +1577,14 @@
 }
 
 void OpenGLRenderer::setupDrawShader() {
-    if (mShader) {
-        mShader->describe(mDescription, mExtensions);
+    if (mDrawModifiers.mShader) {
+        mDrawModifiers.mShader->describe(mDescription, mExtensions);
     }
 }
 
 void OpenGLRenderer::setupDrawColorFilter() {
-    if (mColorFilter) {
-        mColorFilter->describe(mDescription, mExtensions);
+    if (mDrawModifiers.mColorFilter) {
+        mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
     }
 }
 
@@ -1541,16 +1600,19 @@
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
-    chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
-            mDescription, swapSrcDst);
+    bool blend = (mColorSet && mColorA < 1.0f) ||
+            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
+    chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
 void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
-    chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()) ||
-            (mColorFilter && mColorFilter->blend()), mode, mDescription, swapSrcDst);
+    blend |= (mColorSet && mColorA < 1.0f) ||
+            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
+            (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
+    chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
 void OpenGLRenderer::setupDrawProgram() {
@@ -1603,7 +1665,7 @@
 }
 
 void OpenGLRenderer::setupDrawColorUniforms() {
-    if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) {
+    if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
     }
 }
@@ -1615,23 +1677,25 @@
 }
 
 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
-    if (mShader) {
+    if (mDrawModifiers.mShader) {
         if (ignoreTransform) {
             mModelView.loadInverse(*mSnapshot->transform);
         }
-        mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit);
+        mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
+                mModelView, *mSnapshot, &mTextureUnit);
     }
 }
 
 void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
-    if (mShader) {
-        mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit);
+    if (mDrawModifiers.mShader) {
+        mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
+                mIdentity, *mSnapshot, &mTextureUnit);
     }
 }
 
 void OpenGLRenderer::setupDrawColorFilterUniforms() {
-    if (mColorFilter) {
-        mColorFilter->setupProgram(mCaches.currentProgram);
+    if (mDrawModifiers.mColorFilter) {
+        mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
     }
 }
 
@@ -1682,6 +1746,23 @@
     mCaches.unbindIndicesBuffer();
 }
 
+void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) {
+    bool force = mCaches.unbindMeshBuffer();
+    GLsizei stride = sizeof(ColorTextureVertex);
+
+    mCaches.bindPositionVertexPointer(force, vertices, stride);
+    if (mCaches.currentProgram->texCoords >= 0) {
+        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+    }
+    int slot = mCaches.currentProgram->getAttrib("colors");
+    if (slot >= 0) {
+        glEnableVertexAttribArray(slot);
+        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
+    }
+
+    mCaches.unbindIndicesBuffer();
+}
+
 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
     bool force = mCaches.unbindMeshBuffer();
     mCaches.bindPositionVertexPointer(force, vertices);
@@ -1703,21 +1784,24 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList,
-        Rect& dirty, int32_t flags, uint32_t level) {
-
+status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) {
     // 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);
+        if (CC_UNLIKELY(mDrawDeferDisabled)) {
+            return displayList->replay(*this, dirty, flags, 0);
+        }
+
+        DeferredDisplayList deferredList;
+        return displayList->replay(*this, dirty, flags, 0, &deferredList);
     }
 
     return DrawGlInfo::kStatusDone;
 }
 
-void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
     if (displayList) {
-        displayList->output(level);
+        displayList->output(0);
     }
 }
 
@@ -1833,9 +1917,16 @@
 
     const uint32_t count = meshWidth * meshHeight * 6;
 
-    // TODO: Support the colors array
-    TextureVertex mesh[count];
-    TextureVertex* vertex = mesh;
+    ColorTextureVertex mesh[count];
+    ColorTextureVertex* vertex = mesh;
+
+    bool cleanupColors = false;
+    if (!colors) {
+        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
+        colors = new int[colorsCount];
+        memset(colors, 0xff, colorsCount * sizeof(int));
+        cleanupColors = true;
+    }
 
     for (int32_t y = 0; y < meshHeight; y++) {
         for (int32_t x = 0; x < meshWidth; x++) {
@@ -1855,13 +1946,13 @@
             int dx = i + (meshWidth + 1) * 2 + 2;
             int dy = dx + 1;
 
-            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
-            TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1);
-            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
 
-            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
-            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
-            TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
 
             left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
             top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
@@ -1871,12 +1962,16 @@
     }
 
     if (quickReject(left, top, right, bottom)) {
+        if (cleanupColors) delete[] colors;
         return DrawGlInfo::kStatusDone;
     }
 
     mCaches.activeTexture(0);
     Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) {
+        if (cleanupColors) delete[] colors;
+        return DrawGlInfo::kStatusDone;
+    }
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -1886,13 +1981,35 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+    float a = alpha / 255.0f;
+
     if (hasLayer()) {
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     }
 
-    drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
-            mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0],
-            GL_TRIANGLES, count, false, false, 0, false, false);
+    setupDraw();
+    setupDrawWithTextureAndColor();
+    setupDrawColor(a, a, a, a);
+    setupDrawColorFilter();
+    setupDrawBlending(true, mode, false);
+    setupDrawProgram();
+    setupDrawDirtyRegionsDisabled();
+    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false);
+    setupDrawTexture(texture->id);
+    setupDrawPureColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]);
+
+    glDrawArrays(GL_TRIANGLES, 0, count);
+
+    finishDrawTexture();
+
+    int slot = mCaches.currentProgram->getAttrib("colors");
+    if (slot >= 0) {
+        glDisableVertexAttribArray(slot);
+    }
+
+    if (cleanupColors) delete[] colors;
 
     return DrawGlInfo::kStatusDrew;
 }
@@ -1934,7 +2051,7 @@
     // Apply a scale transform on the canvas only when a shader is in use
     // Skia handles the ratio between the dst and src rects as a scale factor
     // when a shader is set
-    bool useScaleTransform = mShader && scaled;
+    bool useScaleTransform = mDrawModifiers.mShader && scaled;
     bool ignoreTransform = false;
 
     if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) {
@@ -2389,15 +2506,15 @@
     //       if shader-based correction is enabled
     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
     const ShadowTexture* shadow = mCaches.dropShadowCache.get(
-            paint, text, bytesCount, count, mShadowRadius, positions);
+            paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
     const AutoTexture autoCleanup(shadow);
 
-    const float sx = x - shadow->left + mShadowDx;
-    const float sy = y - shadow->top + mShadowDy;
+    const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
+    const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
 
-    const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
-    int shadowColor = mShadowColor;
-    if (mShader) {
+    const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
+    int shadowColor = mDrawModifiers.mShadowColor;
+    if (mDrawModifiers.mShader) {
         shadowColor = 0xffffffff;
     }
 
@@ -2445,7 +2562,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (CC_UNLIKELY(mHasShadow)) {
+    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, mode, 0.0f, 0.0f);
     }
@@ -2536,7 +2653,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (CC_UNLIKELY(mHasShadow)) {
+    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
                 oldX, oldY);
     }
@@ -2692,8 +2809,8 @@
     mCaches.activeTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
-        SkiaColorFilter* oldFilter = mColorFilter;
-        mColorFilter = layer->getColorFilter();
+        SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
+        mDrawModifiers.mColorFilter = layer->getColorFilter();
 
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
@@ -2732,7 +2849,7 @@
 #endif
         }
 
-        mColorFilter = oldFilter;
+        mDrawModifiers.mColorFilter = oldFilter;
 
         if (layer->debugDrawUpdate) {
             layer->debugDrawUpdate = false;
@@ -2753,13 +2870,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::resetShader() {
-    mShader = NULL;
+    mDrawModifiers.mShader = NULL;
 }
 
 void OpenGLRenderer::setupShader(SkiaShader* shader) {
-    mShader = shader;
-    if (mShader) {
-        mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
+    mDrawModifiers.mShader = shader;
+    if (mDrawModifiers.mShader) {
+        mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
     }
 }
 
@@ -2768,11 +2885,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::resetColorFilter() {
-    mColorFilter = NULL;
+    mDrawModifiers.mColorFilter = NULL;
 }
 
 void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    mColorFilter = filter;
+    mDrawModifiers.mColorFilter = filter;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2780,15 +2897,15 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::resetShadow() {
-    mHasShadow = false;
+    mDrawModifiers.mHasShadow = false;
 }
 
 void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    mHasShadow = true;
-    mShadowRadius = radius;
-    mShadowDx = dx;
-    mShadowDy = dy;
-    mShadowColor = color;
+    mDrawModifiers.mHasShadow = true;
+    mDrawModifiers.mShadowRadius = radius;
+    mDrawModifiers.mShadowDx = dx;
+    mDrawModifiers.mShadowDy = dy;
+    mDrawModifiers.mShadowColor = color;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2796,22 +2913,23 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::resetPaintFilter() {
-    mHasDrawFilter = false;
+    mDrawModifiers.mHasDrawFilter = false;
 }
 
 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
-    mHasDrawFilter = true;
-    mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
-    mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
+    mDrawModifiers.mHasDrawFilter = true;
+    mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
+    mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
 }
 
 SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
-    if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint;
+    if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) return paint;
 
     uint32_t flags = paint->getFlags();
 
     mFilteredPaint = *paint;
-    mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
+    mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
+            mDrawModifiers.mPaintFilterSetBits);
 
     return &mFilteredPaint;
 }
@@ -2911,7 +3029,7 @@
 
     int color = paint->getColor();
     // If a shader is set, preserve only the alpha
-    if (mShader) {
+    if (mDrawModifiers.mShader) {
         color |= 0x00ffffff;
     }
     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
@@ -2984,7 +3102,7 @@
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
         int color, SkXfermode::Mode mode, bool ignoreTransform) {
     // If a shader is set, preserve only the alpha
-    if (mShader) {
+    if (mDrawModifiers.mShader) {
         color |= 0x00ffffff;
     }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0ad81c1..e12083c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -48,6 +48,34 @@
 namespace android {
 namespace uirenderer {
 
+struct DrawModifiers {
+    SkiaShader* mShader;
+    SkiaColorFilter* mColorFilter;
+
+    // Drop shadow
+    bool mHasShadow;
+    float mShadowRadius;
+    float mShadowDx;
+    float mShadowDy;
+    int mShadowColor;
+
+    // Draw filters
+    bool mHasDrawFilter;
+    int mPaintFilterClearBits;
+    int mPaintFilterSetBits;
+};
+
+struct DeferredDisplayState {
+    Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
+    int mMultipliedAlpha; // -1 if invalid (because caching not set)
+
+    // the below are set and used by the OpenGLRenderer at record and deferred playback
+    Rect mClip;
+    mat4 mMatrix;
+    SkiaShader* mShader;
+    DrawModifiers mDrawModifiers;
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
@@ -182,9 +210,8 @@
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
     virtual Rect* getClipRect();
 
-    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
-            uint32_t level = 0);
-    virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
+    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
+    virtual void outputDisplayList(DisplayList* displayList);
     virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -233,6 +260,23 @@
 
     SkPaint* filterPaint(SkPaint* paint);
 
+    bool disallowDeferral() {
+        // returns true if the OpenGLRenderer's state can be completely represented by
+        // a DeferredDisplayState object
+        return !mSnapshot->clipRegion->isEmpty() ||
+                mSnapshot->alpha < 1.0 ||
+                (mSnapshot->flags & Snapshot::kFlagIsLayer) ||
+                (mSnapshot->flags & Snapshot::kFlagFboTarget); // ensure we're not in a layer
+    }
+
+    bool disallowReorder() { return mDrawReorderDisabled; }
+
+    bool storeDisplayState(DeferredDisplayState& state);
+    void restoreDisplayState(const DeferredDisplayState& state);
+
+    const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
+    void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
+
     ANDROID_API bool isCurrentTransformSimple() {
         return mSnapshot->transform->isSimple();
     }
@@ -777,6 +821,7 @@
      * Various methods to setup OpenGL rendering.
      */
     void setupDrawWithTexture(bool isAlpha8 = false);
+    void setupDrawWithTextureAndColor(bool isAlpha8 = false);
     void setupDrawWithExternalTexture();
     void setupDrawNoTexture();
     void setupDrawAA();
@@ -811,6 +856,7 @@
     void setupDrawTextureTransformUniforms(mat4& transform);
     void setupDrawTextGammaUniforms();
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
+    void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors);
     void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords);
     void setupDrawVertices(GLvoid* vertices);
     void finishDrawTexture();
@@ -866,26 +912,11 @@
     // State used to define the clipping region
     sp<Snapshot> mTilingSnapshot;
 
-    // Shaders
-    SkiaShader* mShader;
-
-    // Color filters
-    SkiaColorFilter* mColorFilter;
-
     // Used to draw textured quads
     TextureVertex mMeshVertices[4];
 
-    // Drop shadow
-    bool mHasShadow;
-    float mShadowRadius;
-    float mShadowDx;
-    float mShadowDy;
-    int mShadowColor;
-
-    // Draw filters
-    bool mHasDrawFilter;
-    int mPaintFilterClearBits;
-    int mPaintFilterSetBits;
+    // shader, filters, and shadow
+    DrawModifiers mDrawModifiers;
     SkPaint mFilteredPaint;
 
     // Various caches
@@ -923,6 +954,8 @@
     // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in
     // Properties.h
     bool mScissorOptimizationDisabled;
+    bool mDrawDeferDisabled;
+    bool mDrawReorderDisabled;
 
     // No-ops start/endTiling when set
     bool mSuppressTiling;
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index cab0e54..ee7bf70 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -25,7 +25,6 @@
 
 #include "Rect.h"
 #include "Vertex.h"
-#include "utils/Compare.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 8ee8f5c..62e38d3 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -42,6 +42,35 @@
 // Caching
 ///////////////////////////////////////////////////////////////////////////////
 
+int PatchCache::PatchDescription::compare(
+        const PatchCache::PatchDescription& lhs, const PatchCache::PatchDescription& rhs) {
+    int deltaInt = lhs.bitmapWidth - rhs.bitmapWidth;
+    if (deltaInt != 0) return deltaInt;
+
+    deltaInt = lhs.bitmapHeight - rhs.bitmapHeight;
+    if (deltaInt != 0) return deltaInt;
+
+    if (lhs.pixelWidth < rhs.pixelWidth) return -1;
+    if (lhs.pixelWidth > rhs.pixelWidth) return +1;
+
+    if (lhs.pixelHeight < rhs.pixelHeight) return -1;
+    if (lhs.pixelHeight > rhs.pixelHeight) return +1;
+
+    deltaInt = lhs.xCount - rhs.xCount;
+    if (deltaInt != 0) return deltaInt;
+
+    deltaInt = lhs.yCount - rhs.yCount;
+    if (deltaInt != 0) return deltaInt;
+
+    deltaInt = lhs.emptyCount - rhs.emptyCount;
+    if (deltaInt != 0) return deltaInt;
+
+    deltaInt = lhs.colorKey - rhs.colorKey;
+    if (deltaInt != 0) return deltaInt;
+
+    return 0;
+}
+
 void PatchCache::clear() {
     size_t count = mCache.size();
     for (size_t i = 0; i < count; i++) {
@@ -50,7 +79,7 @@
     mCache.clear();
 }
 
-Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight,
+Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
         const float pixelWidth, const float pixelHeight,
         const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
         const uint32_t width, const uint32_t height, const int8_t numColors) {
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 505798a..0822cba 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -19,7 +19,6 @@
 
 #include <utils/KeyedVector.h>
 
-#include "utils/Compare.h"
 #include "Debug.h"
 #include "Patch.h"
 
@@ -47,7 +46,7 @@
     PatchCache(uint32_t maxCapacity);
     ~PatchCache();
 
-    Patch* get(const float bitmapWidth, const float bitmapHeight,
+    Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
             const float pixelWidth, const float pixelHeight,
             const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
             const uint32_t width, const uint32_t height, const int8_t numColors);
@@ -70,7 +69,7 @@
                 xCount(0), yCount(0), emptyCount(0), colorKey(0) {
         }
 
-        PatchDescription(const float bitmapWidth, const float bitmapHeight,
+        PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
                 const float pixelWidth, const float pixelHeight,
                 const uint32_t xCount, const uint32_t yCount,
                 const int8_t emptyCount, const uint32_t colorKey):
@@ -80,28 +79,29 @@
                 emptyCount(emptyCount), colorKey(colorKey) {
         }
 
-        bool operator<(const PatchDescription& rhs) const {
-            LTE_FLOAT(bitmapWidth) {
-                LTE_FLOAT(bitmapHeight) {
-                    LTE_FLOAT(pixelWidth) {
-                        LTE_FLOAT(pixelHeight) {
-                            LTE_INT(xCount) {
-                                LTE_INT(yCount) {
-                                    LTE_INT(emptyCount) {
-                                        LTE_INT(colorKey) return false;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
+        static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
+
+        bool operator==(const PatchDescription& other) const {
+            return compare(*this, other) == 0;
+        }
+
+        bool operator!=(const PatchDescription& other) const {
+            return compare(*this, other) != 0;
+        }
+
+        friend inline int strictly_order_type(const PatchDescription& lhs,
+                const PatchDescription& rhs) {
+            return PatchDescription::compare(lhs, rhs) < 0;
+        }
+
+        friend inline int compare_type(const PatchDescription& lhs,
+                const PatchDescription& rhs) {
+            return PatchDescription::compare(lhs, rhs);
         }
 
     private:
-        float bitmapWidth;
-        float bitmapHeight;
+        uint32_t bitmapWidth;
+        uint32_t bitmapHeight;
         float pixelWidth;
         float pixelHeight;
         uint32_t xCount;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index f0b5553..14a2376 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -160,7 +160,7 @@
         // up and to the left.
         // This offset value is based on an assumption that some hardware may use as
         // little as 12.4 precision, so we offset by slightly more than 1/16.
-        p.translate(.375, .375, 0);
+        p.translate(.065, .065, 0);
     }
 
     mat4 t(transformMatrix);
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index b1df980..7b67b3c 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -81,6 +81,8 @@
 
 #define PROGRAM_IS_SIMPLE_GRADIENT 41
 
+#define PROGRAM_HAS_COLORS 42
+
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
@@ -120,6 +122,9 @@
     bool hasExternalTexture;
     bool hasTextureTransform;
 
+    // Color attribute
+    bool hasColors;
+
     // Modulate, this should only be set when setColor() return true
     bool modulate;
 
@@ -164,6 +169,8 @@
         hasExternalTexture = false;
         hasTextureTransform = false;
 
+        hasColors = false;
+
         isAA = false;
 
         modulate = false;
@@ -259,6 +266,7 @@
         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
         if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
         if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
+        if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index fb00335..74d598d 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -40,6 +40,8 @@
         "attribute vec4 position;\n";
 const char* gVS_Header_Attributes_TexCoords =
         "attribute vec2 texCoords;\n";
+const char* gVS_Header_Attributes_Colors =
+        "attribute vec4 colors;\n";
 const char* gVS_Header_Attributes_AAVertexShapeParameters =
         "attribute float vtxAlpha;\n";
 const char* gVS_Header_Uniforms_TextureTransform =
@@ -65,6 +67,8 @@
         "uniform mediump vec2 textureDimension;\n";
 const char* gVS_Header_Varyings_HasTexture =
         "varying vec2 outTexCoords;\n";
+const char* gVS_Header_Varyings_HasColors =
+        "varying vec4 outColors;\n";
 const char* gVS_Header_Varyings_IsAAVertexShape =
         "varying float alpha;\n";
 const char* gVS_Header_Varyings_HasBitmap =
@@ -94,6 +98,8 @@
         "\nvoid main(void) {\n";
 const char* gVS_Main_OutTexCoords =
         "    outTexCoords = texCoords;\n";
+const char* gVS_Main_OutColors =
+        "    outColors = colors;\n";
 const char* gVS_Main_OutTransformedTexCoords =
         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
 const char* gVS_Main_OutGradient[6] = {
@@ -325,6 +331,8 @@
     };
 const char* gFS_Main_FragColor =
         "    gl_FragColor = fragColor;\n";
+const char* gFS_Main_FragColor_HasColors =
+        "    gl_FragColor *= outColors;\n";
 const char* gFS_Main_FragColor_Blend =
         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
 const char* gFS_Main_FragColor_Blend_Swap =
@@ -459,6 +467,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Attributes_AAVertexShapeParameters);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Attributes_Colors);
+    }
     // Uniforms
     shader.append(gVS_Header_Uniforms);
     if (description.hasTextureTransform) {
@@ -480,6 +491,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAAVertexShape);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Varyings_HasColors);
+    }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
@@ -499,6 +513,9 @@
         if (description.isAA) {
             shader.append(gVS_Main_AAVertexShape);
         }
+        if (description.hasColors) {
+            shader.append(gVS_Main_OutColors);
+        }
         if (description.hasBitmap) {
             shader.append(description.isPoint ?
                     gVS_Main_OutPointBitmapTexCoords :
@@ -549,6 +566,9 @@
     if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAAVertexShape);
     }
+    if (description.hasColors) {
+        shader.append(gVS_Header_Varyings_HasColors);
+    }
     if (description.hasGradient) {
         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
     }
@@ -583,7 +603,7 @@
     }
 
     // Optimization for common cases
-    if (!description.isAA && !blendFramebuffer &&
+    if (!description.isAA && !blendFramebuffer && !description.hasColors &&
             description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
         bool fast = false;
 
@@ -729,6 +749,9 @@
             shader.append(!description.swapSrcDst ?
                     gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
         }
+        if (description.hasColors) {
+            shader.append(gFS_Main_FragColor_HasColors);
+        }
     }
     // End the shader
     shader.append(gFS_Footer);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 0c75242..f3957cf 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -82,6 +82,19 @@
  */
 #define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
 
+/**
+ * Disables draw operation deferral if set to "true", forcing draw
+ * commands to be issued to OpenGL in order, and processed in sequence
+ * with state-manipulation canvas commands.
+ */
+#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
+
+/**
+ * Used to disable draw operation reordering when deferring draw operations
+ * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
+ */
+#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
+
 // These properties are defined in mega-bytes
 #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
 #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 5f4bb5a..f50ac3c 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -159,6 +159,13 @@
         bottom += dy;
     }
 
+    void outset(float delta) {
+        left -= delta;
+        top -= delta;
+        right += delta;
+        bottom += delta;
+    }
+
     void snapToPixelBoundaries() {
         left = floorf(left + 0.5f);
         top = floorf(top + 0.5f);
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 9c7a5ab..db7bd48 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -222,7 +222,7 @@
         }
 
         // Cleanup shadow
-        delete[] shadow.image;
+        delete shadow.image;
     }
 
     return texture;
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c120428..523120e 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -33,7 +33,7 @@
 }; // struct Vertex
 
 /**
- * Simple structure to describe a vertex with a position and a texture.
+ * Simple structure to describe a vertex with a position and texture UV.
  */
 struct TextureVertex {
     float position[2];
@@ -53,6 +53,24 @@
 }; // struct TextureVertex
 
 /**
+ * Simple structure to describe a vertex with a position, texture UV and ARGB color.
+ */
+struct ColorTextureVertex : TextureVertex {
+    float color[4];
+
+    static inline void set(ColorTextureVertex* vertex, float x, float y,
+            float u, float v, int color) {
+        TextureVertex::set(vertex, x, y, u, v);
+
+        const float a = ((color >> 24) & 0xff) / 255.0f;
+        vertex[0].color[0] = a * ((color >> 16) & 0xff) / 255.0f;
+        vertex[0].color[1] = a * ((color >>  8) & 0xff) / 255.0f;
+        vertex[0].color[2] = a * ((color      ) & 0xff) / 255.0f;
+        vertex[0].color[3] = a;
+    }
+}; // struct ColorTextureVertex
+
+/**
  * Simple structure to describe a vertex with a position and an alpha value.
  */
 struct AlphaVertex : Vertex {
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 24b0523..f653592 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <SkGlyph.h>
 #include <utils/Log.h>
 
 #include "Debug.h"
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 1a75ea8..8c5a8ff 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -20,7 +20,6 @@
 
 #include <utils/JenkinsHash.h>
 
-#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include "Debug.h"
diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h
deleted file mode 100644
index fdd9acf..0000000
--- a/libs/hwui/utils/Compare.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_COMPARE_H
-#define ANDROID_HWUI_COMPARE_H
-
-#include <cmath>
-
-/**
- * Compare floats.
- */
-#define LTE_FLOAT(a) \
-    if (a < rhs.a) return true; \
-    if (a == rhs.a)
-
-/**
- * Compare integers.
- */
-#define LTE_INT(a) \
-    if (a < rhs.a) return true; \
-    if (a == rhs.a)
-
-#endif // ANDROID_HWUI_COMPARE_H
diff --git a/libs/hwui/utils/Timing.h b/libs/hwui/utils/Timing.h
new file mode 100644
index 0000000..eced987
--- /dev/null
+++ b/libs/hwui/utils/Timing.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_TIMING_H
+#define ANDROID_HWUI_TIMING_H
+
+#include <sys/time.h>
+
+#define TIME_METHOD() MethodTimer __method_timer(__func__)
+class MethodTimer {
+public:
+    MethodTimer(const char* name)
+            : mMethodName(name) {
+        gettimeofday(&mStart, NULL);
+    }
+
+    ~MethodTimer() {
+        struct timeval stop;
+        gettimeofday(&stop, NULL);
+        long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
+                + (stop.tv_usec - mStart.tv_usec);
+        ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);
+    }
+private:
+    const char* mMethodName;
+    struct timeval mStart;
+};
+
+#endif
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4398642..f6593e0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -191,17 +191,27 @@
         public static final int AACObjectHE_PS      = 29;
         public static final int AACObjectELD        = 39;
 
+        // from OMX_VIDEO_VP8LEVELTYPE
+        public static final int VP8Level_Version0 = 0x01;
+        public static final int VP8Level_Version1 = 0x02;
+        public static final int VP8Level_Version2 = 0x04;
+        public static final int VP8Level_Version3 = 0x08;
+
+        // from OMX_VIDEO_VP8PROFILETYPE
+        public static final int VP8ProfileMain = 0x01;
+
+
         /**
          * Defined in the OpenMAX IL specs, depending on the type of media
          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
-         * or OMX_VIDEO_MPEG4PROFILETYPE.
+         * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
          */
         public int profile;
 
         /**
          * Defined in the OpenMAX IL specs, depending on the type of media
          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
-         * or OMX_VIDEO_MPEG4LEVELTYPE.
+         * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
          */
         public int level;
     };
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7bd9049..11f4180 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -948,7 +948,12 @@
 
     private void setDataSource(String path, String[] keys, String[] values)
             throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
-        File file = new File(path);
+        final Uri uri = Uri.parse(path);
+        if ("file".equals(uri.getScheme())) {
+            path = uri.getPath();
+        }
+
+        final File file = new File(path);
         if (file.exists()) {
             FileInputStream is = new FileInputStream(file);
             FileDescriptor fd = is.getFD();
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f8c945b..86700b3 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -28,7 +28,6 @@
 #include "JNIHelp.h"
 
 #include <gui/Surface.h>
-#include <gui/SurfaceTextureClient.h>
 
 #include <media/ICrypto.h>
 #include <media/stagefright/MediaCodec.h>
@@ -114,9 +113,9 @@
         const sp<IGraphicBufferProducer> &bufferProducer,
         const sp<ICrypto> &crypto,
         int flags) {
-    sp<SurfaceTextureClient> client;
+    sp<Surface> client;
     if (bufferProducer != NULL) {
-        mSurfaceTextureClient = new SurfaceTextureClient(bufferProducer);
+        mSurfaceTextureClient = new Surface(bufferProducer);
     } else {
         mSurfaceTextureClient.clear();
     }
@@ -398,7 +397,7 @@
     if (jsurface != NULL) {
         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
         if (surface != NULL) {
-            bufferProducer = surface->getSurfaceTexture();
+            bufferProducer = surface->getIGraphicBufferProducer();
         } else {
             jniThrowException(
                     env,
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a9bb9af..f478788 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -32,7 +32,7 @@
 struct ICrypto;
 struct IGraphicBufferProducer;
 struct MediaCodec;
-struct SurfaceTextureClient;
+class Surface;
 
 struct JMediaCodec : public RefBase {
     JMediaCodec(
@@ -91,7 +91,7 @@
 private:
     jclass mClass;
     jweak mObject;
-    sp<SurfaceTextureClient> mSurfaceTextureClient;
+    sp<Surface> mSurfaceTextureClient;
 
     sp<ALooper> mLooper;
     sp<MediaCodec> mCodec;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 5408a1f..7421022 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -273,7 +273,7 @@
     if (jsurface) {
         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
         if (surface != NULL) {
-            new_st = surface->getSurfaceTexture();
+            new_st = surface->getIGraphicBufferProducer();
             if (new_st == NULL) {
                 jniThrowException(env, "java/lang/IllegalArgumentException",
                     "The surface does not have a binding SurfaceTexture!");
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index b6e6ceb..5bf16cc 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -34,6 +34,7 @@
 #include "android_runtime/AndroidRuntime.h"
 
 #include <system/audio.h>
+#include <android_runtime/android_view_Surface.h>
 
 // ----------------------------------------------------------------------------
 
@@ -47,8 +48,6 @@
 struct fields_t {
     jfieldID    context;
     jfieldID    surface;
-    /* actually in android.view.Surface XXX */
-    jfieldID    surface_native;
 
     jmethodID   post_event;
 };
@@ -109,8 +108,7 @@
 static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
 {
     ALOGV("get_surface");
-    Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native);
-    return sp<Surface>(p);
+    return android_view_Surface_getSurface(env, clazz);
 }
 
 // Returns true if it throws an exception.
@@ -328,7 +326,7 @@
             return;
         }
 
-        ALOGI("prepare: surface=%p (identity=%d)", native_surface.get(), native_surface->getIdentity());
+        ALOGI("prepare: surface=%p", native_surface.get());
         if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
             return;
         }
@@ -409,11 +407,6 @@
         return;
     }
 
-    fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    if (fields.surface_native == NULL) {
-        return;
-    }
-
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
     if (fields.post_event == NULL) {
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 41c28c0..c1ad516 100644
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -34,6 +34,8 @@
 
 #include "VideoEditorMain.h"
 
+#include <android_runtime/android_view_Surface.h>
+
 extern "C" {
 #include <M4OSA_Clock.h>
 #include <M4OSA_CharStar.h>
@@ -628,19 +630,8 @@
                                                 (NULL == surface),
                                                 "surface is null");
 
-    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surfaceClass),
-                                             "not initialized");
+    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, surface);
 
-    jfieldID surface_native =
-            pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surface_native),
-                                             "not initialized");
-
-    Surface* const p = (Surface*)pEnv->GetIntField(surface, surface_native);
-    sp<Surface> previewSurface = sp<Surface>(p);
     // Validate the mSurface's mNativeSurface field
     videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
                                                 (NULL == previewSurface.get()),
@@ -709,19 +700,9 @@
     videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
                                                 (NULL == mSurface),
                                                 "mSurface is null");
-    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surfaceClass),
-                                             "not initialized");
 
-    jfieldID surface_native =
-            pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surface_native),
-                                             "not initialized");
+    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
 
-    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
-    sp<Surface> previewSurface = sp<Surface>(p);
     // Validate the mSurface's mNativeSurface field
     videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
                                                 (NULL == previewSurface.get()),
@@ -1038,20 +1019,8 @@
     videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
                                                 (NULL == mSurface),
                                                 "mSurface is null");
-    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surfaceClass),
-                                             "not initialized");
 
-    jfieldID surface_native =
-            pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surface_native),
-                                             "not initialized");
-
-    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
-    sp<Surface> previewSurface = sp<Surface>(p);
-
+    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
 
     const char *pString = pEnv->GetStringUTFChars(filePath, NULL);
     if (pString == M4OSA_NULL) {
@@ -2144,21 +2113,8 @@
                                                 (NULL == mSurface),
                                                 "mSurface is null");
 
-    jclass surfaceClass = pEnv->FindClass("android/view/Surface");
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surfaceClass),
-                                             "not initialized");
-    //jfieldID surface_native = pEnv->GetFieldID(surfaceClass, "mSurface", "I");
-    jfieldID surface_native
-        = pEnv->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+    sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
 
-    videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
-                                             (M4OSA_NULL == surface_native),
-                                             "not initialized");
-
-    Surface* const p = (Surface*)pEnv->GetIntField(mSurface, surface_native);
-
-    sp<Surface> previewSurface = sp<Surface>(p);
     // Validate the mSurface's mNativeSurface field
     videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
                                                 (NULL == previewSurface.get()),
diff --git a/media/mca/filterfw/jni/jni_gl_environment.cpp b/media/mca/filterfw/jni/jni_gl_environment.cpp
index b64004e..9abf191 100644
--- a/media/mca/filterfw/jni/jni_gl_environment.cpp
+++ b/media/mca/filterfw/jni/jni_gl_environment.cpp
@@ -24,7 +24,7 @@
 #include "native/core/gl_env.h"
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 #include <utils/Errors.h>
 #include <system/window.h>
 
@@ -34,7 +34,7 @@
 using android::MediaRecorder;
 using android::sp;
 using android::IGraphicBufferProducer;
-using android::SurfaceTextureClient;
+using android::Surface;
 
 
 class NativeWindowHandle : public WindowHandle {
@@ -290,7 +290,7 @@
               <IGraphicBufferProducer> handle.");
       return -1;
     }
-    sp<SurfaceTextureClient> surfaceTC = new SurfaceTextureClient(surfaceMS);
+    sp<Surface> surfaceTC = new Surface(surfaceMS);
     // Get the ANativeWindow
     sp<ANativeWindow> window = surfaceTC;
 
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index 8ed82e2..73768fe 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -161,7 +161,7 @@
 
   // Create dummy surface using a GLConsumer
   surfaceTexture_ = new GLConsumer(0);
-  window_ = new SurfaceTextureClient(static_cast<sp<IGraphicBufferProducer> >(
+  window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(
           surfaceTexture_->getBufferQueue()));
 
   surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
diff --git a/media/mca/filterfw/native/core/gl_env.h b/media/mca/filterfw/native/core/gl_env.h
index 3c87195..81e1e9d 100644
--- a/media/mca/filterfw/native/core/gl_env.h
+++ b/media/mca/filterfw/native/core/gl_env.h
@@ -28,7 +28,7 @@
 #include <EGL/egl.h>
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
 
 namespace android {
 namespace filterfw {
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.h b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
index 374604c..afedcbd 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.h
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
@@ -33,7 +33,6 @@
      //! Return the allocation size for the pixels
     size_t getSize() const { return mSize; }
 
-    SK_DECLARE_UNFLATTENABLE_OBJECT()
 protected:
     // overrides from SkPixelRef
     virtual void* onLockPixels(SkColorTable**);
diff --git a/nfc-extras/java/com/android/nfc_extras/EeAlreadyOpenException.java b/nfc-extras/java/com/android/nfc_extras/EeAlreadyOpenException.java
new file mode 100644
index 0000000..9fde0a3
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeAlreadyOpenException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+public class EeAlreadyOpenException extends EeIOException {
+    public EeAlreadyOpenException() {
+        super();
+    }
+
+    public EeAlreadyOpenException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/EeExternalFieldException.java b/nfc-extras/java/com/android/nfc_extras/EeExternalFieldException.java
new file mode 100644
index 0000000..4326fab
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeExternalFieldException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+public class EeExternalFieldException extends EeIOException {
+    public EeExternalFieldException() {
+        super();
+    }
+
+    public EeExternalFieldException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/EeIOException.java b/nfc-extras/java/com/android/nfc_extras/EeIOException.java
new file mode 100644
index 0000000..66a3b25
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeIOException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+import java.io.IOException;
+
+public class EeIOException extends IOException {
+    public EeIOException() {
+        super();
+    }
+
+    public EeIOException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/EeInitializationException.java b/nfc-extras/java/com/android/nfc_extras/EeInitializationException.java
new file mode 100644
index 0000000..00e5264
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeInitializationException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+public class EeInitializationException extends EeIOException {
+    public EeInitializationException() {
+        super();
+    }
+
+    public EeInitializationException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/EeListenModeException.java b/nfc-extras/java/com/android/nfc_extras/EeListenModeException.java
new file mode 100644
index 0000000..07f1980
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeListenModeException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+public class EeListenModeException extends EeIOException {
+    public EeListenModeException() {
+        super();
+    }
+
+    public EeListenModeException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/EeNfcDisabledException.java b/nfc-extras/java/com/android/nfc_extras/EeNfcDisabledException.java
new file mode 100644
index 0000000..091db28
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/EeNfcDisabledException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc_extras;
+
+public class EeNfcDisabledException extends EeIOException {
+    public EeNfcDisabledException() {
+        super();
+    }
+
+    public EeNfcDisabledException(String message) {
+        super(message);
+    }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
index f47327a..fd7cb33 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -28,6 +28,15 @@
     private final NfcAdapterExtras mExtras;
     private final Binder mToken;
 
+    // Exception types that can be thrown by NfcService
+    // 1:1 mapped to EE_ERROR_ types in NfcService
+    private static final int EE_ERROR_IO = -1;
+    private static final int EE_ERROR_ALREADY_OPEN = -2;
+    private static final int EE_ERROR_INIT = -3;
+    private static final int EE_ERROR_LISTEN_MODE = -4;
+    private static final int EE_ERROR_EXT_FIELD = -5;
+    private static final int EE_ERROR_NFC_DISABLED = -6;
+
     /**
      * Broadcast Action: An ISO-DEP AID was selected.
      *
@@ -118,24 +127,49 @@
     /**
      * Open the NFC Execution Environment on its contact interface.
      *
-     * <p>Only one process may open the secure element at a time. If it is
-     * already open, an {@link IOException} is thrown.
+     * <p>Opening a channel to the the secure element may fail
+     * for a number of reasons:
+     * <ul>
+     * <li>NFC must be enabled for the connection to the SE to be opened.
+     * If it is disabled at the time of this call, an {@link EeNfcDisabledException}
+     * is thrown.
      *
+     * <li>Only one process may open the secure element at a time. Additionally,
+     * this method is not reentrant. If the secure element is already opened,
+     * either by this process or by a different process, an {@link EeAlreadyOpenException}
+     * is thrown.
+     *
+     * <li>If the connection to the secure element could not be initialized,
+     * an {@link EeInitializationException} is thrown.
+     *
+     * <li>If the secure element or the NFC controller is activated in listen
+     * mode - that is, it is talking over the contactless interface - an
+     * {@link EeListenModeException} is thrown.
+     *
+     * <li>If the NFC controller is in a field powered by a remote device,
+     * such as a payment terminal, an {@link EeExternalFieldException} is
+     * thrown.
+     * </ul>
      * <p>All other NFC functionality is disabled while the NFC-EE is open
      * on its contact interface, so make sure to call {@link #close} once complete.
      *
      * <p class="note">
      * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
      *
-     * @throws IOException if the NFC-EE is already open, or some other error occurs
+     * @throws EeAlreadyOpenException if the NFC-EE is already open
+     * @throws EeNfcDisabledException if NFC is disabled
+     * @throws EeInitializationException if the Secure Element could not be initialized
+     * @throws EeListenModeException if the NFCC or Secure Element is activated in listen mode
+     * @throws EeExternalFieldException if the NFCC is in the presence of a remote-powered field
+     * @throws EeIoException if an unknown error occurs
      */
-    public void open() throws IOException {
+    public void open() throws EeIOException {
         try {
             Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
             throwBundle(b);
         } catch (RemoteException e) {
             mExtras.attemptDeadServiceRecovery(e);
-            throw new IOException("NFC Service was dead, try again");
+            throw new EeIOException("NFC Service was dead, try again");
         }
     }
 
@@ -176,9 +210,20 @@
         return b.getByteArray("out");
     }
 
-    private static void throwBundle(Bundle b) throws IOException {
-        if (b.getInt("e") == -1) {
-            throw new IOException(b.getString("m"));
+    private static void throwBundle(Bundle b) throws EeIOException {
+        switch (b.getInt("e")) {
+            case EE_ERROR_NFC_DISABLED:
+                throw new EeNfcDisabledException(b.getString("m"));
+            case EE_ERROR_IO:
+                throw new EeIOException(b.getString("m"));
+            case EE_ERROR_INIT:
+                throw new EeInitializationException(b.getString("m"));
+            case EE_ERROR_EXT_FIELD:
+                throw new EeExternalFieldException(b.getString("m"));
+            case EE_ERROR_LISTEN_MODE:
+                throw new EeListenModeException(b.getString("m"));
+            case EE_ERROR_ALREADY_OPEN:
+                throw new EeAlreadyOpenException(b.getString("m"));
         }
     }
 }
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 493c168..24d9c39 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
-    <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejeza kamili"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
     <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?"\n\n" Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Cheleza data yangu"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
@@ -32,7 +32,7 @@
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
-    <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejeza..."</string>
-    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejeza kumekamilika"</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejesha..."</string>
+    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejesha kumekamilika"</string>
     <string name="toast_timeout" msgid="5276598587087626877">"Muda wa uendeshaji umeisha"</string>
 </resources>
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
index a6415b2..89f84fc 100644
--- a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
@@ -4,6 +4,7 @@
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.content.Context;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
@@ -11,6 +12,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.HashSet;
 
 public class SharedStorageAgent extends FullBackupAgent {
     static final String TAG = "SharedStorageAgent";
@@ -38,13 +40,20 @@
         // "primary" shared storage volume is first in the list.
         if (mVolumes != null) {
             if (DEBUG) Slog.i(TAG, "Backing up " + mVolumes.length + " shared volumes");
+            // Ignore all apps' getExternalFilesDir() content; it is backed up as part of
+            // each app-specific payload.
+            HashSet<String> externalFilesDirFilter = new HashSet<String>();
+            final File externalAndroidRoot = new File(Environment.getExternalStorageDirectory(),
+                    Environment.DIRECTORY_ANDROID);
+            externalFilesDirFilter.add(externalAndroidRoot.getCanonicalPath());
+
             for (int i = 0; i < mVolumes.length; i++) {
                 StorageVolume v = mVolumes[i];
                 // Express the contents of volume N this way in the tar stream:
                 //     shared/N/path/to/file
                 // The restore will then extract to the given volume
                 String domain = FullBackup.SHARED_PREFIX + i;
-                fullBackupFileTree(null, domain, v.getPath(), null, output);
+                fullBackupFileTree(null, domain, v.getPath(), externalFilesDirFilter, output);
             }
         }
     }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b85121e..66080f3 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -10,6 +10,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.DUMP" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 79f9650..8d949a5 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -485,14 +485,12 @@
 
             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
-            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
-                throw new RuntimeException("Cannot swap buffers");
-            }
+            boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
             checkEglError();
 
             finishGL();
 
-            return true;
+            return status;
         }
 
         private FloatBuffer createMesh(int left, int top, float right, float bottom) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index ceb8654..8e1773a 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -154,6 +154,13 @@
         return Math.max(mMinAlpha, result);
     }
 
+    private void updateAlphaFromOffset(View animView, boolean dismissable) {
+        if (FADE_OUT_DURING_SWIPE && dismissable) {
+            animView.setAlpha(getAlphaForOffset(animView));
+        }
+        invalidateGlobalRegion(animView);
+    }
+
     // invalidate the view's own bounds all the way up the view hierarchy
     public static void invalidateGlobalRegion(View view) {
         invalidateGlobalRegion(
@@ -290,10 +297,7 @@
         });
         anim.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    animView.setAlpha(getAlphaForOffset(animView));
-                }
-                invalidateGlobalRegion(animView);
+                updateAlphaFromOffset(animView, canAnimViewBeDismissed);
             }
         });
         anim.start();
@@ -307,10 +311,12 @@
         anim.setDuration(duration);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    animView.setAlpha(getAlphaForOffset(animView));
-                }
-                invalidateGlobalRegion(animView);
+                updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+            }
+        });
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animator) {
+                updateAlphaFromOffset(animView, canAnimViewBeDismissed);
             }
         });
         anim.start();
@@ -347,10 +353,8 @@
                         }
                     }
                     setTranslation(mCurrAnimView, delta);
-                    if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
-                        mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
-                    }
-                    invalidateGlobalRegion(mCurrView);
+
+                    updateAlphaFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
                 }
                 break;
             case MotionEvent.ACTION_UP:
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 198bb74..8979fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -21,15 +21,11 @@
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.net.Uri;
-import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.Log;
 
-import java.io.IOException;
-import java.lang.IllegalStateException;
 import java.lang.Thread;
 import java.util.LinkedList;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index ddfaad5..b498368 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -50,6 +50,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -455,7 +456,7 @@
         }
 
         // Take the screenshot
-        mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
+        mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
         if (mScreenBitmap == null) {
             notifyScreenshotError(mContext, mNotificationManager);
             finisher.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 5d9c7bc..988951c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -147,9 +149,17 @@
             }
         }
         public float getXVelocity() {
+            if (Float.isNaN(mVX)) {
+                Slog.v("FlingTracker", "warning: vx=NaN");
+                // XXX: should return 0
+            }
             return mVX;
         }
         public float getYVelocity() {
+            if (Float.isNaN(mVY)) {
+                Slog.v("FlingTracker", "warning: vx=NaN");
+                // XXX: should return 0
+            }
             return mVY;
         }
         public void recycle() {
@@ -282,6 +292,9 @@
                     || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) {
                 post(mStopAnimator);
             }
+        } else {
+            Slog.v(TAG, "animationTick called with dtms=" + dtms + "; nothing to do (h="
+                    + mExpandedHeight + " v=" + mVel + ")");
         }
     }
 
@@ -372,7 +385,7 @@
                         case MotionEvent.ACTION_MOVE:
                             final float h = rawY - mAbsPos[1] - mTouchOffset;
                             if (h > mPeekHeight) {
-                                if (mPeekAnimator != null && mPeekAnimator.isRunning()) {
+                                if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
                                     mPeekAnimator.cancel();
                                 }
                                 mJustPeeked = false;
@@ -503,7 +516,7 @@
     public void setExpandedHeight(float height) {
         if (DEBUG) LOG("setExpandedHeight(%.1f)", height);
         mRubberbanding = false;
-        if (mTimeAnimator.isRunning()) {
+        if (mTimeAnimator.isStarted()) {
             post(mStopAnimator);
         }
         setExpandedHeightInternal(height);
@@ -517,6 +530,11 @@
     }
 
     public void setExpandedHeightInternal(float h) {
+        if (Float.isNaN(h)) {
+            Slog.v(TAG, "setExpandedHeightInternal: warning: h=NaN");
+            // XXX: should set h to 0
+        }
+
         float fh = getFullHeight();
         if (fh == 0) {
             // Hmm, full height hasn't been computed yet
@@ -524,6 +542,7 @@
 
         if (h < 0) h = 0;
         if (!(mRubberbandingEnabled && (mTracking || mRubberbanding)) && h > fh) h = fh;
+
         mExpandedHeight = h;
 
         if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
@@ -546,6 +565,10 @@
     }
 
     public void setExpandedFraction(float frac) {
+        if (Float.isNaN(frac)) {
+            Slog.v(TAG, "setExpandedFraction: frac=NaN");
+            // XXX: set frac to 0 to defend
+        }
         setExpandedHeight(getFullHeight() * frac);
     }
 
@@ -594,4 +617,20 @@
             if (DEBUG) LOG("skipping expansion: is expanded");
         }
     }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(String.format("[PanelView(%s): expandedHeight=%f fullHeight=%f closing=%s"
+                + " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
+                + "]",
+                this.getClass().getSimpleName(),
+                getExpandedHeight(),
+                getFullHeight(),
+                mClosing?"T":"f",
+                mTracking?"T":"f",
+                mRubberbanding?"T":"f",
+                mJustPeeked?"T":"f",
+                mPeekAnimator, ((mPeekAnimator!=null && mPeekAnimator.isStarted())?" (started)":""),
+                mTimeAnimator, ((mTimeAnimator!=null && mTimeAnimator.isStarted())?" (started)":"")
+        ));
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 01596dc..9b1c1db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -246,16 +246,6 @@
     private ViewGroup mCling;
     private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle
 
-    boolean mAnimating;
-    boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
-    float mAnimY;
-    float mAnimVel;
-    float mAnimAccel;
-    long mAnimLastTimeNanos;
-    boolean mAnimatingReveal = false;
-    int mViewDelta;
-    float mFlingVelocity;
-    int mFlingY;
     int[] mAbsPos = new int[2];
     Runnable mPostCollapseCleanup = null;
 
@@ -352,7 +342,7 @@
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                    if (mExpandedVisible && !mAnimating) {
+                    if (mExpandedVisible) {
                         animateCollapsePanels();
                     }
                 }
@@ -963,7 +953,7 @@
                 mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
             }
 
-            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 && !mAnimating) {
+            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0) {
                 animateCollapsePanels();
             }
         }
@@ -1411,10 +1401,6 @@
         if (SPEW) {
             Slog.d(TAG, "animateCollapse():"
                     + " mExpandedVisible=" + mExpandedVisible
-                    + " mAnimating=" + mAnimating
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel
                     + " flags=" + flags);
         }
 
@@ -2051,16 +2037,6 @@
                     + ", mTrackingPosition=" + mTrackingPosition);
             pw.println("  mTicking=" + mTicking);
             pw.println("  mTracking=" + mTracking);
-            pw.println("  mNotificationPanel=" + 
-                    ((mNotificationPanel == null) 
-                            ? "null" 
-                            : (mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""))));
-            pw.println("  mAnimating=" + mAnimating
-                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
-                    + ", mAnimAccel=" + mAnimAccel);
-            pw.println("  mAnimLastTimeNanos=" + mAnimLastTimeNanos);
-            pw.println("  mAnimatingReveal=" + mAnimatingReveal
-                    + " mViewDelta=" + mViewDelta);
             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mPile: " + viewInfo(mPile));
             pw.println("  mTickerView: " + viewInfo(mTickerView));
@@ -2075,6 +2051,20 @@
             mNavigationBarView.dump(fd, pw, args);
         }
 
+        pw.println("  Panels: ");
+        if (mNotificationPanel != null) {
+            pw.println("    mNotificationPanel=" +
+                mNotificationPanel + " params=" + mNotificationPanel.getLayoutParams().debug(""));
+            pw.print  ("      ");
+            mNotificationPanel.dump(fd, pw, args);
+        }
+        if (mSettingsPanel != null) {
+            pw.println("    mSettingsPanel=" +
+                mSettingsPanel + " params=" + mSettingsPanel.getLayoutParams().debug(""));
+            pw.print  ("      ");
+            mSettingsPanel.dump(fd, pw, args);
+        }
+
         if (DUMPTRUCK) {
             synchronized (mNotificationData) {
                 int N = mNotificationData.size();
diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml
index fef00c2..ee7f4b8 100644
--- a/packages/VpnDialogs/res/layout/confirm.xml
+++ b/packages/VpnDialogs/res/layout/confirm.xml
@@ -52,6 +52,7 @@
                 android:layout_height="wrap_content"
                 android:text="@string/accept"
                 android:textSize="20sp"
+                android:filterTouchesWhenObscured="true"
                 android:checked="false"/>
     </LinearLayout>
 </ScrollView>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 7a1e66c..6faf4e0 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -78,6 +78,7 @@
             getWindow().setCloseOnTouchOutside(false);
             mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
             mButton.setEnabled(false);
+            mButton.setFilterTouchesWhenObscured(true);
         } catch (Exception e) {
             Log.e(TAG, "onResume", e);
             finish();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 88a0ef3..e1d9b73 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -20,11 +20,7 @@
 import static android.view.View.MeasureSpec.getMode;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.*;
 
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
@@ -2639,7 +2635,11 @@
         }
 
         if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
-            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
+            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) {
+            setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
         }
 
         if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9cb54a9..acbde9b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -101,55 +101,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.*;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
@@ -353,10 +305,17 @@
     PointerLocationView mPointerLocationView;
     InputChannel mPointerLocationInputChannel;
 
-    // The current size of the screen; really; (ir)regardless of whether the status
-    // bar can be hidden or not
+    // The current size of the screen; really; extends into the overscan area of
+    // the screen and doesn't account for any system elements like the status bar.
+    int mOverscanScreenLeft, mOverscanScreenTop;
+    int mOverscanScreenWidth, mOverscanScreenHeight;
+    // The current visible size of the screen; really; (ir)regardless of whether the status
+    // bar can be hidden but not extending into the overscan area.
     int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
     int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
+    // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate.
+    int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop;
+    int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight;
     // The current size of the screen; these may be different than (0,0)-(dw,dh)
     // if the status bar can't be hidden; in that case it effectively carves out
     // that area of the display from all other windows.
@@ -455,6 +414,11 @@
     int mPortraitRotation = 0;   // default portrait rotation
     int mUpsideDownRotation = 0; // "other" portrait rotation
 
+    int mOverscanLeft = 0;
+    int mOverscanTop = 0;
+    int mOverscanRight = 0;
+    int mOverscanBottom = 0;
+
     // What we do when the user long presses on home
     private int mLongPressOnHomeBehavior = -1;
 
@@ -946,6 +910,9 @@
 
     @Override
     public void setInitialDisplaySize(Display display, int width, int height, int density) {
+        if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException("Can only set the default display");
+        }
         mDisplay = display;
 
         int shortSize, longSize;
@@ -1056,6 +1023,16 @@
         mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
     }
 
+    @Override
+    public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+        if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+            mOverscanLeft = left;
+            mOverscanTop = top;
+            mOverscanRight = right;
+            mOverscanBottom = bottom;
+        }
+    }
+
     public void updateSettings() {
         ContentResolver resolver = mContext.getContentResolver();
         boolean updateRotation = false;
@@ -2388,7 +2365,7 @@
                     contentInset.set(mStableLeft, mStableTop,
                             availRight - mStableRight, availBottom - mStableBottom);
                 }
-            } else if ((fl & FLAG_FULLSCREEN) != 0) {
+            } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
                 contentInset.setEmpty();
             } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
                         | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
@@ -2407,20 +2384,64 @@
     @Override
     public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
                               int displayRotation) {
-        mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
-        mUnrestrictedScreenWidth = displayWidth;
-        mUnrestrictedScreenHeight = displayHeight;
-        mRestrictedScreenLeft = mRestrictedScreenTop = 0;
-        mRestrictedScreenWidth = displayWidth;
-        mRestrictedScreenHeight = displayHeight;
+        final int overscanLeft, overscanTop, overscanRight, overscanBottom;
+        if (isDefaultDisplay) {
+            switch (displayRotation) {
+                case Surface.ROTATION_90:
+                    overscanLeft = mOverscanTop;
+                    overscanTop = mOverscanRight;
+                    overscanRight = mOverscanBottom;
+                    overscanBottom = mOverscanLeft;
+                    break;
+                case Surface.ROTATION_180:
+                    overscanLeft = mOverscanRight;
+                    overscanTop = mOverscanBottom;
+                    overscanRight = mOverscanLeft;
+                    overscanBottom = mOverscanTop;
+                    break;
+                case Surface.ROTATION_270:
+                    overscanLeft = mOverscanBottom;
+                    overscanTop = mOverscanLeft;
+                    overscanRight = mOverscanTop;
+                    overscanBottom = mOverscanRight;
+                    break;
+                default:
+                    overscanLeft = mOverscanLeft;
+                    overscanTop = mOverscanTop;
+                    overscanRight = mOverscanRight;
+                    overscanBottom = mOverscanBottom;
+                    break;
+            }
+        } else {
+            overscanLeft = 0;
+            overscanTop = 0;
+            overscanRight = 0;
+            overscanBottom = 0;
+        }
+        mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
+        mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
+        mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
+        mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
+        mSystemLeft = 0;
+        mSystemTop = 0;
+        mSystemRight = displayWidth;
+        mSystemBottom = displayHeight;
+        mUnrestrictedScreenLeft = overscanLeft;
+        mUnrestrictedScreenTop = overscanTop;
+        mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
+        mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
+        mRestrictedScreenLeft = mUnrestrictedScreenLeft;
+        mRestrictedScreenTop = mUnrestrictedScreenTop;
+        mRestrictedScreenWidth = mUnrestrictedScreenWidth;
+        mRestrictedScreenHeight = mUnrestrictedScreenHeight;
         mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
-                = mSystemLeft = mCurLeft = 0;
+                = mCurLeft = mUnrestrictedScreenLeft;
         mDockTop = mContentTop = mStableTop = mStableFullscreenTop
-                = mSystemTop = mCurTop = 0;
+                = mCurTop = mUnrestrictedScreenTop;
         mDockRight = mContentRight = mStableRight = mStableFullscreenRight
-                = mSystemRight = mCurRight = displayWidth;
+                = mCurRight = displayWidth - overscanRight;
         mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
-                = mSystemBottom = mCurBottom = displayHeight;
+                = mCurBottom = displayHeight - overscanBottom;
         mDockLayer = 0x10000000;
         mStatusBarLayer = -1;
 
@@ -2467,13 +2488,15 @@
                 mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
                 if (mNavigationBarOnBottom) {
                     // It's a system nav bar or a portrait screen; nav bar goes on bottom.
-                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
-                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
+                    int top = displayHeight - overscanBottom
+                            - mNavigationBarHeightForRotation[displayRotation];
+                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
                     mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
                     if (navVisible) {
                         mNavigationBar.showLw(true);
                         mDockBottom = mTmpNavigationFrame.top;
-                        mRestrictedScreenHeight = mDockBottom - mDockTop;
+                        mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
+                        mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
                     } else {
                         // We currently want to hide the navigation UI.
                         mNavigationBar.hideLw(true);
@@ -2486,13 +2509,15 @@
                     }
                 } else {
                     // Landscape screen; nav bar goes to the right.
-                    int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
-                    mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
+                    int left = displayWidth - overscanRight
+                            - mNavigationBarWidthForRotation[displayRotation];
+                    mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
                     mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
                     if (navVisible) {
                         mNavigationBar.showLw(true);
                         mDockRight = mTmpNavigationFrame.left;
-                        mRestrictedScreenWidth = mDockRight - mDockLeft;
+                        mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+                        mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
                     } else {
                         // We currently want to hide the navigation UI.
                         mNavigationBar.hideLw(true);
@@ -2524,8 +2549,8 @@
                 // apply any navigation bar insets
                 pf.left = df.left = mUnrestrictedScreenLeft;
                 pf.top = df.top = mUnrestrictedScreenTop;
-                pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
-                pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
+                pf.right = df.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+                pf.bottom = df.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
                 vf.left = mStableLeft;
                 vf.top = mStableTop;
                 vf.right = mStableRight;
@@ -2685,12 +2710,12 @@
                 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
             } else {
                 // Give the window full screen.
-                pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
-                pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+                pf.left = df.left = cf.left = mOverscanScreenLeft;
+                pf.top = df.top = cf.top = mOverscanScreenTop;
                 pf.right = df.right = cf.right
-                        = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        = mOverscanScreenLeft + mOverscanScreenWidth;
                 pf.bottom = df.bottom = cf.bottom
-                        = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                        = mOverscanScreenTop + mOverscanScreenHeight;
             }
         } else  if (attrs.type == TYPE_INPUT_METHOD) {
             pf.left = df.left = cf.left = vf.left = mDockLeft;
@@ -2729,33 +2754,44 @@
                         pf.top = df.top = mUnrestrictedScreenTop;
                         pf.right = df.right = hasNavBar
                                             ? mRestrictedScreenLeft+mRestrictedScreenWidth
-                                            : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                                            : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                         pf.bottom = df.bottom = hasNavBar
                                               ? mRestrictedScreenTop+mRestrictedScreenHeight
-                                              : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                                              : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
 
                         if (DEBUG_LAYOUT) {
                             Log.v(TAG, String.format(
                                         "Laying out status bar window: (%d,%d - %d,%d)",
                                         pf.left, pf.top, pf.right, pf.bottom));
                         }
+                    } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0
+                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        // Asking to layout into the overscan region, so give it that pure
+                        // unrestricted area.
+                        pf.left = df.left = mOverscanScreenLeft;
+                        pf.top = df.top = mOverscanScreenTop;
+                        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
                     } else if (mCanHideNavigationBar
                             && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                             && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                         // Asking for layout as if the nav bar is hidden, lets the
-                        // application extend into the unrestricted screen area.  We
+                        // application extend into the unrestricted overscan screen area.  We
                         // only do this for application windows to ensure no window that
                         // can be above the nav bar can do this.
-                        pf.left = df.left = mUnrestrictedScreenLeft;
-                        pf.top = df.top = mUnrestrictedScreenTop;
-                        pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
-                        pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                        pf.left = df.left = mOverscanScreenLeft;
+                        pf.top = df.top = mOverscanScreenTop;
+                        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
                     } else {
-                        pf.left = df.left = mRestrictedScreenLeft;
-                        pf.top = df.top = mRestrictedScreenTop;
-                        pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
-                        pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
+                        pf.left = df.left = mRestrictedOverscanScreenLeft;
+                        pf.top = df.top = mRestrictedOverscanScreenTop;
+                        pf.right = df.right = mRestrictedOverscanScreenLeft
+                                + mRestrictedOverscanScreenWidth;
+                        pf.bottom = df.bottom = mRestrictedOverscanScreenTop
+                                + mRestrictedOverscanScreenHeight;
                     }
 
                     if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
@@ -2793,10 +2829,10 @@
                     pf.top = df.top = cf.top = mUnrestrictedScreenTop;
                     pf.right = df.right = cf.right = hasNavBar
                                         ? mRestrictedScreenLeft+mRestrictedScreenWidth
-                                        : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                                        : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = cf.bottom = hasNavBar
                                           ? mRestrictedScreenTop+mRestrictedScreenHeight
-                                          : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                                          : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     if (DEBUG_LAYOUT) {
                         Log.v(TAG, String.format(
                                     "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
@@ -2807,8 +2843,8 @@
                     // The navigation bar has Real Ultimate Power.
                     pf.left = df.left = mUnrestrictedScreenLeft;
                     pf.top = df.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                    pf.right = df.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     if (DEBUG_LAYOUT) {
                         Log.v(TAG, String.format(
                                     "Laying out navigation bar window: (%d,%d - %d,%d)",
@@ -2818,18 +2854,37 @@
                                 || attrs.type == TYPE_BOOT_PROGRESS)
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
                     // Fullscreen secure system overlays get what they ask for.
-                    pf.left = df.left = mUnrestrictedScreenLeft;
-                    pf.top = df.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                    pf.left = df.left = mOverscanScreenLeft;
+                    pf.top = df.top = mOverscanScreenTop;
+                    pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
                 } else if (attrs.type == TYPE_BOOT_PROGRESS
                         || attrs.type == TYPE_UNIVERSE_BACKGROUND) {
                     // Boot progress screen always covers entire display.
-                    pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
-                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.left = df.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = cf.right = mOverscanScreenLeft + mOverscanScreenWidth;
                     pf.bottom = df.bottom = cf.bottom
-                            = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                            = mOverscanScreenTop + mOverscanScreenHeight;
+                } else if (attrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+                    // The wallpaper mostly goes into the overscan region.
+                    pf.left = df.left = cf.left = mRestrictedOverscanScreenLeft;
+                    pf.top = df.top = cf.top = mRestrictedOverscanScreenTop;
+                    pf.right = df.right = cf.right
+                            = mRestrictedOverscanScreenLeft + mRestrictedOverscanScreenWidth;
+                    pf.bottom = df.bottom = cf.bottom
+                            = mRestrictedOverscanScreenTop + mRestrictedOverscanScreenHeight;
+                } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
+                        && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                        && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                    // Asking to layout into the overscan region, so give it that pure
+                    // unrestricted area.
+                    pf.left = df.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = cf.right
+                            = mOverscanScreenLeft + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = cf.bottom
+                            = mOverscanScreenTop + mOverscanScreenHeight;
                 } else if (mCanHideNavigationBar
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
@@ -2843,9 +2898,9 @@
                     // what the screen would be if only laying out to hide the nav bar.
                     pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
                     pf.top = df.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.right = df.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = cf.bottom
-                            = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                            = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                 } else {
                     pf.left = df.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -4661,6 +4716,22 @@
         pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
                 pw.print(" mScreenOnFully="); pw.print(mScreenOnFully);
                 pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled);
+        pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
+                pw.print(","); pw.print(mOverscanScreenTop);
+                pw.print(") "); pw.print(mOverscanScreenWidth);
+                pw.print("x"); pw.println(mOverscanScreenHeight);
+        if (mOverscanLeft != 0 || mOverscanTop != 0
+                || mOverscanRight != 0 || mOverscanBottom != 0) {
+            pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
+                    pw.print(" top="); pw.print(mOverscanTop);
+                    pw.print(" right="); pw.print(mOverscanRight);
+                    pw.print(" bottom="); pw.println(mOverscanBottom);
+        }
+        pw.print(prefix); pw.print("mRestrictedOverscanScreen=(");
+                pw.print(mRestrictedOverscanScreenLeft);
+                pw.print(","); pw.print(mRestrictedOverscanScreenTop);
+                pw.print(") "); pw.print(mRestrictedOverscanScreenWidth);
+                pw.print("x"); pw.println(mRestrictedOverscanScreenHeight);
         pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
                 pw.print(","); pw.print(mUnrestrictedScreenTop);
                 pw.print(") "); pw.print(mUnrestrictedScreenWidth);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 27d808b..a0a5f5a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -136,6 +136,16 @@
         mAppWidgetHost = new AppWidgetHost(
                 context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
         mAppWidgetHost.setUserId(mUserId);
+
+        DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        if (dpm != null) {
+            mDisabledFeatures = getDisabledFeatures(dpm);
+            mCameraDisabled = dpm.getCameraDisabled(null);
+        }
+
+        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+
         cleanupAppWidgetIds();
 
         mAppWidgetManager = AppWidgetManager.getInstance(mContext);
@@ -143,14 +153,6 @@
 
         mViewStateManager = new KeyguardViewStateManager(this);
 
-        DevicePolicyManager dpm =
-            (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-            mDisabledFeatures = getDisabledFeatures(dpm);
-            mCameraDisabled = dpm.getCameraDisabled(null);
-        }
-
-        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
         mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
 
@@ -172,19 +174,21 @@
             mCleanupAppWidgetsOnBootCompleted = true;
             return;
         }
-        // Clean up appWidgetIds that are bound to lockscreen, but not actually used
-        // This is only to clean up after another bug: we used to not call
-        // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
-        // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
-        // that are triggered by deleteAppWidgetId, which is why we're doing this
-        int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
-        int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
-        for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
-            int appWidgetId = appWidgetIdsBoundToHost[i];
-            if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
-                Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
-                        + appWidgetId);
-                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+            // Clean up appWidgetIds that are bound to lockscreen, but not actually used
+            // This is only to clean up after another bug: we used to not call
+            // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
+            // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
+            // that are triggered by deleteAppWidgetId, which is why we're doing this
+            int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
+            int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
+            for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
+                int appWidgetId = appWidgetIdsBoundToHost[i];
+                if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
+                    Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
+                            + appWidgetId);
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
             }
         }
     }
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
index 8163ea0..3c3b919 100644
--- a/services/input/SpriteController.cpp
+++ b/services/input/SpriteController.cpp
@@ -22,12 +22,14 @@
 
 #include <cutils/log.h>
 #include <utils/String8.h>
+#include <gui/Surface.h>
 
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkColor.h>
 #include <SkPaint.h>
 #include <SkXfermode.h>
+#include <android/native_window.h>
 
 namespace android {
 
@@ -197,32 +199,33 @@
         if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
                 && update.state.wantSurfaceVisible()) {
             sp<Surface> surface = update.state.surfaceControl->getSurface();
-            Surface::SurfaceInfo surfaceInfo;
-            status_t status = surface->lock(&surfaceInfo);
+            ANativeWindow_Buffer outBuffer;
+            status_t status = surface->lock(&outBuffer, NULL);
             if (status) {
                 ALOGE("Error %d locking sprite surface before drawing.", status);
             } else {
                 SkBitmap surfaceBitmap;
-                ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
+                ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
                 surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                        surfaceInfo.w, surfaceInfo.h, bpr);
-                surfaceBitmap.setPixels(surfaceInfo.bits);
+                        outBuffer.width, outBuffer.height, bpr);
+                surfaceBitmap.setPixels(outBuffer.bits);
 
-                SkCanvas surfaceCanvas(surfaceBitmap);
+                SkCanvas surfaceCanvas;
+                surfaceCanvas.setBitmapDevice(surfaceBitmap);
 
                 SkPaint paint;
                 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
                 surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
 
-                if (surfaceInfo.w > uint32_t(update.state.icon.bitmap.width())) {
+                if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) {
                     paint.setColor(0); // transparent fill color
                     surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
-                            surfaceInfo.w, update.state.icon.bitmap.height(), paint);
+                            outBuffer.width, update.state.icon.bitmap.height(), paint);
                 }
-                if (surfaceInfo.h > uint32_t(update.state.icon.bitmap.height())) {
+                if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) {
                     paint.setColor(0); // transparent fill color
                     surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
-                            surfaceInfo.w, surfaceInfo.h, paint);
+                            outBuffer.width, outBuffer.height, paint);
                 }
 
                 status = surface->unlockAndPost();
@@ -370,8 +373,7 @@
     sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
             String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
             ISurfaceComposerClient::eHidden);
-    if (surfaceControl == NULL || !surfaceControl->isValid()
-            || !surfaceControl->getSurface()->isValid()) {
+    if (surfaceControl == NULL || !surfaceControl->isValid()) {
         ALOGE("Error creating sprite surface.");
         return NULL;
     }
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 235c662..3dade37 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -126,6 +126,7 @@
                     -LOG_SIZE, "APANIC_CONSOLE");
             addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
                     -LOG_SIZE, "APANIC_THREADS");
+            addAuditErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_AUDIT");
         } else {
             if (db != null) db.addText("SYSTEM_RESTART", headers);
         }
@@ -174,4 +175,32 @@
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
         db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
     }
+
+    private static void addAuditErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,
+            String headers, int maxSize, String tag) throws IOException {
+        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
+        Slog.i(TAG, "Copying audit failures to DropBox");
+
+        File file = new File("/proc/last_kmsg");
+        long fileTime = file.lastModified();
+        if (fileTime <= 0) return;  // File does not exist
+
+        if (prefs != null) {
+            long lastTime = prefs.getLong(tag, 0);
+            if (lastTime == fileTime) return;  // Already logged this particular file
+            // TODO: move all these SharedPreferences Editor commits
+            // outside this function to the end of logBootEvents
+            prefs.edit().putLong(tag, fileTime).apply();
+        }
+
+        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        StringBuilder sb = new StringBuilder();
+        for (String line : log.split("\n")) {
+            if (line.contains("audit")) {
+                sb.append(line + "\n");
+            }
+        }
+        Slog.i(TAG, "Copied " + sb.toString().length() + " worth of audits to DropBox");
+        db.addText(tag, headers + sb.toString());
+    }
 }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6efe4c5..6d817a1 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -32,7 +31,6 @@
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
-import android.app.Activity;
 import android.bluetooth.BluetoothTetheringDataTracker;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -88,7 +86,6 @@
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
-import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseIntArray;
 
@@ -1315,7 +1312,13 @@
             if (usedNetworkType != networkType) {
                 Integer currentPid = new Integer(pid);
                 mNetRequestersPids[usedNetworkType].remove(currentPid);
-                reassessPidDns(pid, true);
+
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    reassessPidDns(pid, true);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
                 flushVmDnsCache();
                 if (mNetRequestersPids[usedNetworkType].size() != 0) {
                     if (VDBG) {
@@ -3330,12 +3333,15 @@
 
     @Override
     public boolean updateLockdownVpn() {
-        enforceSystemUid();
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
+            return false;
+        }
 
         // Tear down existing lockdown if profile was removed
         mLockdownEnabled = LockdownVpnTracker.isEnabled();
         if (mLockdownEnabled) {
-            if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
+            if (!mKeyStore.isUnlocked()) {
                 Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker");
                 return false;
             }
@@ -3381,11 +3387,4 @@
             throw new IllegalStateException("Unavailable in lockdown mode");
         }
     }
-
-    private static void enforceSystemUid() {
-        final int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID) {
-            throw new SecurityException("Only available to AID_SYSTEM");
-        }
-    }
 }
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 94a087a..016c561 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -16,9 +16,6 @@
 
 package com.android.server;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -40,12 +37,17 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.text.format.Formatter;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TimeUtils;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * This class implements a service to monitor the amount of disk
  * storage space on the device.  If the free storage on device is less
@@ -66,17 +68,18 @@
  */
 public class DeviceStorageMonitorService extends Binder {
     private static final String TAG = "DeviceStorageMonitorService";
+
     private static final boolean DEBUG = false;
     private static final boolean localLOGV = false;
+
     private static final int DEVICE_MEMORY_WHAT = 1;
     private static final int MONITOR_INTERVAL = 1; //in minutes
     private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
-    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
-    private static final int DEFAULT_THRESHOLD_MAX_BYTES = 500*1024*1024; // 500MB
+
     private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes
     private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
     private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
-    private static final int DEFAULT_FULL_THRESHOLD_BYTES = 1024*1024; // 1MB
+
     private long mFreeMem;  // on /data
     private long mFreeMemAfterLastCacheClear;  // on /data
     private long mLastReportedFreeMem;
@@ -84,14 +87,16 @@
     private boolean mLowMemFlag=false;
     private boolean mMemFullFlag=false;
     private Context mContext;
-    private ContentResolver mContentResolver;
+    private ContentResolver mResolver;
     private long mTotalMemory;  // on /data
     private StatFs mDataFileStats;
     private StatFs mSystemFileStats;
     private StatFs mCacheFileStats;
-    private static final String DATA_PATH = "/data";
-    private static final String SYSTEM_PATH = "/system";
-    private static final String CACHE_PATH = "/cache";
+
+    private static final File DATA_PATH = Environment.getDataDirectory();
+    private static final File SYSTEM_PATH = Environment.getRootDirectory();
+    private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
+
     private long mThreadStartTime = -1;
     private boolean mClearSucceeded = false;
     private boolean mClearingCache;
@@ -116,7 +121,7 @@
     // more files than absolutely needed, to reduce the frequency that
     // flushing takes place.
     private long mMemCacheTrimToThreshold;
-    private int mMemFullThreshold;
+    private long mMemFullThreshold;
 
     /**
      * This string is used for ServiceManager access to this class.
@@ -151,7 +156,7 @@
 
     private final void restatDataDir() {
         try {
-            mDataFileStats.restat(DATA_PATH);
+            mDataFileStats.restat(DATA_PATH.getAbsolutePath());
             mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
                 mDataFileStats.getBlockSize();
         } catch (IllegalArgumentException e) {
@@ -163,7 +168,7 @@
             mFreeMem = Long.parseLong(debugFreeMem);
         }
         // Read the log interval from secure settings
-        long freeMemLogInterval = Settings.Global.getLong(mContentResolver,
+        long freeMemLogInterval = Settings.Global.getLong(mResolver,
                 Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
                 DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000;
         //log the amount of free memory in event log
@@ -173,14 +178,14 @@
             mLastReportedFreeMemTime = currTime;
             long mFreeSystem = -1, mFreeCache = -1;
             try {
-                mSystemFileStats.restat(SYSTEM_PATH);
+                mSystemFileStats.restat(SYSTEM_PATH.getAbsolutePath());
                 mFreeSystem = (long) mSystemFileStats.getAvailableBlocks() *
                     mSystemFileStats.getBlockSize();
             } catch (IllegalArgumentException e) {
                 // ignore; report -1
             }
             try {
-                mCacheFileStats.restat(CACHE_PATH);
+                mCacheFileStats.restat(CACHE_PATH.getAbsolutePath());
                 mFreeCache = (long) mCacheFileStats.getAvailableBlocks() *
                     mCacheFileStats.getBlockSize();
             } catch (IllegalArgumentException e) {
@@ -190,7 +195,7 @@
                                 mFreeMem, mFreeSystem, mFreeCache);
         }
         // Read the reporting threshold from secure settings
-        long threshold = Settings.Global.getLong(mContentResolver,
+        long threshold = Settings.Global.getLong(mResolver,
                 Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
                 DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD);
         // If mFree changed significantly log the new value
@@ -303,40 +308,6 @@
                 delay);
     }
 
-    /*
-     * just query settings to retrieve the memory threshold.
-     * Preferred this over using a ContentObserver since Settings.Secure caches the value
-     * any way
-     */
-    private long getMemThreshold() {
-        long value = Settings.Global.getInt(
-                              mContentResolver,
-                              Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
-                              DEFAULT_THRESHOLD_PERCENTAGE);
-        if(localLOGV) Slog.v(TAG, "Threshold Percentage="+value);
-        value = (value*mTotalMemory)/100;
-        long maxValue = Settings.Global.getInt(
-                mContentResolver,
-                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
-                DEFAULT_THRESHOLD_MAX_BYTES);
-        //evaluate threshold value
-        return value < maxValue ? value : maxValue;
-    }
-
-    /*
-     * just query settings to retrieve the memory full threshold.
-     * Preferred this over using a ContentObserver since Settings.Secure caches the value
-     * any way
-     */
-    private int getMemFullThreshold() {
-        int value = Settings.Global.getInt(
-                              mContentResolver,
-                              Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
-                              DEFAULT_FULL_THRESHOLD_BYTES);
-        if(localLOGV) Slog.v(TAG, "Full Threshold Bytes="+value);
-        return value;
-    }
-
     /**
     * Constructor to run service. initializes the disk space threshold value
     * and posts an empty message to kickstart the process.
@@ -344,11 +315,11 @@
     public DeviceStorageMonitorService(Context context) {
         mLastReportedFreeMemTime = 0;
         mContext = context;
-        mContentResolver = mContext.getContentResolver();
+        mResolver = mContext.getContentResolver();
         //create StatFs object
-        mDataFileStats = new StatFs(DATA_PATH);
-        mSystemFileStats = new StatFs(SYSTEM_PATH);
-        mCacheFileStats = new StatFs(CACHE_PATH);
+        mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
+        mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
+        mCacheFileStats = new StatFs(CACHE_PATH.getAbsolutePath());
         //initialize total storage on device
         mTotalMemory = (long)mDataFileStats.getBlockCount() *
                         mDataFileStats.getBlockSize();
@@ -360,9 +331,12 @@
         mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
         mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
         // cache storage thresholds
-        mMemLowThreshold = getMemThreshold();
-        mMemFullThreshold = getMemFullThreshold();
+        final StorageManager sm = StorageManager.from(context);
+        mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
+        mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
+
         mMemCacheStartTrimThreshold = ((mMemLowThreshold*3)+mMemFullThreshold)/4;
         mMemCacheTrimToThreshold = mMemLowThreshold
                 + ((mMemLowThreshold-mMemCacheStartTrimThreshold)*2);
@@ -373,7 +347,6 @@
         mCacheFileDeletedObserver.startWatching();
     }
 
-
     /**
     * This method sends a notification to NotificationManager to display
     * an error dialog indicating low disk space and launch the Installer
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1a8641b..6ba5cff 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -731,7 +731,8 @@
         }
     }
 
-    private void resetAllInternalStateLocked(final boolean updateOnlyWhenLocaleChanged) {
+    private void resetAllInternalStateLocked(final boolean updateOnlyWhenLocaleChanged,
+            final boolean resetDefaultEnabledIme) {
         if (!mSystemReady) {
             // not system ready
             return;
@@ -749,8 +750,7 @@
             }
             // InputMethodAndSubtypeListManager should be reset when the locale is changed.
             mImListManager = new InputMethodAndSubtypeListManager(mContext, this);
-            buildInputMethodListLocked(mMethodList, mMethodMap,
-                    updateOnlyWhenLocaleChanged /* resetDefaultEnabledIme */);
+            buildInputMethodListLocked(mMethodList, mMethodMap, resetDefaultEnabledIme);
             if (!updateOnlyWhenLocaleChanged) {
                 final String selectedImiId = mSettings.getSelectedInputMethod();
                 if (TextUtils.isEmpty(selectedImiId)) {
@@ -775,14 +775,21 @@
     }
 
     private void checkCurrentLocaleChangedLocked() {
-        resetAllInternalStateLocked(true);
+        resetAllInternalStateLocked(true /* updateOnlyWhenLocaleChanged */,
+                true /* resetDefaultImeLocked */);
     }
 
     private void switchUserLocked(int newUserId) {
         mSettings.setCurrentUserId(newUserId);
         // InputMethodFileManager should be reset when the user is changed
         mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
-        resetAllInternalStateLocked(false);
+        final String defaultImiId = mSettings.getSelectedInputMethod();
+        final boolean needsToResetDefaultIme = TextUtils.isEmpty(defaultImiId);
+        if (DEBUG) {
+            Slog.d(TAG, "Switch user: " + newUserId + " current ime = " + defaultImiId);
+        }
+        resetAllInternalStateLocked(false  /* updateOnlyWhenLocaleChanged */,
+                needsToResetDefaultIme);
     }
 
     @Override
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 29e4c43..25ed27a 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1120,19 +1120,31 @@
     @Override
     public NetworkStats getNetworkStatsSummaryDev() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        return mStatsFactory.readNetworkStatsSummaryDev();
+        try {
+            return mStatsFactory.readNetworkStatsSummaryDev();
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
     }
 
     @Override
     public NetworkStats getNetworkStatsSummaryXt() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        return mStatsFactory.readNetworkStatsSummaryXt();
+        try {
+            return mStatsFactory.readNetworkStatsSummaryXt();
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
     }
 
     @Override
     public NetworkStats getNetworkStatsDetail() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        return mStatsFactory.readNetworkStatsDetail(UID_ALL);
+        try {
+            return mStatsFactory.readNetworkStatsDetail(UID_ALL);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
     }
 
     @Override
@@ -1289,7 +1301,11 @@
     @Override
     public NetworkStats getNetworkStatsUidDetail(int uid) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        return mStatsFactory.readNetworkStatsDetail(uid);
+        try {
+            return mStatsFactory.readNetworkStatsDetail(uid);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 13bf39f..9f2685b 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -26,6 +26,7 @@
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
+import android.app.INotificationListener;
 import android.app.ITransientNotification;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -151,6 +152,7 @@
     private boolean mInCall = false;
     private boolean mNotificationPulseEnabled;
 
+    // used as a mutex for access to all active notifications & listeners
     private final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
 
@@ -161,6 +163,8 @@
 
     private final AppOpsManager mAppOps;
 
+    private ArrayList<NotificationListenerInfo> mListeners = new ArrayList<NotificationListenerInfo>();
+
     // Notification control database. For now just contains disabled packages.
     private AtomicFile mPolicyFile;
     private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -174,6 +178,38 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
+    private class NotificationListenerInfo implements DeathRecipient {
+        INotificationListener listener;
+        int userid;
+        public NotificationListenerInfo(INotificationListener listener, int userid) {
+            this.listener = listener;
+            this.userid = userid;
+        }
+
+        public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
+            if (this.userid != sbn.getUserId()) return;
+            try {
+                listener.onNotificationPosted(sbn);
+            } catch (RemoteException ex) {
+                // not there?
+            }
+        }
+
+        public void notifyRemovedIfUserMatch(StatusBarNotification sbn) {
+            if (this.userid != sbn.getUserId()) return;
+            try {
+                listener.onNotificationRemoved(sbn);
+            } catch (RemoteException ex) {
+                // not there?
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            unregisterListener(this.listener, this.userid);
+        }
+    }
+
     private static class Archive {
         static final int BUFFER_SIZE = 1000;
         ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
@@ -406,6 +442,56 @@
         return tmp;
     }
 
+    @Override
+    public void registerListener(final INotificationListener listener, final int userid) {
+        checkCallerIsSystem();
+        synchronized (mNotificationList) {
+            try {
+                NotificationListenerInfo info = new NotificationListenerInfo(listener, userid);
+                listener.asBinder().linkToDeath(info, 0);
+                mListeners.add(info);
+            } catch (RemoteException e) {
+                // already dead
+            }
+        }
+    }
+
+    @Override
+    public void unregisterListener(INotificationListener listener, int userid) {
+        checkCallerIsSystem();
+        synchronized (mNotificationList) {
+            final int N = mListeners.size();
+            for (int i=N-1; i>=0; i--) {
+                final NotificationListenerInfo info = mListeners.get(i);
+                if (info.listener == listener && info.userid == userid) {
+                    mListeners.remove(listener);
+                }
+            }
+        }
+    }
+
+    private void notifyPostedLocked(NotificationRecord n) {
+        final StatusBarNotification sbn = n.sbn;
+        for (final NotificationListenerInfo info : mListeners) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    info.notifyPostedIfUserMatch(sbn);
+                }});
+        }
+    }
+
+    private void notifyRemovedLocked(NotificationRecord n) {
+        final StatusBarNotification sbn = n.sbn;
+        for (final NotificationListenerInfo info : mListeners) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    info.notifyRemovedIfUserMatch(sbn);
+                }});
+        }
+    }
+
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
@@ -1165,6 +1251,8 @@
 
                 // finally, keep some of this information around for later use
                 mArchive.record(n);
+
+                notifyPostedLocked(r);
             } else {
                 Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
                 if (old != null && old.statusBarKey != null) {
@@ -1175,6 +1263,8 @@
                     finally {
                         Binder.restoreCallingIdentity(identity);
                     }
+
+                    notifyRemovedLocked(r);
                 }
                 return; // do not play sounds, show lights, etc. for invalid notifications
             }
@@ -1341,6 +1431,7 @@
                 Binder.restoreCallingIdentity(identity);
             }
             r.statusBarKey = null;
+            notifyRemovedLocked(r);
         }
 
         // sound
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index e5cba62..9c518a1 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -718,7 +718,7 @@
         synchronized (mLock) {
             // Disconnect from services for the old user.
             UserState oldUserState = getUserStateLocked(mCurrentUserId);
-            unbindAllServicesLocked(oldUserState);
+            oldUserState.onSwitchToAnotherUser();
 
             // Disable the local managers for the old user.
             if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
@@ -737,11 +737,14 @@
             if (userState.mUiAutomationService != null) {
                 // Switching users disables the UI automation service.
                 userState.mUiAutomationService.binderDied();
-            } else if (readConfigurationForUserStateLocked(userState)) {
-                // Update the user state if needed.
-               onUserStateChangedLocked(userState);
             }
 
+            readConfigurationForUserStateLocked(userState);
+            // Even if reading did not yield change, we have to update
+            // the state since the context in which the current user
+            // state was used has changed since it was inactive.
+            onUserStateChangedLocked(userState);
+
             if (announceNewUser) {
                 // Schedule announcement of the current user if needed.
                 mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED,
@@ -1640,14 +1643,18 @@
 
             if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
                     >= Build.VERSION_CODES.JELLY_BEAN) {
-                mFetchFlags |= (info.flags
-                        & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 ?
-                                AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+                if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
+                    mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+                } else {
+                    mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+                }
             }
 
-            mFetchFlags |= (info.flags
-                    & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0 ?
-                            AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS : 0;
+            if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
+                mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
+            } else {
+                mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
+            }
 
             if (mResolveInfo != null) {
                 mRequestTouchExplorationMode = (info.flags
@@ -2561,11 +2568,21 @@
     private class UserState {
         public final int mUserId;
 
-        public final CopyOnWriteArrayList<Service> mBoundServices = new CopyOnWriteArrayList<Service>();
+        // Non-transient state.
 
         public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
             new RemoteCallbackList<IAccessibilityManagerClient>();
 
+        public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
+                new SparseArray<AccessibilityConnectionWrapper>();
+
+        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
+
+        // Transient state.
+
+        public final CopyOnWriteArrayList<Service> mBoundServices =
+                new CopyOnWriteArrayList<Service>();
+
         public final Map<ComponentName, Service> mComponentNameToServiceMap =
                 new HashMap<ComponentName, Service>();
 
@@ -2579,15 +2596,9 @@
         public final Set<ComponentName> mTouchExplorationGrantedServices =
                 new HashSet<ComponentName>();
 
-        public final SparseArray<AccessibilityConnectionWrapper>
-                mInteractionConnections =
-                new SparseArray<AccessibilityConnectionWrapper>();
-
-        public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
-
         public int mHandledFeedbackTypes = 0;
 
-        public int mLastSentClientState;
+        public int mLastSentClientState = -1;
 
         public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
@@ -2612,6 +2623,34 @@
             }
             return clientState;
         }
+
+        public void onSwitchToAnotherUser() {
+            // Clear UI test automation state.
+            if (mUiAutomationService != null) {
+                mUiAutomationService.binderDied();
+                mUiAutomationService = null;
+                mUiAutomationServiceClient = null;
+            }
+
+            // Unbind all services.
+            unbindAllServicesLocked(this);
+
+            // Clear service management state.
+            mBoundServices.clear();
+            mBindingServices.clear();
+
+            // Clear event management state.
+            mHandledFeedbackTypes = 0;
+            mLastSentClientState = -1;
+
+            // Clear state persisted in settings.
+            mEnabledServices.clear();
+            mTouchExplorationGrantedServices.clear();
+            mIsAccessibilityEnabled = false;
+            mIsTouchExplorationEnabled = false;
+            mIsEnhancedWebAccessibilityEnabled = false;
+            mIsDisplayMagnificationEnabled = false;
+        }
     }
 
     private final class AccessibilityContentObserver extends ContentObserver {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c1b406e..f2d401f 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -471,6 +471,7 @@
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
         if (inHistory && !finishing) {
             if (task != null) {
+                task.removeActivity(this);
                 task.numActivities--;
             }
             if (newTask != null) {
@@ -505,6 +506,7 @@
             inHistory = false;
             if (task != null && !finishing) {
                 task.numActivities--;
+                task = null;
             }
             clearOptionsLocked();
         }
@@ -539,7 +541,7 @@
         ActivityResult r = new ActivityResult(from, resultWho,
         		requestCode, resultCode, resultData);
         if (results == null) {
-            results = new ArrayList();
+            results = new ArrayList<ResultInfo>();
         }
         results.add(r);
     }
@@ -950,6 +952,8 @@
         StringBuilder sb = new StringBuilder(128);
         sb.append("ActivityRecord{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(" t");
+        sb.append(task.taskId);
         sb.append(" u");
         sb.append(userId);
         sb.append(' ');
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4373502..a18a0d1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -54,6 +54,7 @@
 import android.graphics.Bitmap.Config;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -66,6 +67,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Display;
 
 import java.io.FileDescriptor;
@@ -75,6 +77,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 /**
  * State and management of a single stack of activities.
@@ -98,7 +101,8 @@
     static final boolean DEBUG_APP = false;
 
     static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
-    
+    static final boolean VALIDATE_TASK_REPLACE = true;
+
     // How long we wait until giving up on the last activity telling us it
     // is idle.
     static final int IDLE_TIMEOUT = 10*1000;
@@ -137,7 +141,10 @@
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     static final boolean SHOW_APP_STARTING_PREVIEW = true;
-    
+
+    static final boolean FORWARD_ITERATOR = false;
+    static final boolean REVERSE_ITERATOR = true;
+
     enum ActivityState {
         INITIALIZING,
         RESUMED,
@@ -154,7 +161,7 @@
     final boolean mMainStack;
     
     final Context mContext;
-    
+
     /**
      * The back history of all previous (and possibly still
      * running) activities.  It contains #ActivityRecord objects.
@@ -162,6 +169,17 @@
     private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
 
     /**
+     * The back history of all previous (and possibly still
+     * running) activities.  It contains #TaskRecord objects.
+     */
+    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
+
+    /**
+     * Mapping from taskId to TaskRecord
+     */
+    private SparseArray<TaskRecord> mTaskIdToTaskRecord = new SparseArray<TaskRecord>();
+
+    /**
      * Used for validating app tokens with window manager.
      */
     final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
@@ -289,6 +307,12 @@
      */
     boolean mDismissKeyguardOnNextActivity = false;
 
+    /** So we don't have to keep constructing a new object for utility non-nested use. */
+    final ActivityIterator mTmpActivityIterator = new ActivityIterator(FORWARD_ITERATOR, true);
+
+    /** So we don't have to keep constructing a new object for utility non-nested use. */
+    final TaskIterator mTmpTaskIterator = new TaskIterator();
+
     /**
      * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
      * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
@@ -508,30 +532,69 @@
     }
 
     final ActivityRecord isInStackLocked(IBinder token) {
+        ActivityRecord newAr = newIsInStackLocked(token);
+
         ActivityRecord r = ActivityRecord.forToken(token);
         if (mHistory.contains(r)) {
+            if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
+                    "isInStackLocked: mismatch: newAr=" + newAr + " r=" + r);
             return r;
         }
+        if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+                "isInStackLocked: mismatch: newAr!=null");
+        return null;
+    }
+
+    final ActivityRecord newIsInStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r != null) {
+            final TaskRecord task = r.task;
+            if (mTaskHistory.contains(task) && task.mActivities.contains(r)) {
+                return r;
+            }
+        }
         return null;
     }
 
     int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+        int newTaskId = newGetTaskForActivityLocked(token, onlyRoot);
+
         TaskRecord lastTask = null;
         final int N = mHistory.size();
         for (int i = 0; i < N; i++) {
             ActivityRecord r = mHistory.get(i);
             if (r.appToken == token) {
                 if (!onlyRoot || lastTask != r.task) {
+                    if (VALIDATE_TASK_REPLACE && newTaskId != r.task.taskId) Slog.w(TAG,
+                            "getTaskForActivityLocked: mismatch: new=" + newTaskId
+                            + " taskId=" + r.task.taskId);
                     return r.task.taskId;
                 }
+                if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+                    "getTaskForActivityLocked: mismatch: newTaskId=" + newTaskId + " not -1.");
                 return -1;
             }
             lastTask = r.task;
         }
 
+        if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+            "getTaskForActivityLocked: mismatch at end: newTaskId=" + newTaskId + " not -1.");
         return -1;
     }
 
+    int newGetTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r == null) {
+            return -1;
+        }
+        final TaskRecord task = r.task;
+        switch (task.mActivities.indexOf(r)) {
+            case -1: return -1;
+            case 0: return task.taskId;
+            default: return onlyRoot ? -1 : task.taskId;
+        }
+    }
+
     private final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -624,17 +687,29 @@
      * @return whether there are any activities for the specified user.
      */
     final boolean switchUserLocked(int userId, UserStartedState uss) {
+        if (VALIDATE_TOKENS) {
+            validateAppTokensLocked();
+        }
+        final boolean newResult = newSwitchUserLocked(userId, uss);
+
         mCurrentUser = userId;
         mStartingUsers.add(uss);
 
         // Only one activity? Nothing to do...
-        if (mHistory.size() < 2)
+        if (mHistory.size() < 2) {
+            if (VALIDATE_TASK_REPLACE && newResult) Slog.w(TAG,
+                    "switchUserLocked: mismatch: " + newResult + " " + false);
             return false;
+        }
 
         boolean haveActivities = false;
         // Check if the top activity is from the new user.
         ActivityRecord top = mHistory.get(mHistory.size() - 1);
-        if (top.userId == userId) return true;
+        if (top.userId == userId) {
+            if (VALIDATE_TASK_REPLACE && !newResult) Slog.w(TAG,
+                    "switchUserLocked: mismatch: " + newResult + " " + true);
+            return true;
+        }
         // Otherwise, move the user's activities to the top.
         int N = mHistory.size();
         int i = 0;
@@ -651,7 +726,44 @@
             }
         }
         // Transition from the old top to the new top
+        if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                "switchUserLocked: calling resumeTopActivity " + top);
         resumeTopActivityLocked(top);
+        if (VALIDATE_TASK_REPLACE && (newResult != haveActivities)) Slog.w(TAG,
+                    "switchUserLocked: mismatch: " + newResult + " " + haveActivities);
+        return haveActivities;
+    }
+
+    /*
+     * Move the activities around in the stack to bring a user to the foreground.
+     * @return whether there are any activities for the specified user.
+     */
+    final boolean newSwitchUserLocked(int userId, UserStartedState uss) {
+//        mStartingUsers.add(uss);
+        if (mCurrentUser == userId) {
+            return true;
+        }
+        mCurrentUser = userId;
+
+        // Move userId's tasks to the top.
+        boolean haveActivities = false;
+        TaskRecord task = null;
+        int index = mTaskHistory.size();
+        for (int i = 0; i < index; ++i) {
+            task = mTaskHistory.get(i);
+            if (task.userId == userId) {
+                haveActivities = true;
+                mTaskHistory.remove(i);
+                mTaskHistory.add(task);
+                --index;
+            }
+        }
+
+        // task is now the original topmost TaskRecord. Transition from the old top to the new top.
+        ActivityRecord top = task != null ? task.getTopActivity() : null;
+        if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                "newSwitchUserLocked: would call resumeTopActivity " + top);
+//        resumeTopActivityLocked(top);
         return haveActivities;
     }
 
@@ -889,6 +1001,9 @@
             mGoingToSleep.release();
         }
         // Ensure activities are no longer sleeping.
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords();
+        }
         for (int i=mHistory.size()-1; i>=0; i--) {
             ActivityRecord r = mHistory.get(i);
             r.setSleeping(false);
@@ -933,6 +1048,9 @@
 
             // Make sure any stopped but visible activities are now sleeping.
             // This ensures that the activity's onStop() is called.
+            if (VALIDATE_TASK_REPLACE) {
+                verifyActivityRecords();
+            }
             for (int i=mHistory.size()-1; i>=0; i--) {
                 ActivityRecord r = mHistory.get(i);
                 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
@@ -1077,6 +1195,9 @@
         ActivityRecord r = null;
 
         synchronized (mService) {
+            if (VALIDATE_TASK_REPLACE) {
+                verifyActivityRecords();
+            }
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
                 r = mHistory.get(index);
@@ -1094,6 +1215,9 @@
         ActivityRecord r = null;
 
         synchronized (mService) {
+            if (VALIDATE_TASK_REPLACE) {
+                verifyActivityRecords();
+            }
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
                 r = mHistory.get(index);
@@ -1306,6 +1430,9 @@
 
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords();
+        }
         final int count = mHistory.size();
         int i = count-1;
         while (mHistory.get(i) != top) {
@@ -1868,6 +1995,7 @@
                             Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
                                     here);
                         }
+                        r.task.addActivityToTop(r);
                         mHistory.add(addPos, r);
                         r.putInHistory();
                         mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
@@ -1907,6 +2035,7 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
         }
+        r.task.addActivityToTop(r);
         mHistory.add(addPos, r);
         r.putInHistory();
         r.frontOfTask = newTask;
@@ -1986,6 +2115,9 @@
         if (doResume) {
             resumeTopActivityLocked(null);
         }
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords();
+        }
     }
 
     final void validateAppTokensLocked() {
@@ -2107,13 +2239,13 @@
                             if (mService.mCurTask <= 0) {
                                 mService.mCurTask = 1;
                             }
-                            target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
-                                    null, false);
+                            target.setTask(createTaskRecord(mService.mCurTask, target.info, null,
+                                    false), null, false);
                             target.task.affinityIntent = target.intent;
                             if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                                     + " out to new task " + target.task);
                         }
-                        mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
+                        mService.mWindowManager.setAppGroupId(target.appToken, target.task.taskId);
                         if (replyChainEnd < 0) {
                             replyChainEnd = targetI;
                         }
@@ -2145,7 +2277,6 @@
                             }
                             mHistory.remove(srcPos);
                             mHistory.add(dstPos, p);
-                            mService.mWindowManager.moveAppToken(dstPos, p.appToken);
                             mService.mWindowManager.setAppGroupId(p.appToken, taskId);
                             dstPos++;
                             i++;
@@ -2173,8 +2304,7 @@
                             // like these are all in the reply chain.
                             replyChainEnd = targetI+1;
                             while (replyChainEnd < mHistory.size() &&
-                                    (mHistory.get(
-                                                replyChainEnd)).task == task) {
+                                    (mHistory.get(replyChainEnd)).task == task) {
                                 replyChainEnd++;
                             }
                             replyChainEnd--;
@@ -2297,7 +2427,6 @@
                         if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
                                 + " from " + srcPos + " to " + lastReparentPos
                                 + " in to resetting task " + task);
-                        mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
                         mService.mWindowManager.setAppGroupId(p.appToken, taskId);
                     }
                     // TODO: This is wrong because it doesn't take lastReparentPos into account.
@@ -2348,6 +2477,9 @@
             }
         }
 
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords();
+        }
         return taskTop;
     }
     
@@ -3013,7 +3145,7 @@
                 if (mService.mCurTask <= 0) {
                     mService.mCurTask = 1;
                 }
-                r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+                r.setTask(createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                         + " in new task " + r.task);
             } else {
@@ -3077,7 +3209,7 @@
                 N > 0 ? mHistory.get(N-1) : null;
             r.setTask(prev != null
                     ? prev.task
-                    : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+                    : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
@@ -4162,6 +4294,9 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Removing activity " + r + " from stack");
         }
+        if (r.task != null) {
+            r.task.removeActivity(r);
+        }
         mHistory.remove(r);
         r.takeFromHistory();
         removeTimeoutsForActivityLocked(r);
@@ -4566,7 +4701,6 @@
             updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
         }
 
-        mService.mWindowManager.moveAppTokensToTop(moved);
         mService.mWindowManager.moveTaskToTop(task);
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
@@ -4659,7 +4793,6 @@
             mService.mWindowManager.prepareAppTransition(
                     AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
-        mService.mWindowManager.moveAppTokensToBottom(moved);
         mService.mWindowManager.moveTaskToBottom(task);
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
@@ -5173,4 +5306,185 @@
 
         return starting;
     }
+
+    void verifyActivityRecords() {
+        /* Until we have activity movement implemented for tasks just do the simple test
+        ActivityIterator iterator = new ActivityIterator();
+        int i;
+        int N = mHistory.size();
+        for (i = 0; i < N && iterator.hasNext(); ++i) {
+            ActivityRecord r1 = mHistory.get(i);
+            ActivityRecord r2 = iterator.next();
+            if (r1 != r2) {
+                break;
+            }
+        }
+        if (i != N || iterator.hasNext()) {
+            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+        } */
+        // Simple test
+        ActivityIterator iterator = new ActivityIterator();
+        while (iterator.hasNext()) {
+            ActivityRecord r = iterator.next();
+            if (!mHistory.contains(r)) {
+                break;
+            }
+        }
+        if (iterator.size() != mHistory.size() || iterator.hasNext()) {
+            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+        }
+    }
+
+    private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+            boolean toTop) {
+        TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);
+        if (oldTask != null) {
+            Slog.w(TAG, "createTaskRecord: Reusing taskId=" + taskId + " without removing");
+            mTaskHistory.remove(oldTask);
+        }
+        TaskRecord task = new TaskRecord(taskId, info, intent);
+        mTaskIdToTaskRecord.put(taskId, task);
+        if (toTop) {
+            mTaskHistory.add(task);
+        } else {
+            mTaskHistory.add(0, task);
+        }
+        return task;
+    }
+
+    class TaskIterator implements Iterator<TaskRecord> {
+        private int mCur;
+        private boolean mReverse;
+
+        TaskIterator() {
+            this(FORWARD_ITERATOR);
+        }
+
+        TaskIterator(boolean reverse) {
+            reset(reverse);
+        }
+
+        public void reset(boolean reverse) {
+            mReverse = reverse;
+            mCur = reverse ? mTaskHistory.size() - 1 : 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskHistory.size();
+        }
+
+        @Override
+        public TaskRecord next() {
+            if (hasNext()) {
+                TaskRecord task = mTaskHistory.get(mCur);
+                mCur += (mReverse ? -1 : 1);
+                return task;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    class ActivityIterator implements Iterator<ActivityRecord> {
+        final TaskIterator mIterator;
+        boolean mReverse;
+        int mCur;
+        TaskRecord mTaskRecord;
+        final boolean mSkipFinishing;
+
+        public ActivityIterator() {
+            this(FORWARD_ITERATOR);
+        }
+
+        public ActivityIterator(boolean reverse) {
+            this(reverse, false);
+        }
+
+        public ActivityIterator(boolean reverse, boolean skipFinishing) {
+            mSkipFinishing = skipFinishing;
+            mIterator = new TaskIterator();
+            reset(reverse);
+        }
+
+        public void reset(boolean reverse) {
+            mReverse = reverse;
+            mIterator.reset(reverse);
+            getNextTaskRecord();
+        }
+
+        private void getNextTaskRecord() {
+            if (mIterator.hasNext()) {
+                mTaskRecord = mIterator.next();
+                mCur = mReverse ? mTaskRecord.mActivities.size() - 1 : 0;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (mTaskRecord == null) {
+                return false;
+            }
+            if (mReverse) {
+                return mCur >= 0;
+            }
+            return mCur < mTaskRecord.mActivities.size();
+        }
+
+        @Override
+        public ActivityRecord next() {
+            while (hasNext()) {
+                ActivityRecord r = mTaskRecord.mActivities.get(mCur);
+                mCur += mReverse ? -1 : 1;
+                if (!hasNext()) {
+                    getNextTaskRecord();
+                }
+                if (mSkipFinishing && r.finishing) {
+                    continue;
+                }
+                return r;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        int size() {
+            int size = 0;
+            final TaskIterator iterator = new TaskIterator();
+            while (iterator.hasNext()) {
+                size += iterator.next().mActivities.size();
+            }
+            return size;
+        }
+
+        ActivityRecord peek() {
+            if (mTaskRecord != null && mCur >= 0 && mCur < mTaskRecord.mActivities.size()) {
+                return mTaskRecord.mActivities.get(mCur);
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < mTaskHistory.size(); ++i) {
+                final TaskRecord task = mTaskHistory.get(i);
+                sb.append("task_").append(i).append("-").append(task.mActivities).append(" ");
+            }
+            return sb.toString();
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 1bae9ca..347aa7d 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 class TaskRecord extends ThumbnailHolder {
     final int taskId;       // Unique identifier for this task.
@@ -39,7 +40,11 @@
 
     String stringName;      // caching of toString() result.
     int userId;             // user for which this task was created
-    
+
+    int numFullscreen;      // Number of fullscreen activities.
+
+    final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
+
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
         affinity = info.taskAffinity;
@@ -104,12 +109,49 @@
             userId = UserHandle.getUserId(info.applicationInfo.uid);
         }
     }
-    
+
+    ActivityRecord getTopActivity() {
+        for (int i = mActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = mActivities.get(i);
+            if (r.finishing) {
+                continue;
+            }
+            return r;
+        }
+        return null;
+    }
+
+    void addActivityAtBottom(ActivityRecord r) {
+        if (!mActivities.remove(r) && r.fullscreen) {
+            // Was not previously in list.
+            numFullscreen++;
+        }
+        mActivities.add(0, r);
+    }
+
+    void addActivityToTop(ActivityRecord r) {
+        if (!mActivities.remove(r) && r.fullscreen) {
+            // Was not previously in list.
+            numFullscreen++;
+        }
+        mActivities.add(r);
+    }
+
+    /** @return true if this was the last activity in the task */
+    boolean removeActivity(ActivityRecord r) {
+        if (mActivities.remove(r) && r.fullscreen) {
+            // Was previously in list.
+            numFullscreen--;
+        }
+        return mActivities.size() == 0;
+    }
+
     void dump(PrintWriter pw, String prefix) {
         if (numActivities != 0 || rootWasReset || userId != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                     pw.print(" rootWasReset="); pw.print(rootWasReset);
-                    pw.print(" userId="); pw.println(userId);
+                    pw.print(" userId="); pw.print(userId);
+                    pw.print(" numFullscreen="); pw.println(numFullscreen);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);
@@ -136,6 +178,7 @@
             pw.print(prefix); pw.print("realActivity=");
             pw.println(realActivity.flattenToShortString());
         }
+        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
         if (!askedCompatMode) {
             pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
         }
@@ -146,6 +189,7 @@
                 pw.print((getInactiveDuration()/1000)); pw.println("s)");
     }
 
+    @Override
     public String toString() {
         if (stringName != null) {
             return stringName;
@@ -156,19 +200,21 @@
         sb.append(" #");
         sb.append(taskId);
         if (affinity != null) {
-            sb.append(" A ");
+            sb.append(" A=");
             sb.append(affinity);
         } else if (intent != null) {
-            sb.append(" I ");
+            sb.append(" I=");
             sb.append(intent.getComponent().flattenToShortString());
         } else if (affinityIntent != null) {
-            sb.append(" aI ");
+            sb.append(" aI=");
             sb.append(affinityIntent.getComponent().flattenToShortString());
         } else {
             sb.append(" ??");
         }
-        sb.append(" U ");
+        sb.append(" U=");
         sb.append(userId);
+        sb.append(" sz=");
+        sb.append(mActivities.size());
         sb.append('}');
         return stringName = sb.toString();
     }
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index bb19cc7..bb7334a 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -462,7 +462,7 @@
      * secondary thread to perform connection work, returning quickly.
      */
     public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
-        if (keyStore.state() != KeyStore.State.UNLOCKED) {
+        if (!keyStore.isUnlocked()) {
             throw new IllegalStateException("KeyStore isn't unlocked");
         }
 
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index a3ab3c1..4161147 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
 
@@ -122,7 +123,7 @@
     public final void setLayerStackInTransactionLocked(int layerStack) {
         if (mCurrentLayerStack != layerStack) {
             mCurrentLayerStack = layerStack;
-            Surface.setDisplayLayerStack(mDisplayToken, layerStack);
+            SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack);
         }
     }
 
@@ -155,7 +156,7 @@
             }
             mCurrentDisplayRect.set(displayRect);
 
-            Surface.setDisplayProjection(mDisplayToken,
+            SurfaceControl.setDisplayProjection(mDisplayToken,
                     orientation, layerStackRect, displayRect);
         }
     }
@@ -166,7 +167,7 @@
     public final void setSurfaceInTransactionLocked(Surface surface) {
         if (mCurrentSurface != surface) {
             mCurrentSurface = surface;
-            Surface.setDisplaySurface(mDisplayToken, surface);
+            SurfaceControl.setDisplaySurface(mDisplayToken, surface);
         }
     }
 
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 813c9c7..17b0662 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -324,6 +324,18 @@
     }
 
     /**
+     * Sets the overscan insets for a particular display.
+     */
+    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null) {
+                display.setOverscan(left, top, right, bottom);
+            }
+        }
+    }
+
+    /**
      * Called by the window manager to perform traversals while holding a
      * surface flinger transaction.
      */
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index ee2d617..475f27b 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -25,7 +25,8 @@
 import android.view.Display;
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
-import android.view.Surface.PhysicalDisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.PhysicalDisplayInfo;
 
 import java.io.PrintWriter;
 
@@ -39,15 +40,15 @@
     private static final String TAG = "LocalDisplayAdapter";
 
     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
-            Surface.BUILT_IN_DISPLAY_ID_MAIN,
-            Surface.BUILT_IN_DISPLAY_ID_HDMI,
+            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
+            SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
     };
 
     private final SparseArray<LocalDisplayDevice> mDevices =
             new SparseArray<LocalDisplayDevice>();
     private HotplugDisplayEventReceiver mHotplugReceiver;
 
-    private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
+    private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo();
 
     // Called with SyncRoot lock held.
     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
@@ -67,8 +68,8 @@
     }
 
     private void tryConnectDisplayLocked(int builtInDisplayId) {
-        IBinder displayToken = Surface.getBuiltInDisplay(builtInDisplayId);
-        if (displayToken != null && Surface.getDisplayInfo(displayToken, mTempPhys)) {
+        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
+        if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
             LocalDisplayDevice device = mDevices.get(builtInDisplayId);
             if (device == null) {
                 // Display was added.
@@ -97,20 +98,20 @@
 
     private final class LocalDisplayDevice extends DisplayDevice {
         private final int mBuiltInDisplayId;
-        private final PhysicalDisplayInfo mPhys;
+        private final SurfaceControl.PhysicalDisplayInfo mPhys;
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
         private boolean mBlanked;
 
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
-                PhysicalDisplayInfo phys) {
+                SurfaceControl.PhysicalDisplayInfo phys) {
             super(LocalDisplayAdapter.this, displayToken);
             mBuiltInDisplayId = builtInDisplayId;
-            mPhys = new PhysicalDisplayInfo(phys);
+            mPhys = new SurfaceControl.PhysicalDisplayInfo(phys);
         }
 
-        public boolean updatePhysicalDisplayInfoLocked(PhysicalDisplayInfo phys) {
+        public boolean updatePhysicalDisplayInfoLocked(SurfaceControl.PhysicalDisplayInfo phys) {
             if (!mPhys.equals(phys)) {
                 mPhys.copyFrom(phys);
                 mHavePendingChanges = true;
@@ -142,7 +143,7 @@
                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
                 }
 
-                if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) {
+                if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
@@ -172,13 +173,13 @@
         @Override
         public void blankLocked() {
             mBlanked = true;
-            Surface.blankDisplay(getDisplayTokenLocked());
+            SurfaceControl.blankDisplay(getDisplayTokenLocked());
         }
 
         @Override
         public void unblankLocked() {
             mBlanked = false;
-            Surface.unblankDisplay(getDisplayTokenLocked());
+            SurfaceControl.unblankDisplay(getDisplayTokenLocked());
         }
 
         @Override
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 1583137..424ec36 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -143,6 +143,19 @@
         }
     }
 
+    public void setOverscan(int left, int top, int right, int bottom) {
+        mInfo.overscanLeft = left;
+        mInfo.overscanTop = top;
+        mInfo.overscanRight = right;
+        mInfo.overscanBottom = bottom;
+        if (mOverrideDisplayInfo != null) {
+            mOverrideDisplayInfo.overscanLeft = left;
+            mOverrideDisplayInfo.overscanTop = top;
+            mOverrideDisplayInfo.overscanRight = right;
+            mOverrideDisplayInfo.overscanBottom = bottom;
+        }
+    }
+
     /**
      * Returns true if the logical display is in a valid state.
      * This method should be checked after calling {@link #updateLocked} to handle the
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index 36e9f74..a18352c 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -30,6 +30,7 @@
 import android.view.Display;
 import android.view.Gravity;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -284,7 +285,7 @@
         @Override
         public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
             synchronized (getSyncRoot()) {
-                IBinder displayToken = Surface.createDisplay(mName, false);
+                IBinder displayToken = SurfaceControl.createDisplay(mName, false);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
                         mWidth, mHeight, refreshRate, mDensityDpi, surfaceTexture);
 
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index c8a44d2..b655b3a 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -41,6 +41,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -332,7 +333,7 @@
 
         String name = display.getFriendlyDisplayName();
         String address = display.getDeviceAddress();
-        IBinder displayToken = Surface.createDisplay(name, secure);
+        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
         mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
                 refreshRate, deviceFlags, address, surface);
         sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 8e19e11..e302e83 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -34,6 +34,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
 import java.io.PrintWriter;
@@ -80,7 +81,8 @@
     private int mDisplayWidth;      // real width, not rotated
     private int mDisplayHeight;     // real height, not rotated
     private SurfaceSession mSurfaceSession;
-    private Surface mSurface;
+    private SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
     private NaturalSurfaceLayout mSurfaceLayout;
     private EGLDisplay mEglDisplay;
     private EGLConfig mEglConfig;
@@ -370,7 +372,7 @@
 
     private boolean captureScreenshotTextureAndSetViewport() {
         // TODO: Use a SurfaceTexture to avoid the extra texture upload.
-        Bitmap bitmap = Surface.screenshot(mDisplayWidth, mDisplayHeight,
+        Bitmap bitmap = SurfaceControl.screenshot(mDisplayWidth, mDisplayHeight,
                 0, ELECTRON_BEAM_LAYER - 1);
         if (bitmap == null) {
             Slog.e(TAG, "Could not take a screenshot!");
@@ -525,32 +527,33 @@
             mSurfaceSession = new SurfaceSession();
         }
 
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
-            if (mSurface == null) {
+            if (mSurfaceControl == null) {
                 try {
                     int flags;
                     if (mMode == MODE_FADE) {
-                        flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
+                        flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN;
                     } else {
-                        flags = Surface.OPAQUE | Surface.HIDDEN;
+                        flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
                     }
-                    mSurface = new Surface(mSurfaceSession,
+                    mSurfaceControl = new SurfaceControl(mSurfaceSession,
                             "ElectronBeam", mDisplayWidth, mDisplayHeight,
                             PixelFormat.OPAQUE, flags);
-                } catch (Surface.OutOfResourcesException ex) {
+                } catch (SurfaceControl.OutOfResourcesException ex) {
                     Slog.e(TAG, "Unable to create surface.", ex);
                     return false;
                 }
             }
 
-            mSurface.setLayerStack(mDisplayLayerStack);
-            mSurface.setSize(mDisplayWidth, mDisplayHeight);
-
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurface);
+            mSurfaceControl.setLayerStack(mDisplayLayerStack);
+            mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
+            mSurface.copyFrom(mSurfaceControl);
+            
+            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
         }
         return true;
     }
@@ -560,6 +563,7 @@
             int[] eglSurfaceAttribList = new int[] {
                     EGL14.EGL_NONE
             };
+            // turn our SurfaceControl into a Surface
             mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
                     eglSurfaceAttribList, 0);
             if (mEglSurface == null) {
@@ -580,16 +584,17 @@
     }
 
     private void destroySurface() {
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             mSurfaceLayout.dispose();
             mSurfaceLayout = null;
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
-                mSurface.destroy();
+                mSurfaceControl.destroy();
+                mSurface.release();
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
             }
-            mSurface = null;
+            mSurfaceControl = null;
             mSurfaceVisible = false;
             mSurfaceAlpha = 0f;
         }
@@ -597,13 +602,13 @@
 
     private boolean showSurface(float alpha) {
         if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
-                mSurface.setLayer(ELECTRON_BEAM_LAYER);
-                mSurface.setAlpha(alpha);
-                mSurface.show();
+                mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER);
+                mSurfaceControl.setAlpha(alpha);
+                mSurfaceControl.show();
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
             }
             mSurfaceVisible = true;
             mSurfaceAlpha = alpha;
@@ -708,17 +713,17 @@
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
         private final DisplayManagerService mDisplayManager;
-        private Surface mSurface;
+        private SurfaceControl mSurfaceControl;
 
-        public NaturalSurfaceLayout(DisplayManagerService displayManager, Surface surface) {
+        public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) {
             mDisplayManager = displayManager;
-            mSurface = surface;
+            mSurfaceControl = surfaceControl;
             mDisplayManager.registerDisplayTransactionListener(this);
         }
 
         public void dispose() {
             synchronized (this) {
-                mSurface = null;
+                mSurfaceControl = null;
             }
             mDisplayManager.unregisterDisplayTransactionListener(this);
         }
@@ -726,27 +731,27 @@
         @Override
         public void onDisplayTransaction() {
             synchronized (this) {
-                if (mSurface == null) {
+                if (mSurfaceControl == null) {
                     return;
                 }
 
                 DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
                 switch (displayInfo.rotation) {
                     case Surface.ROTATION_0:
-                        mSurface.setPosition(0, 0);
-                        mSurface.setMatrix(1, 0, 0, 1);
+                        mSurfaceControl.setPosition(0, 0);
+                        mSurfaceControl.setMatrix(1, 0, 0, 1);
                         break;
                     case Surface.ROTATION_90:
-                        mSurface.setPosition(0, displayInfo.logicalHeight);
-                        mSurface.setMatrix(0, -1, 1, 0);
+                        mSurfaceControl.setPosition(0, displayInfo.logicalHeight);
+                        mSurfaceControl.setMatrix(0, -1, 1, 0);
                         break;
                     case Surface.ROTATION_180:
-                        mSurface.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
-                        mSurface.setMatrix(-1, 0, 0, -1);
+                        mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
+                        mSurfaceControl.setMatrix(-1, 0, 0, -1);
                         break;
                     case Surface.ROTATION_270:
-                        mSurface.setPosition(displayInfo.logicalWidth, 0);
-                        mSurface.setMatrix(0, 1, -1, 0);
+                        mSurfaceControl.setPosition(displayInfo.logicalWidth, 0);
+                        mSurfaceControl.setMatrix(0, 1, -1, 0);
                         break;
                 }
             }
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index ad68307..297324b 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -6,6 +6,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
@@ -38,7 +39,7 @@
     boolean allDrawn;
 
     // Special surface for thumbnail animation.
-    Surface thumbnail;
+    SurfaceControl thumbnail;
     int thumbnailTransactionSeq;
     int thumbnailX;
     int thumbnailY;
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 8fd5209..8cc1d02 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -157,7 +157,7 @@
                         + win.isDrawnLw()
                         + ", isAnimating=" + win.mWinAnimator.isAnimating());
                 if (!win.isDrawnLw()) {
-                    Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mWinAnimator.mSurface
+                    Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mWinAnimator.mSurfaceControl
                             + " pv=" + win.mPolicyVisibility
                             + " mDrawState=" + win.mWinAnimator.mDrawState
                             + " ah=" + win.mAttachedHidden
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 5b77b20..774b165 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.util.Slog;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
 /**
@@ -33,23 +34,25 @@
         final int left;
         final int top;
         final int layer;
-        final Surface surface;
+        final SurfaceControl surface;
 
         BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b, int layerStack)
-                throws Surface.OutOfResourcesException {
+                throws SurfaceControl.OutOfResourcesException {
             left = l;
             top = t;
             this.layer = layer;
             int w = r-l;
             int h = b-t;
+
             if (WindowManagerService.DEBUG_SURFACE_TRACE) {
                 surface = new WindowStateAnimator.SurfaceTrace(session, "BlackSurface("
                         + l + ", " + t + ")",
-                        w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+                        w, h, PixelFormat.OPAQUE, SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             } else {
-                surface = new Surface(session, "BlackSurface",
-                        w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+                surface = new SurfaceControl(session, "BlackSurface",
+                        w, h, PixelFormat.OPAQUE, SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             }
+
             surface.setAlpha(1);
             surface.setLayerStack(layerStack);
             surface.setLayer(layer);
@@ -104,7 +107,7 @@
     }
 
     public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
-            int layer, final int layerStack) throws Surface.OutOfResourcesException {
+            int layer, final int layerStack) throws SurfaceControl.OutOfResourcesException {
         boolean success = false;
 
         mOuterRect = new Rect(outer);
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/java/com/android/server/wm/DimLayer.java
index 88efe2e..9bd36ba 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/java/com/android/server/wm/DimLayer.java
@@ -7,6 +7,7 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
 
@@ -18,7 +19,7 @@
     final DisplayContent mDisplayContent;
 
     /** Actual surface that dims */
-    Surface mDimSurface;
+    SurfaceControl mDimSurface;
 
     /** Last value passed to mDimSurface.setAlpha() */
     float mAlpha = 0;
@@ -47,17 +48,17 @@
     DimLayer(WindowManagerService service, int displayId) {
         if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
         mDisplayContent = service.getDisplayContentLocked(displayId);
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
             if (WindowManagerService.DEBUG_SURFACE_TRACE) {
                 mDimSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession,
                     "DimSurface",
                     16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+                    SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             } else {
-                mDimSurface = new Surface(service.mFxSession, TAG,
+                mDimSurface = new SurfaceControl(service.mFxSession, TAG,
                     16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+                    SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
             }
             if (WindowManagerService.SHOW_TRANSACTIONS ||
                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG,
@@ -66,7 +67,7 @@
         } catch (Exception e) {
             Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
         }
     }
 
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index a592893..938fa5c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,10 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerService.FORWARD_ITERATOR;
+import static com.android.server.wm.WindowManagerService.REVERSE_ITERATOR;
+
+import android.graphics.Rect;
 import android.os.Debug;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -38,7 +42,7 @@
  * WindowManagerService.mWindowMap.
  */
 class DisplayContent {
-    private final static String TAG = "DisplayContent";
+//    private final static String TAG = "DisplayContent";
 
     /** Unique identifier of this stack. */
     private final int mDisplayId;
@@ -73,20 +77,6 @@
     final boolean isDefaultDisplay;
 
     /**
-     * List controlling the ordering of windows in different applications which must
-     * be kept in sync with ActivityManager.
-     */
-    final AppTokenList mAppTokens = new AppTokenList();
-
-    /**
-     * AppWindowTokens in the Z order they were in at the start of an animation. Between
-     * animations this list is maintained in the exact order of mAppTokens. If tokens
-     * are added to mAppTokens during an animation an attempt is made to insert them at the same
-     * logical location in this list. Note that this list is always in sync with mWindows.
-     */
-    AppTokenList mAnimatingAppTokens = new AppTokenList();
-
-    /**
      * Window tokens that are in the process of exiting, but still
      * on screen for animations.
      */
@@ -104,6 +94,8 @@
     ArrayList<TaskList> mTaskLists = new ArrayList<TaskList>();
     SparseArray<TaskList> mTaskIdToTaskList = new SparseArray<TaskList>();
 
+    private final AppTokenIterator mTmpAppIterator = new AppTokenIterator();
+
     /**
      * @param display May not be null.
      */
@@ -140,18 +132,6 @@
      * @param wtoken The token to insert.
      */
     void addAppToken(final int addPos, final AppWindowToken wtoken) {
-        mAppTokens.add(addPos, wtoken);
-
-        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
-            // It was inserted into the beginning or end of mAppTokens. Honor that.
-            mAnimatingAppTokens.add(addPos, wtoken);
-        } else {
-            // Find the item immediately above the mAppTokens insertion point and put the token
-            // immediately below that one in mAnimatingAppTokens.
-            final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
-            mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
-        }
-
         TaskList task = mTaskIdToTaskList.get(wtoken.groupId);
         if (task == null) {
             task = new TaskList(wtoken, this);
@@ -163,8 +143,6 @@
     }
 
     void removeAppToken(final AppWindowToken wtoken) {
-        mAppTokens.remove(wtoken);
-        mAnimatingAppTokens.remove(wtoken);
         final int taskId = wtoken.groupId;
         final TaskList task = mTaskIdToTaskList.get(taskId);
         if (task != null) {
@@ -177,11 +155,6 @@
         }
     }
 
-    void refillAnimatingAppTokens() {
-        mAnimatingAppTokens.clear();
-        mAnimatingAppTokens.addAll(mAppTokens);
-    }
-
     void setAppTaskId(AppWindowToken wtoken, int newTaskId) {
         final int taskId = wtoken.groupId;
         TaskList task = mTaskIdToTaskList.get(taskId);
@@ -204,6 +177,18 @@
         wtoken.groupId = newTaskId;
     }
 
+    /**
+     * Return the utility iterator so we don't have to construct new iterators every time we
+     * iterate.
+     * NOTE: Do not ever nest this call or you will have a bad time!
+     * @param reverse Direction of iterator.
+     * @return The utility iterator.
+     */
+    AppTokenIterator getTmpAppIterator(boolean reverse) {
+        mTmpAppIterator.reset(reverse);
+        return mTmpAppIterator;
+    }
+
     class TaskListsIterator implements Iterator<TaskList> {
         private int mCur;
         private boolean mReverse;
@@ -213,9 +198,12 @@
         }
 
         TaskListsIterator(boolean reverse) {
+            reset(reverse);
+        }
+
+        void reset(boolean reverse) {
             mReverse = reverse;
-            int numTaskLists = mTaskLists.size();
-            mCur = reverse ? numTaskLists - 1 : 0;
+            mCur = reverse ? mTaskLists.size() - 1 : 0;
         }
 
         @Override
@@ -240,21 +228,29 @@
         public void remove() {
             throw new IllegalArgumentException();
         }
+
+        @Override public String toString() {
+            return mTaskLists.toString();
+        }
     }
 
     class AppTokenIterator implements Iterator<AppWindowToken> {
-        final TaskListsIterator mIterator;
-        final boolean mReverse;
+        final TaskListsIterator mIterator = new TaskListsIterator();
+        boolean mReverse;
         int mCur;
         TaskList mTaskList;
 
         public AppTokenIterator() {
-            this(false);
+            this(FORWARD_ITERATOR);
         }
 
         public AppTokenIterator(boolean reverse) {
+            reset(reverse);
+        }
+
+        void reset(boolean reverse) {
             mReverse = reverse;
-            mIterator = new TaskListsIterator(reverse);
+            mIterator.reset(reverse);
             getNextTaskList();
         }
 
@@ -302,30 +298,9 @@
             }
             return size;
         }
-    }
 
-    void verifyAppTokens() {
-        AppTokenIterator iterator = new AppTokenIterator();
-        for (int i = 0; i < mAppTokens.size(); ++i) {
-            if (!iterator.hasNext()) {
-                Slog.e(TAG, "compareAppTokens: More mAppTokens than TaskList tokens. Callers="
-                        + Debug.getCallers(4));
-                while (i < mAppTokens.size()) {
-                    Slog.e(TAG, "compareAppTokens: mAppTokens[" + i + "]=" + mAppTokens.get(i));
-                    i++;
-                }
-                return;
-            }
-            AppWindowToken appToken = mAppTokens.get(i);
-            AppWindowToken taskListToken = iterator.next();
-            if (appToken != taskListToken) {
-                Slog.e(TAG, "compareAppTokens: Mismatch at " + i + " appToken=" + appToken
-                        + " taskListToken=" + taskListToken + ". Callers=" + Debug.getCallers(4));
-            }
-        }
-        if (iterator.hasNext()) {
-            Slog.e(TAG, "compareAppTokens: More TaskList tokens than mAppTokens Callers="
-                    + Debug.getCallers(4));
+        @Override public String toString() {
+            return mIterator.toString();
         }
     }
 
@@ -352,13 +327,17 @@
             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-            if (mAppTokens.size() > 0) {
+            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
+            AppTokenIterator iterator = getTmpAppIterator(REVERSE_ITERATOR);
+            int ndx = iterator.size() - 1;
+            if (ndx >= 0) {
                 pw.println();
                 pw.println("  Application tokens in Z order:");
-                for (int i=mAppTokens.size()-1; i>=0; i--) {
-                    pw.print("  App #"); pw.print(i);
-                            pw.print(' '); pw.print(mAppTokens.get(i)); pw.println(":");
-                    mAppTokens.get(i).dump(pw, "    ");
+                while (iterator.hasNext()) {
+                    AppWindowToken wtoken = iterator.next();
+                    pw.print("  App #"); pw.print(ndx--);
+                            pw.print(' '); pw.print(wtoken); pw.println(":");
+                    wtoken.dump(pw, "    ");
                 }
             }
             if (mExitingTokens.size() > 0) {
@@ -393,7 +372,6 @@
                     pw.println();
                 }
             }
-        pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
         pw.println();
     }
 }
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java
index 61093ad..0f51028 100644
--- a/services/java/com/android/server/wm/DisplayMagnifier.java
+++ b/services/java/com/android/server/wm/DisplayMagnifier.java
@@ -43,6 +43,7 @@
 import android.view.MagnificationSpec;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.animation.DecelerateInterpolator;
@@ -481,7 +482,8 @@
             private final Paint mPaint = new Paint();
 
             private final ValueAnimator mShowHideFrameAnimator;
-            private final Surface mSurface;
+            private final SurfaceControl mSurfaceControl;
+            private final Surface mSurface = new Surface();
 
             private boolean mShown;
             private int mAlpha;
@@ -489,20 +491,21 @@
             private boolean mInvalidated;
 
             public ViewportWindow(Context context) {
-                Surface surface = null;
+                SurfaceControl surfaceControl = null;
                 try {
                     mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
-                    surface = new Surface(mWindowManagerService.mFxSession, SURFACE_TITLE,
-                            mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-                } catch (OutOfResourcesException oore) {
+                    surfaceControl = new SurfaceControl(mWindowManagerService.mFxSession, SURFACE_TITLE,
+                            mTempPoint.x, mTempPoint.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+                } catch (SurfaceControl.OutOfResourcesException oore) {
                     /* ignore */
                 }
-                mSurface = surface;
-                mSurface.setLayerStack(mWindowManager.getDefaultDisplay().getLayerStack());
-                mSurface.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
+                mSurfaceControl = surfaceControl;
+                mSurfaceControl.setLayerStack(mWindowManager.getDefaultDisplay().getLayerStack());
+                mSurfaceControl.setLayer(mWindowManagerService.mPolicy.windowTypeToLayerLw(
                         WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY)
                         * WindowManagerService.TYPE_LAYER_MULTIPLIER);
-                mSurface.setPosition(0, 0);
+                mSurfaceControl.setPosition(0, 0);
+                mSurface.copyFrom(mSurfaceControl);
 
                 TypedValue typedValue = new TypedValue();
                 context.getTheme().resolveAttribute(R.attr.colorActivatedHighlight,
@@ -591,7 +594,7 @@
             public void updateSize() {
                 synchronized (mWindowManagerService.mWindowMap) {
                     mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
-                    mSurface.setSize(mTempPoint.x, mTempPoint.y);
+                    mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y);
                     invalidate(mDirtyRect);
                 }
             }
@@ -641,16 +644,17 @@
                     canvas.drawPath(path, mPaint);
 
                     mSurface.unlockCanvasAndPost(canvas);
-
+                    
                     if (mAlpha > 0) {
-                        mSurface.show();
+                        mSurfaceControl.show();
                     } else {
-                        mSurface.hide();
+                        mSurfaceControl.hide();
                     }
                 }
             }
 
             public void releaseSurface() {
+                mSurfaceControl.release();
                 mSurface.release();
             }
         }
diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/java/com/android/server/wm/DisplaySettings.java
new file mode 100644
index 0000000..34d1a64
--- /dev/null
+++ b/services/java/com/android/server/wm/DisplaySettings.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Current persistent settings about a display
+ */
+public class DisplaySettings {
+    private static final String TAG = WindowManagerService.TAG;
+
+    private final Context mContext;
+    private final AtomicFile mFile;
+    private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
+
+    public static class Entry {
+        public final String name;
+        public int overscanLeft;
+        public int overscanTop;
+        public int overscanRight;
+        public int overscanBottom;
+
+        public Entry(String _name) {
+            name = _name;
+        }
+    }
+
+    public DisplaySettings(Context context) {
+        mContext = context;
+        File dataDir = Environment.getDataDirectory();
+        File systemDir = new File(dataDir, "system");
+        mFile = new AtomicFile(new File(systemDir, "display_settings.xml"));
+    }
+
+    public void getOverscanLocked(String name, Rect outRect) {
+        Entry entry = mEntries.get(name);
+        if (entry != null) {
+            outRect.left = entry.overscanLeft;
+            outRect.top = entry.overscanTop;
+            outRect.right = entry.overscanRight;
+            outRect.bottom = entry.overscanBottom;
+        } else {
+            outRect.set(0, 0, 0, 0);
+        }
+    }
+
+    public void setOverscanLocked(String name, int left, int top, int right, int bottom) {
+        if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+            // Right now all we are storing is overscan; if there is no overscan,
+            // we have no need for the entry.
+            mEntries.remove(name);
+            return;
+        }
+        Entry entry = mEntries.get(name);
+        if (entry == null) {
+            entry = new Entry(name);
+            mEntries.put(name, entry);
+        }
+        entry.overscanLeft = left;
+        entry.overscanTop = top;
+        entry.overscanRight = right;
+        entry.overscanBottom = bottom;
+    }
+
+    public void readSettingsLocked() {
+        FileInputStream stream;
+        try {
+            stream = mFile.openRead();
+        } catch (FileNotFoundException e) {
+            Slog.i(TAG, "No existing display settings " + mFile.getBaseFile()
+                    + "; starting empty");
+            return;
+        }
+        boolean success = false;
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("display")) {
+                    readDisplay(parser);
+                } else {
+                    Slog.w(TAG, "Unknown element under <display-settings>: "
+                            + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+            success = true;
+        } catch (IllegalStateException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "Failed parsing " + e);
+        } finally {
+            if (!success) {
+                mEntries.clear();
+            }
+            try {
+                stream.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    private int getIntAttribute(XmlPullParser parser, String name) {
+        try {
+            String str = parser.getAttributeValue(null, name);
+            return str != null ? Integer.parseInt(str) : 0;
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    private void readDisplay(XmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        String name = parser.getAttributeValue(null, "name");
+        if (name != null) {
+            Entry entry = new Entry(name);
+            entry.overscanLeft = getIntAttribute(parser, "overscanLeft");
+            entry.overscanTop = getIntAttribute(parser, "overscanTop");
+            entry.overscanRight = getIntAttribute(parser, "overscanRight");
+            entry.overscanBottom = getIntAttribute(parser, "overscanBottom");
+            mEntries.put(name, entry);
+        }
+        XmlUtils.skipCurrentTag(parser);
+    }
+
+    public void writeSettingsLocked() {
+        FileOutputStream stream;
+        try {
+            stream = mFile.startWrite();
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write display settings: " + e);
+            return;
+        }
+
+        try {
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(stream, "utf-8");
+            out.startDocument(null, true);
+            out.startTag(null, "display-settings");
+
+            for (Entry entry : mEntries.values()) {
+                out.startTag(null, "display");
+                out.attribute(null, "name", entry.name);
+                if (entry.overscanLeft != 0) {
+                    out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft));
+                }
+                if (entry.overscanTop != 0) {
+                    out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop));
+                }
+                if (entry.overscanRight != 0) {
+                    out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight));
+                }
+                if (entry.overscanBottom != 0) {
+                    out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom));
+                }
+                out.endTag(null, "display");
+            }
+
+            out.endTag(null, "display-settings");
+            out.endDocument();
+            mFile.finishWrite(stream);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write display settings, restoring backup.", e);
+            mFile.failWrite(stream);
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 72fc180..745b886 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -34,6 +34,7 @@
 import android.view.DragEvent;
 import android.view.InputChannel;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
 
@@ -45,7 +46,7 @@
 class DragState {
     final WindowManagerService mService;
     IBinder mToken;
-    Surface mSurface;
+    SurfaceControl mSurfaceControl;
     int mFlags;
     IBinder mLocalWin;
     ClipData mData;
@@ -64,21 +65,21 @@
 
     private final Region mTmpRegion = new Region();
 
-    DragState(WindowManagerService service, IBinder token, Surface surface,
+    DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
             int flags, IBinder localWin) {
         mService = service;
         mToken = token;
-        mSurface = surface;
+        mSurfaceControl = surface;
         mFlags = flags;
         mLocalWin = localWin;
         mNotifiedWindows = new ArrayList<WindowState>();
     }
 
     void reset() {
-        if (mSurface != null) {
-            mSurface.destroy();
+        if (mSurfaceControl != null) {
+            mSurfaceControl.destroy();
         }
-        mSurface = null;
+        mSurfaceControl = null;
         mFlags = 0;
         mLocalWin = null;
         mToken = null;
@@ -293,14 +294,14 @@
         // Move the surface to the given touch
         if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                 WindowManagerService.TAG, ">>> OPEN TRANSACTION notifyMoveLw");
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
-            mSurface.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
+            mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DRAG "
-                    + mSurface + ": pos=(" +
+                    + mSurfaceControl + ": pos=(" +
                     (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                     WindowManagerService.TAG, "<<< CLOSE TRANSACTION notifyMoveLw");
         }
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 71a61c6..5d4ab56 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -27,6 +27,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -43,7 +44,7 @@
 
     final Context mContext;
     final Display mDisplay;
-    Surface mSurface;
+    SurfaceControl mSurfaceControl;
     BlackFrame mCustomBlackFrame;
     BlackFrame mExitingBlackFrame;
     BlackFrame mEnteringBlackFrame;
@@ -127,7 +128,7 @@
     long mHalfwayPoint;
 
     public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
+        pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
                 pw.print(" mWidth="); pw.print(mWidth);
                 pw.print(" mHeight="); pw.println(mHeight);
         if (USE_CUSTOM_BLACK_FRAME) {
@@ -213,41 +214,36 @@
         if (!inTransaction) {
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
         }
 
         try {
             try {
                 if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                    mSurface = new SurfaceTrace(session, "FreezeSurface",
+                    mSurfaceControl = new SurfaceTrace(session, "FreezeSurface",
                             mWidth, mHeight,
-                            PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                            PixelFormat.OPAQUE, SurfaceControl.FX_SURFACE_SCREENSHOT | SurfaceControl.HIDDEN);
                 } else {
-                    mSurface = new Surface(session, "FreezeSurface",
+                    mSurfaceControl = new SurfaceControl(session, "FreezeSurface",
                             mWidth, mHeight,
-                            PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                            PixelFormat.OPAQUE, SurfaceControl.FX_SURFACE_SCREENSHOT | SurfaceControl.HIDDEN);
                 }
-                if (!mSurface.isValid()) {
-                    // Screenshot failed, punt.
-                    mSurface = null;
-                    return;
-                }
-                mSurface.setLayerStack(mDisplay.getLayerStack());
-                mSurface.setLayer(FREEZE_LAYER + 1);
-                mSurface.setAlpha(0);
-                mSurface.show();
-            } catch (Surface.OutOfResourcesException e) {
+                mSurfaceControl.setLayerStack(mDisplay.getLayerStack());
+                mSurfaceControl.setLayer(FREEZE_LAYER + 1);
+                mSurfaceControl.setAlpha(0);
+                mSurfaceControl.show();
+            } catch (SurfaceControl.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
             }
 
             if (WindowManagerService.SHOW_TRANSACTIONS ||
                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  FREEZE " + mSurface + ": CREATE");
+                            "  FREEZE " + mSurfaceControl + ": CREATE");
 
             setRotationInTransaction(originalRotation);
         } finally {
             if (!inTransaction) {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation");
             }
@@ -255,7 +251,7 @@
     }
 
     boolean hasScreenshot() {
-        return mSurface != null;
+        return mSurfaceControl != null;
     }
 
     static int deltaRotation(int oldRotation, int newRotation) {
@@ -265,13 +261,13 @@
     }
 
     private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             matrix.getValues(mTmpFloats);
-            mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
-            mSurface.setMatrix(
+            mSurfaceControl.setPosition(mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+            mSurfaceControl.setMatrix(
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            mSurface.setAlpha(alpha);
+            mSurfaceControl.setAlpha(alpha);
             if (DEBUG_TRANSFORMS) {
                 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
                 float[] dstPnts = new float[4];
@@ -337,7 +333,7 @@
      */
     private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, boolean dismissing) {
-        if (mSurface == null) {
+        if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
         }
@@ -496,7 +492,7 @@
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     WindowManagerService.TAG,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
 
             // Compute the transformation matrix that must be applied
             // the the black frame to make it stay in the initial position
@@ -513,10 +509,10 @@
                 mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3,
                         layerStack);
                 mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
-            } catch (Surface.OutOfResourcesException e) {
+            } catch (SurfaceControl.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         WindowManagerService.TAG,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -527,7 +523,7 @@
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     WindowManagerService.TAG,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
                 // Compute the transformation matrix that must be applied
                 // the the black frame to make it stay in the initial position
@@ -543,10 +539,10 @@
                 mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2,
                         layerStack);
                 mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
-            } catch (Surface.OutOfResourcesException e) {
+            } catch (SurfaceControl.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         WindowManagerService.TAG,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -557,7 +553,7 @@
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     WindowManagerService.TAG,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
 
             try {
                 Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
@@ -565,10 +561,10 @@
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                 mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER,
                         layerStack);
-            } catch (Surface.OutOfResourcesException e) {
+            } catch (SurfaceControl.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         WindowManagerService.TAG,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -584,7 +580,7 @@
     public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight) {
         if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
-        if (mSurface == null) {
+        if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
         }
@@ -602,12 +598,12 @@
 
     public void kill() {
         if (DEBUG_STATE) Slog.v(TAG, "Kill!");
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             if (WindowManagerService.SHOW_TRANSACTIONS ||
                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  FREEZE " + mSurface + ": DESTROY");
-            mSurface.destroy();
-            mSurface = null;
+                            "  FREEZE " + mSurfaceControl + ": DESTROY");
+            mSurfaceControl.destroy();
+            mSurfaceControl = null;
         }
         if (mCustomBlackFrame != null) {
             mCustomBlackFrame.kill();
@@ -865,10 +861,10 @@
             return;
         }
 
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
                 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
-                mSurface.hide();
+                mSurfaceControl.hide();
             }
         }
 
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index 3b4c1ab..e82068c 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -40,6 +40,7 @@
 import android.view.IWindowSession;
 import android.view.InputChannel;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 
@@ -313,19 +314,19 @@
             mService.mDragState.mThumbOffsetY = thumbCenterY;
 
             // Make the surface visible at the proper location
-            final Surface surface = mService.mDragState.mSurface;
+            final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl;
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                     WindowManagerService.TAG, ">>> OPEN TRANSACTION performDrag");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
-                surface.setPosition(touchX - thumbCenterX,
+                surfaceControl.setPosition(touchX - thumbCenterX,
                         touchY - thumbCenterY);
-                surface.setAlpha(.7071f);
-                surface.setLayer(mService.mDragState.getDragLayerLw());
-                surface.setLayerStack(display.getLayerStack());
-                surface.show();
+                surfaceControl.setAlpha(.7071f);
+                surfaceControl.setLayer(mService.mDragState.getDragLayerLw());
+                surfaceControl.setLayerStack(display.getLayerStack());
+                surfaceControl.show();
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                         WindowManagerService.TAG, "<<< CLOSE TRANSACTION performDrag");
             }
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 90bbd08..31628e3 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -24,29 +24,32 @@
 import android.graphics.Region;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
 class StrictModeFlash {
     private static final String TAG = "StrictModeFlash";
 
-    Surface mSurface;
-    int mLastDW;
-    int mLastDH;
-    boolean mDrawNeeded;
-    final int mThickness = 20;
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private int mLastDW;
+    private int mLastDH;
+    private boolean mDrawNeeded;
+    private final int mThickness = 20;
 
     public StrictModeFlash(Display display, SurfaceSession session) {
+        SurfaceControl ctrl = null;
         try {
-            mSurface = new Surface(session, "StrictModeFlash",
-                1, 1, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-        } catch (Surface.OutOfResourcesException e) {
-            return;
+            ctrl = new SurfaceControl(session, "StrictModeFlash",
+                1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            ctrl.setLayerStack(display.getLayerStack());
+            ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);  // one more than Watermark? arbitrary.
+            ctrl.setPosition(0, 0);
+            ctrl.show();
+            mSurface.copyFrom(ctrl);
+        } catch (SurfaceControl.OutOfResourcesException e) {
         }
-
-        mSurface.setLayerStack(display.getLayerStack());
-        mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);  // one more than Watermark? arbitrary.
-        mSurface.setPosition(0, 0);
-        mSurface.show();
+        mSurfaceControl = ctrl;
         mDrawNeeded = true;
     }
 
@@ -88,14 +91,14 @@
     // Note: caller responsible for being inside
     // Surface.openTransaction() / closeTransaction()
     public void setVisibility(boolean on) {
-        if (mSurface == null) {
+        if (mSurfaceControl == null) {
             return;
         }
         drawIfNeeded();
         if (on) {
-            mSurface.show();
+            mSurfaceControl.show();
         } else {
-            mSurface.hide();
+            mSurfaceControl.hide();
         }
     }
 
@@ -105,7 +108,7 @@
         }
         mLastDW = dw;
         mLastDH = dh;
-        mSurface.setSize(dw, dh);
+        mSurfaceControl.setSize(dw, dh);
         mDrawNeeded = true;
     }
 
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
index 5e82af2..1f1dd58 100644
--- a/services/java/com/android/server/wm/TaskGroup.java
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -23,4 +23,9 @@
 public class TaskGroup {
     public int taskId = -1;
     public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
+
+    @Override
+    public String toString() {
+        return "id=" + taskId + " tokens=" + tokens;
+    }
 }
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
index 88791f2..67dfa4f 100644
--- a/services/java/com/android/server/wm/TaskList.java
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -27,4 +27,9 @@
         mAppTokens.add(wtoken);
         mDisplayContent = displayContent;
     }
+
+    @Override
+    public String toString() {
+        return "id=" + taskId + " appTokens=" + mAppTokens;
+    }
 }
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index ac152c9..fedd314 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -28,6 +28,7 @@
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.Surface.OutOfResourcesException;
 
@@ -35,21 +36,20 @@
  * Displays a watermark on top of the window manager's windows.
  */
 class Watermark {
-    final Display mDisplay;
-    final String[] mTokens;
-    final String mText;
-    final Paint mTextPaint;
-    final int mTextWidth;
-    final int mTextHeight;
-    final int mTextAscent;
-    final int mTextDescent;
-    final int mDeltaX;
-    final int mDeltaY;
+    private final Display mDisplay;
+    private final String[] mTokens;
+    private final String mText;
+    private final Paint mTextPaint;
+    private final int mTextWidth;
+    private final int mTextHeight;
+    private final int mDeltaX;
+    private final int mDeltaY;
 
-    Surface mSurface;
-    int mLastDW;
-    int mLastDH;
-    boolean mDrawNeeded;
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private int mLastDW;
+    private int mLastDH;
+    private boolean mDrawNeeded;
 
     Watermark(Display display, DisplayMetrics dm, SurfaceSession session, String[] tokens) {
         if (false) {
@@ -90,8 +90,6 @@
 
         FontMetricsInt fm = mTextPaint.getFontMetricsInt();
         mTextWidth = (int)mTextPaint.measureText(mText);
-        mTextAscent = fm.ascent;
-        mTextDescent = fm.descent;
         mTextHeight = fm.descent - fm.ascent;
 
         mDeltaX = WindowManagerService.getPropertyInt(tokens, 2,
@@ -112,22 +110,25 @@
         mTextPaint.setColor(color);
         mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
 
+        SurfaceControl ctrl = null;
         try {
-            mSurface = new Surface(session, "WatermarkSurface",
-                    1, 1, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-            mSurface.setLayerStack(mDisplay.getLayerStack());
-            mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100);
-            mSurface.setPosition(0, 0);
-            mSurface.show();
-        } catch (OutOfResourcesException e) {
+            ctrl = new SurfaceControl(session, "WatermarkSurface",
+                    1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            ctrl.setLayerStack(mDisplay.getLayerStack());
+            ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100);
+            ctrl.setPosition(0, 0);
+            ctrl.show();
+            mSurface.copyFrom(ctrl);
+        } catch (SurfaceControl.OutOfResourcesException e) {
         }
+        mSurfaceControl = ctrl;
     }
 
     void positionSurface(int dw, int dh) {
         if (mLastDW != dw || mLastDH != dh) {
             mLastDW = dw;
             mLastDH = dh;
-            mSurface.setSize(dw, dh);
+            mSurfaceControl.setSize(dw, dh);
             mDrawNeeded = true;
         }
     }
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 546bf2f..67daf75 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -10,6 +10,8 @@
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
+import static com.android.server.wm.WindowManagerService.FORWARD_ITERATOR;
+import static com.android.server.wm.WindowManagerService.REVERSE_ITERATOR;
 
 import android.content.Context;
 import android.os.Debug;
@@ -22,9 +24,11 @@
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 
+import com.android.server.wm.DisplayContent.AppTokenIterator;
 import com.android.server.wm.WindowManagerService.DisplayContentsIterator;
 import com.android.server.wm.WindowManagerService.LayoutFields;
 
@@ -174,10 +178,9 @@
     private void updateAppWindowsLocked(int displayId) {
         int i;
         final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
-        final AppTokenList appTokens = displayContent.mAnimatingAppTokens;
-        final int NAT = appTokens.size();
-        for (i=0; i<NAT; i++) {
-            final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(FORWARD_ITERATOR);
+        while (iterator.hasNext()) {
+            final AppWindowAnimator appAnimator = iterator.next().mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -222,7 +225,7 @@
             WindowStateAnimator winAnimator = win.mWinAnimator;
             final int flags = winAnimator.mAttrFlags;
 
-            if (winAnimator.mSurface != null) {
+            if (winAnimator.mSurfaceControl != null) {
                 final boolean wasAnimating = winAnimator.mWasAnimating;
                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
 
@@ -370,7 +373,7 @@
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
             WindowStateAnimator winAnimator = win.mWinAnimator;
-            if (winAnimator.mSurface == null) {
+            if (winAnimator.mSurfaceControl == null) {
                 continue;
             }
 
@@ -458,11 +461,10 @@
     private void testTokenMayBeDrawnLocked(int displayId) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final AppTokenList appTokens =
-                mService.getDisplayContentLocked(displayId).mAnimatingAppTokens;
-        final int NT = appTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = appTokens.get(i);
+        AppTokenIterator iterator =
+                mService.getDisplayContentLocked(displayId).getTmpAppIterator(FORWARD_ITERATOR);
+        while (iterator.hasNext()) {
+            AppWindowToken wtoken = iterator.next();
             AppWindowAnimator appAnimator = wtoken.mAppAnimator;
             final boolean allDrawn = wtoken.allDrawn;
             if (allDrawn != appAnimator.allDrawn) {
@@ -529,8 +531,8 @@
 
         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
                 TAG, ">>> OPEN TRANSACTION animateLocked");
-        Surface.openTransaction();
-        Surface.setAnimationTransaction();
+        SurfaceControl.openTransaction();
+        SurfaceControl.setAnimationTransaction();
         try {
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
@@ -622,7 +624,7 @@
         } catch (RuntimeException e) {
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
                     TAG, "<<< CLOSE TRANSACTION animateLocked");
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 7efc165..8cbacdc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -132,6 +132,7 @@
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -197,6 +198,7 @@
     static final boolean DEBUG_LAYOUT_REPEATS = true;
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
+    static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -206,6 +208,9 @@
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean localLOGV = DEBUG;
 
+    final static boolean REVERSE_ITERATOR = true;
+    final static boolean FORWARD_ITERATOR = false;
+
     /** How much to multiply the policy's type layer, to reserve room
      * for multiple windows of the same type and Z-ordering adjustment
      * with TYPE_LAYER_OFFSET. */
@@ -315,6 +320,8 @@
 
     final AppOpsManager mAppOps;
 
+    final DisplaySettings mDisplaySettings;
+
     /**
      * All currently active sessions with clients.
      */
@@ -420,6 +427,8 @@
     private SparseArray<DisplayContent> mTaskIdToDisplayContents =
             new SparseArray<DisplayContent>();
 
+    private final AllWindowsIterator mTmpWindowsIterator = new AllWindowsIterator();
+
     int mRotation = 0;
     int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mAltOrientation = false;
@@ -724,6 +733,8 @@
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mDisplayManagerService = displayManager;
         mHeadless = displayManager.isHeadless();
+        mDisplaySettings = new DisplaySettings(context);
+        mDisplaySettings.readSettingsLocked();
 
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         mDisplayManager.registerDisplayListener(this, null);
@@ -780,11 +791,11 @@
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
             createWatermarkInTransaction();
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
         }
     }
 
@@ -887,7 +898,6 @@
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
         final WindowState attached = win.mAttachedWindow;
-        int i;
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
         if (attached == null) {
             int tokenWindowsPos = 0;
@@ -937,13 +947,11 @@
                         + client.asBinder() + " (token=" + token + ")");
                     // Figure out where the window should go, based on the
                     // order of applications.
-                    AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
-                    final int NA = animatingAppTokens.size();
                     WindowState pos = null;
-                    for (i=NA-1; i>=0; i--) {
-                        AppWindowToken t = animatingAppTokens.get(i);
+                    AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
+                    while (iterator.hasNext()) {
+                        AppWindowToken t = iterator.next();
                         if (t == token) {
-                            i--;
                             break;
                         }
 
@@ -976,15 +984,14 @@
                     } else {
                         // Continue looking down until we find the first
                         // token that has windows on this display.
-                        while (i >= 0) {
-                            AppWindowToken t = animatingAppTokens.get(i);
+                        while (iterator.hasNext()) {
+                            AppWindowToken t = iterator.next();
                             tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
                             final int NW = tokenWindowList.size();
                             if (NW > 0) {
                                 pos = tokenWindowList.get(NW-1);
                                 break;
                             }
-                            i--;
                         }
                         if (pos != null) {
                             // Move in front of any windows attached to this
@@ -1003,7 +1010,8 @@
                         } else {
                             // Just search for the start of this layer.
                             final int myLayer = win.mBaseLayer;
-                            for (i=0; i<N; i++) {
+                            int i;
+                            for (i = 0; i < N; i++) {
                                 WindowState w = windows.get(i);
                                 if (w.mBaseLayer > myLayer) {
                                     break;
@@ -1021,7 +1029,8 @@
             } else {
                 // Figure out where window should go, based on layer.
                 final int myLayer = win.mBaseLayer;
-                for (i=N-1; i>=0; i--) {
+                int i;
+                for (i = N - 1; i >= 0; i--) {
                     if (windows.get(i).mBaseLayer <= myLayer) {
                         break;
                     }
@@ -1046,7 +1055,8 @@
             final int sublayer = win.mSubLayer;
             int largestSublayer = Integer.MIN_VALUE;
             WindowState windowWithLargestSublayer = null;
-            for (i=0; i<NA; i++) {
+            int i;
+            for (i = 0; i < NA; i++) {
                 WindowState w = tokenWindowList.get(i);
                 final int wSublayer = w.mSubLayer;
                 if (wSublayer >= largestSublayer) {
@@ -1106,7 +1116,7 @@
             if (DEBUG_INPUT_METHOD) {
                 Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
                 if (!w.isVisibleOrAdding()) {
-                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface
+                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurfaceControl
                             + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
                             + " policyVis=" + w.mPolicyVisibility
                             + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
@@ -2272,14 +2282,14 @@
             TAG, "Remove " + win + " client="
             + Integer.toHexString(System.identityHashCode(
                 win.mClient.asBinder()))
-            + ", surface=" + win.mWinAnimator.mSurface);
+            + ", surface=" + win.mWinAnimator.mSurfaceControl);
 
         final long origId = Binder.clearCallingIdentity();
 
         win.disposeInputChannel();
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(
-                TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurface
+                TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurfaceControl
                 + " mExiting=" + win.mExiting
                 + " isAnimating=" + win.mWinAnimator.isAnimating()
                 + " app-animation="
@@ -2451,22 +2461,15 @@
 
     public void updateAppOpsState() {
         synchronized(mWindowMap) {
-            boolean changed = false;
-            for (int i=0; i<mDisplayContents.size(); i++) {
-                DisplayContent display = mDisplayContents.valueAt(i);
-                WindowList windows = display.getWindowList();
-                for (int j=0; j<windows.size(); j++) {
-                    final WindowState win = windows.get(j);
-                    if (win.mAppOp != AppOpsManager.OP_NONE) {
-                        changed |= win.setAppOpVisibilityLw(mAppOps.checkOpNoThrow(win.mAppOp,
-                                win.getOwningUid(),
-                                win.getOwningPackage()) == AppOpsManager.MODE_ALLOWED);
-                    }
+            mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+            while (mTmpWindowsIterator.hasNext()) {
+                final WindowState win = mTmpWindowsIterator.next();
+                if (win.mAppOp != AppOpsManager.OP_NONE) {
+                    final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
+                            win.getOwningPackage());
+                    win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
                 }
             }
-            if (changed) {
-                scheduleAnimationLocked();
-            }
         }
     }
 
@@ -2479,7 +2482,7 @@
         }
     }
 
-    static void logSurface(Surface s, String title, String msg, RuntimeException where) {
+    static void logSurface(SurfaceControl s, String title, String msg, RuntimeException where) {
         String str = "  SURFACE " + s + ": " + msg + " / " + title;
         if (where != null) {
             Slog.i(TAG, str, where);
@@ -2776,9 +2779,9 @@
                     if (!win.mHasSurface) {
                         surfaceChanged = true;
                     }
-                    Surface surface = winAnimator.createSurfaceLocked();
-                    if (surface != null) {
-                        outSurface.copyFrom(surface);
+                    SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
+                    if (surfaceControl != null) {
+                        outSurface.copyFrom(surfaceControl);
                         if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                 "  OUT SURFACE " + outSurface + ": copied");
                     } else {
@@ -2818,7 +2821,7 @@
                 }
             } else {
                 winAnimator.mEnterAnimationPending = false;
-                if (winAnimator.mSurface != null) {
+                if (winAnimator.mSurfaceControl != null) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
                             + ": mExiting=" + win.mExiting);
                     // If we are not currently running the exit animation, we
@@ -3106,54 +3109,51 @@
     // -------------------------------------------------------------
 
     public void validateAppTokens(List<TaskGroup> tasks) {
-        int t = tasks.size() - 1;
-        if (t < 0) {
-            Slog.w(TAG, "validateAppTokens: empty task list");
-            return;
-        }
-
-        TaskGroup task = tasks.get(0);
-        int taskId = task.taskId;
-        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
-        if (displayContent == null) {
-            Slog.w(TAG, "validateAppTokens: no Display for taskId=" + taskId);
-            return;
-        }
-
-        AppTokenIterator iterator = displayContent.new AppTokenIterator(true);
-        for ( ; t >= 0; --t) {
-            task = tasks.get(t);
-            List<IApplicationToken> tokens = task.tokens;
-            int v = task.tokens.size() - 1;
-
-            DisplayContent lastDisplayContent = displayContent;
-            displayContent = mTaskIdToDisplayContents.get(taskId);
-            if (displayContent != lastDisplayContent) {
-                Slog.w(TAG, "validateAppTokens: displayContent changed in TaskGroup list!");
+        synchronized (mWindowMap) {
+            int t = tasks.size() - 1;
+            if (t < 0) {
+                Slog.w(TAG, "validateAppTokens: empty task list");
                 return;
             }
 
-            while (v >= 0 && iterator.hasNext()) {
-                AppWindowToken atoken = iterator.next();
-                if (atoken.removed) {
-                    continue;
-                }
-                if (tokens.get(v) != atoken.token) {
-                    Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
-                          + " @ " + v + ", internal is " + atoken.token);
-                }
-                v--;
+            TaskGroup task = tasks.get(0);
+            int taskId = task.taskId;
+            DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+            if (displayContent == null) {
+                Slog.w(TAG, "validateAppTokens: no Display for taskId=" + taskId);
+                return;
             }
-            while (v >= 0) {
-                Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
-                v--;
-            }
-        }
 
-        while (iterator.hasNext()) {
-            AppWindowToken atoken = iterator.next();
-            if (!atoken.removed) {
-                Slog.w(TAG, "Invalid internal atoken: " + atoken.token);
+            boolean mismatch = false;
+            AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
+            for ( ; t >= 0 && !mismatch; --t) {
+                task = tasks.get(t);
+                List<IApplicationToken> tokens = task.tokens;
+                int v = task.tokens.size() - 1;
+
+                DisplayContent lastDisplayContent = displayContent;
+                displayContent = mTaskIdToDisplayContents.get(taskId);
+                if (displayContent != lastDisplayContent) {
+                    Slog.w(TAG, "validateAppTokens: displayContent changed in TaskGroup list!");
+                    return;
+                }
+
+                while (v >= 0) {
+                    AppWindowToken atoken = iterator.next();
+                    if (atoken.removed) {
+                        continue;
+                    }
+                    if (tokens.get(v) != atoken.token) {
+                        mismatch = true;
+                        break;
+                    }
+                    v--;
+                }
+            }
+
+            if (mismatch || iterator.hasNext()) {
+                Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks
+                        + " WindowManager=" + iterator);
             }
         }
     }
@@ -3313,7 +3313,6 @@
                 mTaskIdToDisplayContents.put(taskId, displayContent);
             }
             displayContent.addAppToken(addPos, atoken);
-            displayContent.verifyAppTokens();
             mTokenMap.put(token.asBinder(), atoken);
             mTaskIdToDisplayContents.put(taskId, displayContent);
 
@@ -3386,7 +3385,7 @@
         boolean lastFullscreen = false;
         // TODO: Multi window.
         DisplayContent displayContent = getDefaultDisplayContentLocked();
-        AppTokenIterator iterator = displayContent.new AppTokenIterator(true);
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
         while (iterator.hasNext()) {
             AppWindowToken atoken = iterator.next();
 
@@ -4313,7 +4312,6 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
                 displayContent.removeAppToken(wtoken);
-                displayContent.verifyAppTokens();
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4369,7 +4367,7 @@
         while (iterator.hasNext()) {
             DisplayContent displayContent = iterator.next();
             Slog.v(TAG, "  Display " + displayContent.getDisplayId());
-            AppTokenIterator appIterator = displayContent.new AppTokenIterator(true);
+            AppTokenIterator appIterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
             int i = appIterator.size();
             while (appIterator.hasNext()) {
                 Slog.v(TAG, "  #" + --i + ": " + appIterator.next().token);
@@ -4377,53 +4375,39 @@
         }
     }
 
-    void dumpAnimatingAppTokensLocked() {
-        DisplayContentsIterator iterator = new DisplayContentsIterator();
-        while (iterator.hasNext()) {
-            DisplayContent displayContent = iterator.next();
-            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
-            AppTokenList appTokens = displayContent.mAnimatingAppTokens;
-            for (int i=appTokens.size()-1; i>=0; i--) {
-                Slog.v(TAG, "  #" + i + ": " + appTokens.get(i).token);
-            }
-        }
-    }
-
     void dumpWindowsLocked() {
         int i = 0;
-        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
-        while (iterator.hasNext()) {
-            final WindowState w = iterator.next();
+        mTmpWindowsIterator.reset(REVERSE_ITERATOR);
+        while (mTmpWindowsIterator.hasNext()) {
+            final WindowState w = mTmpWindowsIterator.next();
             Slog.v(TAG, "  #" + i++ + ": " + w);
         }
     }
 
-    private int findWindowOffsetLocked(DisplayContent displayContent, int tokenPos) {
+    private int findAppWindowInsertionPointLocked(AppWindowToken target) {
+        final int taskId = target.groupId;
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.w(TAG, "findTopAppWindowLocked: no DisplayContent for " + target);
+            return 0;
+        }
         final WindowList windows = displayContent.getWindowList();
         final int NW = windows.size();
 
-        if (tokenPos >= displayContent.mAnimatingAppTokens.size()) {
-            int i = NW;
-            while (i > 0) {
-                i--;
-                WindowState win = windows.get(i);
-                if (win.getAppToken() != null) {
-                    return i+1;
-                }
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
+        while (iterator.hasNext()) {
+            if (iterator.next() == target) {
+                break;
             }
         }
 
-        final AppTokenList appTokens = displayContent.mAppTokens;
-        while (tokenPos > 0) {
+        while (iterator.hasNext()) {
             // Find the first app token below the new position that has
             // a window displayed.
-            final AppWindowToken wtoken = appTokens.get(tokenPos-1);
-            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
-                    + tokenPos + " -- " + wtoken.token);
+            final AppWindowToken wtoken = iterator.next();
+            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows in " + wtoken.token);
             if (wtoken.sendingToBottom) {
-                if (DEBUG_REORDER) Slog.v(TAG,
-                        "Skipping token -- currently sending to bottom");
-                tokenPos--;
+                if (DEBUG_REORDER) Slog.v(TAG, "Skipping token -- currently sending to bottom");
                 continue;
             }
             for (int i = wtoken.windows.size() - 1; i >= 0; --i) {
@@ -4447,7 +4431,6 @@
                     }
                 }
             }
-            tokenPos--;
         }
 
         return 0;
@@ -4496,111 +4479,30 @@
         return index;
     }
 
-    @Override
-    public void moveAppToken(int index, IBinder token) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppToken()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+    private void moveTaskWindowsLocked(int taskId) {
+        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+        if (displayContent == null) {
+            Slog.w(TAG, "moveTaskWindowsLocked: can't find DisplayContent for taskId=" + taskId);
+            return;
         }
 
-        synchronized(mWindowMap) {
-            if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
-            if (DEBUG_REORDER) dumpAppTokensLocked();
-            final AppWindowToken wtoken = findAppWindowToken(token);
-            DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
-            final AppTokenList appTokens = displayContent.mAppTokens;
-            final AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
-            final int oldIndex = appTokens.indexOf(wtoken);
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
-                    "Start moving token " + wtoken + " initially at "
-                    + oldIndex);
-            if (oldIndex > index && mAppTransition.isTransitionSet()) {
-                // animation towards back has not started, copy old list for duration of animation.
-                displayContent.refillAnimatingAppTokens();
-            }
-            if (wtoken == null || !appTokens.remove(wtoken)) {
-                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
-                      + token + " (" + wtoken + ")");
-                return;
-            }
-            appTokens.add(index, wtoken);
-            if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
-            else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
-            if (DEBUG_REORDER) dumpAppTokensLocked();
-            if (!mAppTransition.isTransitionSet()) {
-                // Not animating, bring animating app list in line with mAppTokens.
-                displayContent.refillAnimatingAppTokens();
-
-                // Bring window ordering, window focus and input window in line with new app token
-                final long origId = Binder.clearCallingIdentity();
-                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
-                if (DEBUG_REORDER) dumpWindowsLocked();
-                if (tmpRemoveAppWindowsLocked(wtoken)) {
-                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
-                    if (DEBUG_REORDER) dumpWindowsLocked();
-                    DisplayContentsIterator iterator = new DisplayContentsIterator();
-                    while(iterator.hasNext()) {
-                        displayContent = iterator.next();
-                        final int pos = findWindowOffsetLocked(displayContent, index);
-                        final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
-                        if (pos != newPos) {
-                            displayContent.layoutNeeded = true;
-                        }
-                    }
-                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
-                    if (DEBUG_REORDER) dumpWindowsLocked();
-                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                            false /*updateInputWindows*/);
-                    mInputMonitor.setUpdateInputWindowsNeededLw();
-                    performLayoutAndPlaceSurfacesLocked();
-                    mInputMonitor.updateInputWindowsLw(false /*force*/);
-                }
-                Binder.restoreCallingIdentity(origId);
-            }
+        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+        if (taskList == null) {
+            Slog.w(TAG, "moveTaskWindowsLocked: can't find TaskList for taskId=" + taskId);
+            return;
         }
-    }
 
-    private void removeAppTokensLocked(List<IBinder> tokens) {
-        // XXX This should be done more efficiently!
-        // (take advantage of the fact that both lists should be
-        // ordered in the same way.)
-        int N = tokens.size();
-        for (int i=0; i<N; i++) {
-            IBinder token = tokens.get(i);
-            final AppWindowToken wtoken = findAppWindowToken(token);
-            if (wtoken != null) {
-                final DisplayContent displayContent = mTaskIdToDisplayContents.get(wtoken.groupId);
-                if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Temporarily removing "
-                        + wtoken + " from " + displayContent.mAppTokens.indexOf(wtoken));
-                if (!displayContent.mAppTokens.remove(wtoken)) {
-                    Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
-                            + token + " (" + wtoken + ")");
-                    i--;
-                    N--;
-                }
-            }
-        }
-    }
-
-    private void moveAppWindowsLocked(List<IBinder> tokens, DisplayContent displayContent,
-            int tokenPos) {
         // First remove all of the windows from the list.
-        final int N = tokens.size();
-        int i;
-        for (i=0; i<N; i++) {
-            WindowToken token = mTokenMap.get(tokens.get(i));
-            if (token != null) {
-                tmpRemoveAppWindowsLocked(token);
-            }
+        for (AppWindowToken wtoken : taskList.mAppTokens) {
+            tmpRemoveAppWindowsLocked(wtoken);
         }
 
         // And now add them back at the correct place.
         // Where to start adding?
-        int pos = findWindowOffsetLocked(displayContent, tokenPos);
-        for (i=0; i<N; i++) {
-            WindowToken token = mTokenMap.get(tokens.get(i));
-            if (token != null) {
-                final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
+        int pos = findAppWindowInsertionPointLocked(taskList.mAppTokens.get(0));
+        for (AppWindowToken wtoken : taskList.mAppTokens) {
+            if (wtoken != null) {
+                final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
                 if (newPos != pos) {
                     displayContent.layoutNeeded = true;
                 }
@@ -4612,132 +4514,69 @@
             assignLayersLocked(displayContent.getWindowList());
         }
 
+        updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+                false /*updateInputWindows*/);
         mInputMonitor.setUpdateInputWindowsNeededLw();
-
-        // Note that the above updateFocusedWindowLocked used to sit here.
-
         performLayoutAndPlaceSurfacesLocked();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
 
         //dump();
     }
 
-    @Override
-    public void moveAppTokensToTop(List<IBinder> tokens) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppTokensToTop()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        final long origId = Binder.clearCallingIdentity();
-        synchronized(mWindowMap) {
-            DisplayContent displayContent = null;
-            removeAppTokensLocked(tokens);
-            final int N = tokens.size();
-            for (int i=0; i<N; i++) {
-                AppWindowToken wt = findAppWindowToken(tokens.get(i));
-                if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) {
-                        Slog.v(TAG, "Adding next to top: " + wt);
-                        if (displayContent != null &&
-                                displayContent != mTaskIdToDisplayContents.get(wt.groupId)) Slog.e(
-                                    TAG, "moveAppTokensToTop: Not all tokens on same display");
-                    }
-                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
-                    displayContent.mAppTokens.add(wt);
-                    if (mAppTransition.isTransitionSet()) {
-                        wt.sendingToBottom = false;
-                    }
-                }
-            }
-
-            displayContent.refillAnimatingAppTokens();
-            moveAppWindowsLocked(tokens, displayContent, displayContent.mAppTokens.size());
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public void moveAppTokensToBottom(List<IBinder> tokens) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "moveAppTokensToBottom()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        final long origId = Binder.clearCallingIdentity();
-        synchronized(mWindowMap) {
-            DisplayContent displayContent = null;
-            final int N = tokens.size();
-            if (N > 0) {
-                // animating towards back, hang onto old list for duration of animation.
-                AppWindowToken wt = findAppWindowToken(tokens.get(0));
-                if (wt != null) {
-                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
-                    displayContent.refillAnimatingAppTokens();
-                }
-            }
-            removeAppTokensLocked(tokens);
-            int pos = 0;
-            for (int i=0; i<N; i++) {
-                AppWindowToken wt = findAppWindowToken(tokens.get(i));
-                if (wt != null) {
-                    if (DEBUG_TOKEN_MOVEMENT) {
-                        Slog.v(TAG, "Adding next to bottom: " + wt + " at " + pos);
-                        if (displayContent != null &&
-                                displayContent != mTaskIdToDisplayContents.get(wt.groupId)) Slog.e(
-                                    TAG, "moveAppTokensToBottom: Not all tokens on same display");
-                    }
-                    displayContent = mTaskIdToDisplayContents.get(wt.groupId);
-                    displayContent.mAppTokens.add(pos, wt);
-                    if (mAppTransition.isTransitionSet()) {
-                        wt.sendingToBottom = true;
-                    }
-                    pos++;
-                }
-            }
-
-            displayContent.refillAnimatingAppTokens();
-            moveAppWindowsLocked(tokens, displayContent, 0);
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
     public void moveTaskToTop(int taskId) {
-        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
-        if (displayContent == null) {
-            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
-                    + " not found in mTaskIdToDisplayContents");
-            return;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(mWindowMap) {
+                DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+                if (displayContent == null) {
+                    Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
+                            + " not found in mTaskIdToDisplayContents");
+                    return;
+                }
+                TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+                if (taskList == null) {
+                    Slog.e(TAG, "moveTaskToTop: taskId=" + taskId
+                            + " not found in mTaskIdToTaskLists");
+                    return;
+                }
+                if (!displayContent.mTaskLists.remove(taskList)) {
+                    Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskLists");
+                }
+                displayContent.mTaskLists.add(taskList);
+
+                moveTaskWindowsLocked(taskId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
-        if (taskList == null) {
-            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskIdToTaskLists");
-            return;
-        }
-        if (!displayContent.mTaskLists.remove(taskList)) {
-            Slog.e(TAG, "moveTaskToTop: taskId=" + taskId + " not found in mTaskLists");
-        }
-        displayContent.mTaskLists.add(taskList);
-        displayContent.verifyAppTokens();
     }
 
     public void moveTaskToBottom(int taskId) {
-        DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
-        if (displayContent == null) {
-            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
-                    + " not found in mTaskIdToDisplayContents");
-            return;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(mWindowMap) {
+                DisplayContent displayContent = mTaskIdToDisplayContents.get(taskId);
+                if (displayContent == null) {
+                    Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
+                            + " not found in mTaskIdToDisplayContents");
+                    return;
+                }
+                TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
+                if (taskList == null) {
+                    Slog.e(TAG, "moveTaskToTopBottom: taskId=" + taskId
+                            + " not found in mTaskIdToTaskLists");
+                    return;
+                }
+                if (!displayContent.mTaskLists.remove(taskList)) {
+                    Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId + " not found in mTaskLists");
+                }
+                displayContent.mTaskLists.add(0, taskList);
+
+                moveTaskWindowsLocked(taskId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        TaskList taskList = displayContent.mTaskIdToTaskList.get(taskId);
-        if (taskList == null) {
-            Slog.e(TAG, "moveTaskToTopBottomtaskId=" + taskId + " not found in mTaskIdToTaskLists");
-            return;
-        }
-        if (!displayContent.mTaskLists.remove(taskList)) {
-            Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId + " not found in mTaskLists");
-        }
-        displayContent.mTaskLists.add(0, taskList);
-        displayContent.verifyAppTokens();
     }
 
     // -------------------------------------------------------------
@@ -4858,9 +4697,9 @@
     @Override
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
-            final AllWindowsIterator iterator = new AllWindowsIterator();
-            while (iterator.hasNext()) {
-                final WindowState w = iterator.next();
+            mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+            while (mTmpWindowsIterator.hasNext()) {
+                final WindowState w = mTmpWindowsIterator.next();
                 if (w.mHasSurface) {
                     try {
                         w.mClient.closeSystemDialogs(reason);
@@ -5254,9 +5093,9 @@
             // the background..)
             if (on) {
                 boolean isVisible = false;
-                final AllWindowsIterator iterator = new AllWindowsIterator();
-                while (iterator.hasNext()) {
-                    final WindowState ws = iterator.next();
+                mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+                while (mTmpWindowsIterator.hasNext()) {
+                    final WindowState ws = mTmpWindowsIterator.next();
                     if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
                         isVisible = true;
                         break;
@@ -5269,7 +5108,7 @@
 
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     ">>> OPEN TRANSACTION showStrictModeViolation");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
                 // TODO(multi-display): support multiple displays
                 if (mStrictModeFlash == null) {
@@ -5278,7 +5117,7 @@
                 }
                 mStrictModeFlash.setVisibility(on);
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                         "<<< CLOSE TRANSACTION showStrictModeViolation");
             }
@@ -5433,7 +5272,7 @@
                             + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
                 }
             }
-            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
+            rawss = SurfaceControl.screenshot(dw, dh, 0, maxLayer);
         }
 
         if (rawss == null) {
@@ -5643,7 +5482,7 @@
             if (SHOW_TRANSACTIONS) {
                 Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
             }
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
         }
         try {
             // NOTE: We disable the rotation in the emulator because
@@ -5661,7 +5500,7 @@
             mDisplayManagerService.performTraversalInTransactionFromWindowManager();
         } finally {
             if (!inTransaction) {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) {
                     Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
                 }
@@ -6132,9 +5971,9 @@
         }
 
         synchronized (mWindowMap) {
-            final AllWindowsIterator iterator = new AllWindowsIterator();
-            while (iterator.hasNext()) {
-                final WindowState w = iterator.next();
+            mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+            while (mTmpWindowsIterator.hasNext()) {
+                final WindowState w = mTmpWindowsIterator.next();
                 if (System.identityHashCode(w) == hashCode) {
                     return w;
                 }
@@ -6483,8 +6322,8 @@
                         // TODO(multi-display): support other displays
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
                         final Display display = displayContent.getDisplay();
-                        Surface surface = new Surface(session, "drag surface",
-                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
+                        SurfaceControl surface = new SurfaceControl(session, "drag surface",
+                                width, height, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
                         surface.setLayerStack(display.getLayerStack());
                         if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
                                 + surface + ": CREATE");
@@ -6501,7 +6340,7 @@
                     } else {
                         Slog.w(TAG, "Drag already in progress");
                     }
-                } catch (Surface.OutOfResourcesException e) {
+                } catch (SurfaceControl.OutOfResourcesException e) {
                     Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
                     if (mDragState != null) {
                         mDragState.reset();
@@ -6683,10 +6522,10 @@
     // TODO(multidisplay): Call isScreenOn for each display.
     private void sendScreenStatusToClientsLocked() {
         final boolean on = mPowerManager.isScreenOn();
-        final AllWindowsIterator iterator = new AllWindowsIterator();
-        while (iterator.hasNext()) {
+        mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+        while (mTmpWindowsIterator.hasNext()) {
             try {
-                iterator.next().mClient.dispatchScreenState(on);
+                mTmpWindowsIterator.next().mClient.dispatchScreenState(on);
             } catch (RemoteException e) {
                 // Ignored
             }
@@ -6982,7 +6821,6 @@
                         if (mAppTransition.isTransitionSet()) {
                             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
                             mAppTransition.setTimeout();
-                            getDefaultDisplayContentLocked().refillAnimatingAppTokens();
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -7028,11 +6866,10 @@
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
                         DisplayContent displayContent = getDefaultDisplayContentLocked();
-                        AppTokenList appTokens = displayContent.mAppTokens;
-                        int i = appTokens.size();
-                        while (i > 0) {
-                            i--;
-                            AppWindowToken tok = appTokens.get(i);
+                        AppTokenIterator iterator =
+                                displayContent.getTmpAppIterator(REVERSE_ITERATOR);
+                        while (iterator.hasNext()) {
+                            AppWindowToken tok = iterator.next();
                             if (tok.mAppAnimator.freezingScreen) {
                                 Slog.w(TAG, "Force clearing freeze: " + tok);
                                 unsetAppFreezingScreenLocked(tok, true, true);
@@ -7251,6 +7088,15 @@
 
     @Override
     public void setForcedDisplaySize(int displayId, int width, int height) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " +
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        }
+        if (displayId != Display.DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException("Can only set the default display");
+        }
         synchronized(mWindowMap) {
             // Set some sort of reasonable bounds on the size of the display that we
             // will try to emulate.
@@ -7322,6 +7168,15 @@
 
     @Override
     public void clearForcedDisplaySize(int displayId) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " +
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        }
+        if (displayId != Display.DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException("Can only set the default display");
+        }
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent != null) {
@@ -7335,6 +7190,15 @@
 
     @Override
     public void setForcedDisplayDensity(int displayId, int density) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " +
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        }
+        if (displayId != Display.DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException("Can only set the default display");
+        }
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent != null) {
@@ -7357,6 +7221,15 @@
 
     @Override
     public void clearForcedDisplayDensity(int displayId) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " +
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        }
+        if (displayId != Display.DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException("Can only set the default display");
+        }
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent != null) {
@@ -7395,6 +7268,33 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
+    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " +
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        }
+        synchronized(mWindowMap) {
+            DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent != null) {
+                mDisplayManagerService.setOverscan(displayId, left, top, right, bottom);
+                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                synchronized(displayContent.mDisplaySizeLock) {
+                    displayInfo.overscanLeft = left;
+                    displayInfo.overscanTop = top;
+                    displayInfo.overscanRight = right;
+                    displayInfo.overscanBottom = bottom;
+                }
+                mPolicy.setDisplayOverscan(displayContent.getDisplay(), left, top, right, bottom);
+                displayContent.layoutNeeded = true;
+                mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
+                mDisplaySettings.writeSettingsLocked();
+                performLayoutAndPlaceSurfacesLocked();
+            }
+        }
+    }
+
     @Override
     public boolean hasSystemNavBar() {
         return mPolicy.hasSystemNavBar();
@@ -7493,10 +7393,9 @@
         }
 
         // And add in the still active app tokens in Z order.
-        AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
-        NT = animatingAppTokens.size();
-        for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, animatingAppTokens.get(j));
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(FORWARD_ITERATOR);
+        while (iterator.hasNext()) {
+            i = reAddAppWindowsLocked(displayContent, i, iterator.next());
         }
 
         i -= lastBelow;
@@ -7516,7 +7415,7 @@
                 }
             }
             Slog.w(TAG, "Current app token list:");
-            dumpAnimatingAppTokensLocked();
+            dumpAppTokensLocked();
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
@@ -8098,15 +7997,15 @@
                     // TODO(multi-display): support other displays
                     final DisplayContent displayContent = getDefaultDisplayContentLocked();
                     final Display display = displayContent.getDisplay();
-                    Surface surface = new Surface(mFxSession,
+                    SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
                             "thumbnail anim",
                             dirty.width(), dirty.height(),
-                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-                    surface.setLayerStack(display.getLayerStack());
-                    appAnimator.thumbnail = surface;
-                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL " + surface + ": CREATE");
+                            PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+                    surfaceControl.setLayerStack(display.getLayerStack());
+                    appAnimator.thumbnail = surfaceControl;
+                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
                     Surface drawSurface = new Surface();
-                    drawSurface.copyFrom(surface);
+                    drawSurface.copyFrom(surfaceControl);
                     Canvas c = drawSurface.lockCanvas(dirty);
                     c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
                     drawSurface.unlockCanvasAndPost(c);
@@ -8122,10 +8021,14 @@
                     mAppTransition.getStartingPoint(p);
                     appAnimator.thumbnailX = p.x;
                     appAnimator.thumbnailY = p.y;
-                } catch (Surface.OutOfResourcesException e) {
+                } catch (SurfaceControl.OutOfResourcesException e) {
                     Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
                             + " h=" + dirty.height(), e);
                     appAnimator.clearThumbnail();
+                } catch (Surface.OutOfResourcesException e) {
+                    Slog.e(TAG, "Can't allocate Canvas surface w=" + dirty.width()
+                            + " h=" + dirty.height(), e);
+                    appAnimator.clearThumbnail();
                 }
             }
 
@@ -8163,11 +8066,10 @@
         mAppTransition.setIdle();
         // Restore window app tokens to the ActivityManager views
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
-        final AppTokenList animatingAppTokens = displayContent.mAnimatingAppTokens;
-        for (int i = animatingAppTokens.size() - 1; i >= 0; i--) {
-            animatingAppTokens.get(i).sendingToBottom = false;
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(FORWARD_ITERATOR);
+        while (iterator.hasNext()) {
+            iterator.next().sendingToBottom = false;
         }
-        displayContent.refillAnimatingAppTokens();
         rebuildAppWindowListLocked();
 
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
@@ -8224,7 +8126,7 @@
                 if (w.mOrientationChanging) {
                     if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
-                            + w + ", surface " + winAnimator.mSurface);
+                            + w + ", surface " + winAnimator.mSurfaceControl);
                     winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                     if (w.mAppToken != null) {
                         w.mAppToken.allDrawn = false;
@@ -8241,7 +8143,7 @@
                 if (w.isDrawnLw()) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation not waiting for draw in "
-                            + w + ", surface " + winAnimator.mSurface);
+                            + w + ", surface " + winAnimator.mSurfaceControl);
                     w.mOrientationChanging = false;
                 }
             }
@@ -8324,10 +8226,9 @@
     private void updateAllDrawnLocked(DisplayContent displayContent) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final AppTokenList appTokens = displayContent.mAnimatingAppTokens;
-        final int NT = appTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = appTokens.get(i);
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(FORWARD_ITERATOR);
+        while (iterator.hasNext()) {
+            AppWindowToken wtoken = iterator.next();
             if (!wtoken.allDrawn) {
                 int numInteresting = wtoken.numInterestingWindows;
                 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
@@ -8387,7 +8288,7 @@
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
 
             if (mWatermark != null) {
@@ -8590,7 +8491,7 @@
                                     Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
                                             + ", isAnimating=" + winAnimator.isAnimating());
                                     if (!w.isDrawnLw()) {
-                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
+                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
                                                 + " pv=" + w.mPolicyVisibility
                                                 + " mDrawState=" + winAnimator.mDrawState
                                                 + " ah=" + w.mAttachedHidden
@@ -8662,7 +8563,7 @@
         } catch (RuntimeException e) {
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
         }
@@ -9075,7 +8976,7 @@
 
     boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
                                            boolean secure) {
-        final Surface surface = winAnimator.mSurface;
+        final SurfaceControl surface = winAnimator.mSurfaceControl;
         boolean leakedSurface = false;
         boolean killedApps = false;
 
@@ -9092,33 +8993,33 @@
             // window list to make sure we haven't left any dangling surfaces
             // around.
 
-            AllWindowsIterator iterator = new AllWindowsIterator();
+            mTmpWindowsIterator.reset(FORWARD_ITERATOR);
             Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
-            while (iterator.hasNext()) {
-                WindowState ws = iterator.next();
+            while (mTmpWindowsIterator.hasNext()) {
+                WindowState ws = mTmpWindowsIterator.next();
                 WindowStateAnimator wsa = ws.mWinAnimator;
-                if (wsa.mSurface != null) {
+                if (wsa.mSurfaceControl != null) {
                     if (!mSessions.contains(wsa.mSession)) {
                         Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
-                                + ws + " surface=" + wsa.mSurface
+                                + ws + " surface=" + wsa.mSurfaceControl
                                 + " token=" + ws.mToken
                                 + " pid=" + ws.mSession.mPid
                                 + " uid=" + ws.mSession.mUid);
                         if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
-                        wsa.mSurface.destroy();
+                        wsa.mSurfaceControl.destroy();
                         wsa.mSurfaceShown = false;
-                        wsa.mSurface = null;
+                        wsa.mSurfaceControl = null;
                         ws.mHasSurface = false;
                         mForceRemoves.add(ws);
                         leakedSurface = true;
                     } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
                         Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
-                                + ws + " surface=" + wsa.mSurface
+                                + ws + " surface=" + wsa.mSurfaceControl
                                 + " token=" + ws.mAppToken);
                         if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
-                        wsa.mSurface.destroy();
+                        wsa.mSurfaceControl.destroy();
                         wsa.mSurfaceShown = false;
-                        wsa.mSurface = null;
+                        wsa.mSurfaceControl = null;
                         ws.mHasSurface = false;
                         leakedSurface = true;
                     }
@@ -9128,14 +9029,14 @@
             if (!leakedSurface) {
                 Slog.w(TAG, "No leaked surfaces; killing applicatons!");
                 SparseIntArray pidCandidates = new SparseIntArray();
-                iterator = new AllWindowsIterator();
-                while (iterator.hasNext()) {
-                    WindowState ws = iterator.next();
+                mTmpWindowsIterator.reset(FORWARD_ITERATOR);
+                while (mTmpWindowsIterator.hasNext()) {
+                    WindowState ws = mTmpWindowsIterator.next();
                     if (mForceRemoves.contains(ws)) {
                         continue;
                     }
                     WindowStateAnimator wsa = ws.mWinAnimator;
-                    if (wsa.mSurface != null) {
+                    if (wsa.mSurfaceControl != null) {
                         pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
                     }
                 }
@@ -9162,7 +9063,7 @@
                             "RECOVER DESTROY", null);
                     surface.destroy();
                     winAnimator.mSurfaceShown = false;
-                    winAnimator.mSurface = null;
+                    winAnimator.mSurfaceControl = null;
                     winAnimator.mWin.mHasSurface = false;
                 }
 
@@ -9256,7 +9157,7 @@
     }
 
     private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
-        AppTokenIterator iterator = displayContent.new AppTokenIterator(true);
+        AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
         WindowToken nextApp = iterator.hasNext() ? iterator.next() : null;
 
         final WindowList windows = displayContent.getWindowList();
@@ -9688,23 +9589,6 @@
                 }
             }
         }
-        final AppTokenList animatingAppTokens =
-                getDefaultDisplayContentLocked().mAnimatingAppTokens;
-        if (mAppTransition.isRunning() && animatingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Application tokens during animation:");
-            for (int i=animatingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = animatingAppTokens.get(i);
-                pw.print("  App moving to bottom #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
         if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
             pw.println();
             if (mOpeningApps.size() > 0) {
@@ -9737,9 +9621,9 @@
     void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
         int j = 0;
-        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
-        while (iterator.hasNext()) {
-            final WindowState w = iterator.next();
+        mTmpWindowsIterator.reset(REVERSE_ITERATOR);
+        while (mTmpWindowsIterator.hasNext()) {
+            final WindowState w = mTmpWindowsIterator.next();
             if (windows == null || windows.contains(w)) {
                 pw.print("  Window #"); pw.print(j++); pw.print(' ');
                         pw.print(w); pw.println(":");
@@ -9872,7 +9756,7 @@
         if (dumpAll) {
             pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
                     pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
-                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
+                    pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
             if (mLastStatusBarVisibility != 0) {
                 pw.print("  mLastStatusBarVisibility=0x");
                         pw.println(Integer.toHexString(mLastStatusBarVisibility));
@@ -9934,9 +9818,9 @@
         WindowList windows = new WindowList();
         if ("visible".equals(name)) {
             synchronized(mWindowMap) {
-                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
-                while (iterator.hasNext()) {
-                    final WindowState w = iterator.next();
+                mTmpWindowsIterator.reset(REVERSE_ITERATOR);
+                while (mTmpWindowsIterator.hasNext()) {
+                    final WindowState w = mTmpWindowsIterator.next();
                     if (w.mWinAnimator.mSurfaceShown) {
                         windows.add(w);
                     }
@@ -9951,9 +9835,9 @@
             } catch (RuntimeException e) {
             }
             synchronized(mWindowMap) {
-                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
-                while (iterator.hasNext()) {
-                    final WindowState w = iterator.next();
+                mTmpWindowsIterator.reset(REVERSE_ITERATOR);
+                while (mTmpWindowsIterator.hasNext()) {
+                    final WindowState w = mTmpWindowsIterator.next();
                     if (name != null) {
                         if (w.mAttrs.getTitle().toString().contains(name)) {
                             windows.add(w);
@@ -10151,12 +10035,28 @@
         }
     }
 
+    private DisplayContent newDisplayContentLocked(final Display display) {
+        DisplayContent displayContent = new DisplayContent(display);
+        mDisplayContents.put(display.getDisplayId(), displayContent);
+        final Rect rect = new Rect();
+        DisplayInfo info = displayContent.getDisplayInfo();
+        mDisplaySettings.getOverscanLocked(info.name, rect);
+        info.overscanLeft = rect.left;
+        info.overscanTop = rect.top;
+        info.overscanRight = rect.right;
+        info.overscanBottom = rect.bottom;
+        mDisplayManagerService.setOverscan(display.getDisplayId(), rect.left, rect.top,
+                rect.right, rect.bottom);
+        mPolicy.setDisplayOverscan(displayContent.getDisplay(), rect.left, rect.top,
+                rect.right, rect.bottom);
+        return displayContent;
+    }
+
     public void createDisplayContentLocked(final Display display) {
         if (display == null) {
             throw new IllegalArgumentException("getDisplayContent: display must not be null");
         }
-        final DisplayContent displayContent = new DisplayContent(display);
-        mDisplayContents.put(display.getDisplayId(), displayContent);
+        newDisplayContentLocked(display);
     }
 
     /**
@@ -10170,8 +10070,7 @@
         if (displayContent == null) {
             final Display display = mDisplayManager.getDisplay(displayId);
             if (display != null) {
-                displayContent = new DisplayContent(display);
-                mDisplayContents.put(displayId, displayContent);
+                displayContent = newDisplayContentLocked(display);
             }
         }
         return displayContent;
@@ -10180,6 +10079,10 @@
     class DisplayContentsIterator implements Iterator<DisplayContent> {
         private int cur;
 
+        void reset() {
+            cur = 0;
+        }
+
         @Override
         public boolean hasNext() {
             return cur < mDisplayContents.size();
@@ -10199,7 +10102,6 @@
         }
     }
 
-    final static boolean REVERSE_ITERATOR = true;
     class AllWindowsIterator implements Iterator<WindowState> {
         private DisplayContent mDisplayContent;
         private DisplayContentsIterator mDisplayContentsIterator;
@@ -10208,19 +10110,33 @@
         private boolean mReverse;
 
         AllWindowsIterator() {
-            mDisplayContentsIterator = new DisplayContentsIterator();
-            mDisplayContent = mDisplayContentsIterator.next();
-            mWindowList = mDisplayContent.getWindowList();
+            this(false);
         }
 
         AllWindowsIterator(boolean reverse) {
-            this();
+            mDisplayContentsIterator = new DisplayContentsIterator();
+            reset(reverse);
+        }
+
+        void reset(boolean reverse) {
             mReverse = reverse;
-            mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
+            mDisplayContentsIterator.reset();
+            if (mDisplayContentsIterator.hasNext()) {
+                mDisplayContent = mDisplayContentsIterator.next();
+                mWindowList = mDisplayContent.getWindowList();
+                mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
+            } else {
+                mDisplayContent = null;
+                mWindowList = null;
+                mWindowListIndex = 0;
+            }
         }
 
         @Override
         public boolean hasNext() {
+            if (mDisplayContent == null) {
+                return false;
+            }
             if (mReverse) {
                 return mWindowListIndex >= 0;
             }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 8dda544..f0045b1 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -52,6 +52,12 @@
 import java.util.ArrayList;
 
 class WindowList extends ArrayList<WindowState> {
+    WindowList() {
+        super();
+    }
+    WindowList(WindowList windows) {
+        super(windows);
+    }
 }
 
 /**
@@ -1058,7 +1064,7 @@
         return true;
     }
 
-    public boolean setAppOpVisibilityLw(boolean state) {
+    public void setAppOpVisibilityLw(boolean state) {
         if (mAppOpVisibility != state) {
             mAppOpVisibility = state;
             if (state) {
@@ -1068,13 +1074,11 @@
                 // ops modifies they should only be hidden by policy due to the
                 // lock screen, and the user won't be changing this if locked.
                 // Plus it will quickly be fixed the next time we do a layout.
-                showLw(true, false);
+                showLw(true, true);
             } else {
-                hideLw(true, false);
+                hideLw(true, true);
             }
-            return true;
         }
-        return false;
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index a4c6a9e..3a9f7cb 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -20,6 +20,7 @@
 import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
@@ -87,8 +88,8 @@
     int mAnimLayer;
     int mLastLayer;
 
-    Surface mSurface;
-    Surface mPendingDestroySurface;
+    SurfaceControl mSurfaceControl;
+    SurfaceControl mPendingDestroySurface;
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -403,7 +404,7 @@
         if (WindowManagerService.localLOGV) Slog.v(
                 TAG, "Exit animation finished in " + this
                 + ": remove=" + mWin.mRemoveOnExit);
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             mService.mDestroySurface.add(mWin);
             mWin.mDestroying = true;
             if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface(
@@ -424,10 +425,10 @@
             mLastHidden = true;
             if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
                     "HIDE (performLayout)", null);
-            if (mSurface != null) {
+            if (mSurfaceControl != null) {
                 mSurfaceShown = false;
                 try {
-                    mSurface.hide();
+                    mSurfaceControl.hide();
                 } catch (RuntimeException e) {
                     Slog.w(TAG, "Exception hiding surface in " + mWin);
                 }
@@ -444,7 +445,7 @@
         if (mDrawState == DRAW_PENDING) {
             if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
-                        + mSurface);
+                        + mSurfaceControl);
             if (DEBUG_STARTING_WINDOW &&
                     mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
                 Slog.v(TAG, "Draw state now committed in " + mWin);
@@ -466,7 +467,7 @@
             return false;
         }
         if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
-            Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurface);
+            Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceControl);
         }
         mDrawState = READY_TO_SHOW;
         final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING;
@@ -477,7 +478,7 @@
         return true;
     }
 
-    static class SurfaceTrace extends Surface {
+    static class SurfaceTrace extends SurfaceControl {
         private final static String SURFACE_TAG = "SurfaceTrace";
         final static ArrayList<SurfaceTrace> sSurfaces = new ArrayList<SurfaceTrace>();
 
@@ -623,8 +624,8 @@
         }
     }
 
-    Surface createSurfaceLocked() {
-        if (mSurface == null) {
+    SurfaceControl createSurfaceLocked() {
+        if (mSurfaceControl == null) {
             if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": mDrawState=DRAW_PENDING");
             mDrawState = DRAW_PENDING;
@@ -641,11 +642,11 @@
 
             mService.makeWindowFreezingScreenIfNeededLocked(mWin);
 
-            int flags = Surface.HIDDEN;
+            int flags = SurfaceControl.HIDDEN;
             final WindowManager.LayoutParams attrs = mWin.mAttrs;
 
             if ((attrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
-                flags |= Surface.SECURE;
+                flags |= SurfaceControl.SECURE;
             }
             if (WindowState.DEBUG_VISIBILITY) Slog.v(
                 TAG, "Creating surface in session "
@@ -681,15 +682,15 @@
                         WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
                 final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
                 if (!PixelFormat.formatHasAlpha(attrs.format)) {
-                    flags |= Surface.OPAQUE;
+                    flags |= SurfaceControl.OPAQUE;
                 }
                 if (DEBUG_SURFACE_TRACE) {
-                    mSurface = new SurfaceTrace(
+                    mSurfaceControl = new SurfaceTrace(
                             mSession.mSurfaceSession,
                             attrs.getTitle().toString(),
                             w, h, format, flags);
                 } else {
-                    mSurface = new Surface(
+                    mSurfaceControl = new SurfaceControl(
                         mSession.mSurfaceSession,
                         attrs.getTitle().toString(),
                         w, h, format, flags);
@@ -697,13 +698,13 @@
                 mWin.mHasSurface = true;
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
                         "  CREATE SURFACE "
-                        + mSurface + " IN SESSION "
+                        + mSurfaceControl + " IN SESSION "
                         + mSession.mSurfaceSession
                         + ": pid=" + mSession.mPid + " format="
                         + attrs.format + " flags=0x"
                         + Integer.toHexString(flags)
                         + " / " + this);
-            } catch (Surface.OutOfResourcesException e) {
+            } catch (SurfaceControl.OutOfResourcesException e) {
                 mWin.mHasSurface = false;
                 Slog.w(TAG, "OutOfResourcesException creating surface");
                 mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
@@ -717,7 +718,7 @@
             }
 
             if (WindowManagerService.localLOGV) Slog.v(
-                TAG, "Got surface: " + mSurface
+                TAG, "Got surface: " + mSurfaceControl
                 + ", set left=" + mWin.mFrame.left + " top=" + mWin.mFrame.top
                 + ", animLayer=" + mAnimLayer);
             if (SHOW_LIGHT_TRANSACTIONS) {
@@ -727,16 +728,16 @@
                         + mWin.mCompatFrame.width() + "x" + mWin.mCompatFrame.height()
                         + "), layer=" + mAnimLayer + " HIDE", null);
             }
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
                 try {
                     mSurfaceX = mWin.mFrame.left + mWin.mXOffset;
                     mSurfaceY = mWin.mFrame.top + mWin.mYOffset;
-                    mSurface.setPosition(mSurfaceX, mSurfaceY);
+                    mSurfaceControl.setPosition(mSurfaceX, mSurfaceY);
                     mSurfaceLayer = mAnimLayer;
-                    mSurface.setLayerStack(mLayerStack);
-                    mSurface.setLayer(mAnimLayer);
-                    mSurface.setAlpha(0);
+                    mSurfaceControl.setLayerStack(mLayerStack);
+                    mSurfaceControl.setLayer(mAnimLayer);
+                    mSurfaceControl.setAlpha(0);
                     mSurfaceShown = false;
                 } catch (RuntimeException e) {
                     Slog.w(TAG, "Error creating surface in " + w, e);
@@ -744,14 +745,14 @@
                 }
                 mLastHidden = true;
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                         "<<< CLOSE TRANSACTION createSurfaceLocked");
             }
             if (WindowManagerService.localLOGV) Slog.v(
                     TAG, "Created surface " + this);
         }
-        return mSurface;
+        return mSurfaceControl;
     }
 
     void destroySurfaceLocked() {
@@ -759,7 +760,7 @@
             mWin.mAppToken.startingDisplayed = false;
         }
 
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
 
             int i = mWin.mChildWindows.size();
             while (i > 0) {
@@ -776,10 +777,10 @@
                         e.fillInStackTrace();
                     }
                     Slog.w(TAG, "Window " + this + " destroying surface "
-                            + mSurface + ", session " + mSession, e);
+                            + mSurfaceControl + ", session " + mSession, e);
                 }
                 if (mSurfaceDestroyDeferred) {
-                    if (mSurface != null && mPendingDestroySurface != mSurface) {
+                    if (mSurfaceControl != null && mPendingDestroySurface != mSurfaceControl) {
                         if (mPendingDestroySurface != null) {
                             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
                                 RuntimeException e = null;
@@ -791,7 +792,7 @@
                             }
                             mPendingDestroySurface.destroy();
                         }
-                        mPendingDestroySurface = mSurface;
+                        mPendingDestroySurface = mSurfaceControl;
                     }
                 } else {
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
@@ -802,17 +803,17 @@
                         }
                         WindowManagerService.logSurface(mWin, "DESTROY", e);
                     }
-                    mSurface.destroy();
+                    mSurfaceControl.destroy();
                 }
                 mAnimator.hideWallpapersLocked(mWin);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Exception thrown when destroying Window " + this
-                    + " surface " + mSurface + " session " + mSession
+                    + " surface " + mSurfaceControl + " session " + mSession
                     + ": " + e.toString());
             }
 
             mSurfaceShown = false;
-            mSurface = null;
+            mSurfaceControl = null;
             mWin.mHasSurface = false;
             mDrawState = NO_SURFACE;
         }
@@ -1119,7 +1120,7 @@
             try {
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                         "CROP " + w.mSystemDecorRect.toShortString(), null);
-                mSurface.setWindowCrop(w.mSystemDecorRect);
+                mSurfaceControl.setWindowCrop(w.mSystemDecorRect);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error setting crop surface of " + w
                         + " crop=" + w.mSystemDecorRect.toShortString(), e);
@@ -1163,7 +1164,7 @@
                         "POS " + left + ", " + top, null);
                 mSurfaceX = left;
                 mSurfaceY = top;
-                mSurface.setPosition(left, top);
+                mSurfaceControl.setPosition(left, top);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error positioning surface of " + w
                         + " pos=(" + left
@@ -1179,7 +1180,7 @@
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                         "SIZE " + width + "x" + height, null);
                 mSurfaceResized = true;
-                mSurface.setSize(width, height);
+                mSurfaceControl.setSize(width, height);
                 final int displayId = w.mDisplayContent.getDisplayId();
                 mAnimator.setPendingLayoutChanges(displayId,
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
@@ -1203,7 +1204,7 @@
 
     public void prepareSurfaceLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
-        if (mSurface == null) {
+        if (mSurfaceControl == null) {
             if (w.mOrientationChanging) {
                 if (DEBUG_ORIENTATION) {
                     Slog.v(TAG, "Orientation change skips hidden " + w);
@@ -1261,13 +1262,13 @@
                     + "," + (mDtDx*w.mVScale)
                     + "][" + (mDsDy*w.mHScale)
                     + "," + (mDtDy*w.mVScale) + "]", null);
-            if (mSurface != null) {
+            if (mSurfaceControl != null) {
                 try {
                     mSurfaceAlpha = mShownAlpha;
-                    mSurface.setAlpha(mShownAlpha);
+                    mSurfaceControl.setAlpha(mShownAlpha);
                     mSurfaceLayer = mAnimLayer;
-                    mSurface.setLayer(mAnimLayer);
-                    mSurface.setMatrix(
+                    mSurfaceControl.setLayer(mAnimLayer);
+                    mSurfaceControl.setMatrix(
                         mDsDx*w.mHScale, mDtDx*w.mVScale,
                         mDsDy*w.mHScale, mDtDy*w.mVScale);
 
@@ -1285,7 +1286,7 @@
                             w.mOrientationChanging = false;
                         }
                     }
-                    if (mSurface != null) {
+                    if (mSurfaceControl != null) {
                         w.mToken.hasVisible = true;
                     }
                 } catch (RuntimeException e) {
@@ -1318,19 +1319,19 @@
     }
 
     void setTransparentRegionHintLocked(final Region region) {
-        if (mSurface == null) {
+        if (mSurfaceControl == null) {
             Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
             return;
         }
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
             ">>> OPEN TRANSACTION setTransparentRegion");
-        Surface.openTransaction();
+        SurfaceControl.openTransaction();
         try {
             if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
                     "transparentRegionHint=" + region, null);
-            mSurface.setTransparentRegionHint(region);
+            mSurfaceControl.setTransparentRegionHint(region);
         } finally {
-            Surface.closeTransaction();
+            SurfaceControl.closeTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setTransparentRegion");
         }
@@ -1351,17 +1352,17 @@
             }
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     ">>> OPEN TRANSACTION setWallpaperOffset");
-            Surface.openTransaction();
+            SurfaceControl.openTransaction();
             try {
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
                         "POS " + left + ", " + top, null);
-                mSurface.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
+                mSurfaceControl.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
                 updateSurfaceWindowCrop(false);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error positioning surface of " + mWin
                         + " pos=(" + left + "," + top + ")", e);
             } finally {
-                Surface.closeTransaction();
+                SurfaceControl.closeTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                         "<<< CLOSE TRANSACTION setWallpaperOffset");
             }
@@ -1430,7 +1431,7 @@
                 WindowState c = mWin.mChildWindows.get(i);
                 if (c.mAttachedHidden) {
                     c.mAttachedHidden = false;
-                    if (c.mWinAnimator.mSurface != null) {
+                    if (c.mWinAnimator.mSurfaceControl != null) {
                         c.mWinAnimator.performShowLocked();
                         // It hadn't been shown, which means layout not
                         // performed on it, so now we want to make sure to
@@ -1478,9 +1479,9 @@
      */
     boolean showSurfaceRobustlyLocked() {
         try {
-            if (mSurface != null) {
+            if (mSurfaceControl != null) {
                 mSurfaceShown = true;
-                mSurface.show();
+                mSurfaceControl.show();
                 if (mWin.mTurnOnScreen) {
                     if (DEBUG_VISIBILITY) Slog.v(TAG,
                             "Show surface turning screen on: " + mWin);
@@ -1490,7 +1491,7 @@
             }
             return true;
         } catch (RuntimeException e) {
-            Slog.w(TAG, "Failure showing surface " + mSurface + " in " + mWin, e);
+            Slog.w(TAG, "Failure showing surface " + mSurfaceControl + " in " + mWin, e);
         }
 
         mService.reclaimSomeSurfaceMemoryLocked(this, "show", true);
@@ -1599,9 +1600,9 @@
                     pw.print(" "); mTransformation.printShortString(pw);
                     pw.println();
         }
-        if (mSurface != null) {
+        if (mSurfaceControl != null) {
             if (dumpAll) {
-                pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
+                pw.print(prefix); pw.print("mSurface="); pw.println(mSurfaceControl);
                 pw.print(prefix); pw.print("mDrawState=");
                 pw.print(drawStateToString(mDrawState));
                 pw.print(" mLastHidden="); pw.println(mLastHidden);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 81a2c14..4ff3899 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,7 +10,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     easymocklib \
     guava \
-    littlemock
+    mockito-target
 
 LOCAL_JAVA_LIBRARIES := android.test.runner services
 
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index f14569c..ffd1568 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Handler;
+import android.os.UserHandle;
 
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.AbstractFuture;
@@ -133,12 +134,28 @@
     }
 
     @Override
+    public void sendBroadcast(Intent intent, String receiverPermission) {
+        sendBroadcast(intent);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        sendBroadcast(intent);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission) {
+        sendBroadcast(intent);
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         sendBroadcast(intent);
     }
 
     @Override
-    public void sendBroadcast(Intent intent, String receiverPermission) {
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         sendBroadcast(intent);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 93ea6a2..4ae013b 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -21,16 +21,15 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
-import static com.google.testing.littlemock.LittleMock.anyInt;
-import static com.google.testing.littlemock.LittleMock.createCaptor;
-import static com.google.testing.littlemock.LittleMock.doNothing;
-import static com.google.testing.littlemock.LittleMock.doReturn;
-import static com.google.testing.littlemock.LittleMock.doThrow;
-import static com.google.testing.littlemock.LittleMock.eq;
-import static com.google.testing.littlemock.LittleMock.isA;
-import static com.google.testing.littlemock.LittleMock.mock;
-import static com.google.testing.littlemock.LittleMock.reset;
-import static com.google.testing.littlemock.LittleMock.verify;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.net.INetworkPolicyManager;
@@ -48,7 +47,7 @@
 import android.util.Log;
 import android.util.LogPrinter;
 
-import com.google.testing.littlemock.ArgumentCaptor;
+import org.mockito.ArgumentCaptor;
 
 import java.net.InetAddress;
 import java.util.concurrent.Future;
@@ -128,7 +127,7 @@
         doReturn(mWifi.tracker)
                 .when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class));
 
-        final ArgumentCaptor<Handler> trackerHandler = createCaptor();
+        final ArgumentCaptor<Handler> trackerHandler = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mMobile.tracker)
                 .startMonitoring(isA(Context.class), trackerHandler.capture());
 
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
index fb818d4..9939c08 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
@@ -41,13 +41,40 @@
     protected int mask() { return 0x0; };
 
     private static final RectF gRect = new RectF(0, 0, 200, 175);
-    private static final float[] gLinePts = new float[] {
-            100, 0, 200, 200, 200, 200, 0, 200, 0, 200, 100, 0
-    };
     private static final float[] gPts = new float[] {
             0, 100, 100, 0, 100, 200, 200, 100
     };
 
+    private static final int NUM_PARALLEL_LINES = 24;
+    private static final float[] gTriPts = new float[] {
+        75, 0, 130, 130, 130, 130, 0, 130, 0, 130, 75, 0
+    };
+    private static final float[] gLinePts = new float[NUM_PARALLEL_LINES * 8 + gTriPts.length];
+    static {
+        int index;
+        for (index = 0; index < gTriPts.length; index++) {
+            gLinePts[index] = gTriPts[index];
+        }
+        float val = 0;
+        for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
+            gLinePts[index + 0] = 150;
+            gLinePts[index + 1] = val;
+            gLinePts[index + 2] = 300;
+            gLinePts[index + 3] = val;
+            index += 4;
+            val += 8 + (2.0f/NUM_PARALLEL_LINES);
+        }
+        val = 0;
+        for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
+            gLinePts[index + 0] = val;
+            gLinePts[index + 1] = 150;
+            gLinePts[index + 2] = val;
+            gLinePts[index + 3] = 300;
+            index += 4;
+            val += 8 + (2.0f/NUM_PARALLEL_LINES);
+        }
+    };
+
     @SuppressWarnings("serial")
     private static final LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>> gMaps = new LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>>() {
         {
@@ -307,7 +334,7 @@
                             canvas.drawOval(gRect, paint);
                         }
                     });
-                    put("triLines", new DisplayModifier() {
+                    put("lines", new DisplayModifier() {
                         @Override
                         public void modifyDrawing(Paint paint, Canvas canvas) {
                             canvas.drawLines(gLinePts, paint);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
index 854dd69..69d34a5 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
@@ -54,7 +54,7 @@
                 0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2,
                 0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4,
             };
-            
+
             mColors = new int[] {
                 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000,
                 0xff0000ff, 0xffff0000, 0xff00ff00, 0xff00ff00,
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 32b2771..0a78908 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -32,6 +32,12 @@
 import android.widget.TextView;
 import android.view.View;
 import android.util.Log;
+import android.renderscript.ScriptC;
+import android.renderscript.RenderScript;
+import android.renderscript.Type;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Script;
 
 import android.os.Environment;
 import java.io.BufferedWriter;
@@ -44,6 +50,11 @@
     private final String TAG = "Img";
     public final String RESULT_FILE = "image_processing_result.csv";
 
+    RenderScript mRS;
+    Allocation mInPixelsAllocation;
+    Allocation mInPixelsAllocation2;
+    Allocation mOutPixelsAllocation;
+
     /**
      * Define enum type for test names
      */
@@ -408,6 +419,13 @@
         mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
         mBenchmarkResult.setText("Result: not run");
 
+
+        mRS = RenderScript.create(this);
+        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
+        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, mBitmapIn2);
+        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut);
+
+
         setupTests();
         changeTest(TestName.LEVELS_VEC3_RELAXED);
     }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
index faef83aa..a353d9c 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -45,7 +45,6 @@
     protected Allocation mInPixelsAllocation;
     protected Allocation mInPixelsAllocation2;
     protected Allocation mOutPixelsAllocation;
-
     protected ImageProcessingActivity act;
 
     private class MessageProcessor extends RenderScript.RSMessageHandler {
@@ -107,12 +106,12 @@
 
     public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2, Bitmap outb) {
         act = ipact;
-        mRS = RenderScript.create(act);
+        mRS = ipact.mRS;
         mRS.setMessageHandler(new MessageProcessor(act));
 
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b);
-        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, outb);
+        mInPixelsAllocation = ipact.mInPixelsAllocation;
+        mInPixelsAllocation2 = ipact.mInPixelsAllocation2;
+        mOutPixelsAllocation = ipact.mOutPixelsAllocation;
 
         createTest(act.getResources());
     }
@@ -135,8 +134,7 @@
     }
 
     public void destroy() {
-        mRS.destroy();
-        mRS = null;
+        mRS.setMessageHandler(null);
     }
 
     public void updateBitmap(Bitmap b) {
diff --git a/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml b/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml
index c7dcca5..ecb736b 100644
--- a/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml
+++ b/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml
@@ -53,7 +53,7 @@
             android:layout_height="fill_parent"
             android:layout_weight="3" >
 
-            <ImageView
+            <TextureView
                 android:id="@+id/format_view"
                 android:layout_height="0dp"
                 android:layout_width="fill_parent"
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java
index 89eec2c..62dcaa8 100644
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java
+++ b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@
     private int mPreviewTexWidth;
     private int mPreviewTexHeight;
 
-    private ImageView mFormatView;
+    //private TextureView mFormatView;
 
     private Spinner mCameraSpinner;
     private Spinner mResolutionSpinner;
@@ -77,7 +77,8 @@
     private Camera.Size mNextPreviewSize;
     private Camera.Size mPreviewSize;
 
-    private Bitmap mCallbackBitmap;
+    private TextureView mOutputView;
+    //private Bitmap mCallbackBitmap;
 
     private static final int STATE_OFF = 0;
     private static final int STATE_PREVIEW = 1;
@@ -97,7 +98,7 @@
         setContentView(R.layout.cf_main);
 
         mPreviewView = (TextureView) findViewById(R.id.preview_view);
-        mFormatView = (ImageView) findViewById(R.id.format_view);
+        mOutputView = (TextureView) findViewById(R.id.format_view);
 
         mPreviewView.setSurfaceTextureListener(this);
 
@@ -115,8 +116,9 @@
         mResolutionSpinner = (Spinner) findViewById(R.id.resolution_selection);
         mResolutionSpinner.setOnItemSelectedListener(mResolutionSelectedListener);
 
-
         mRS = RenderScript.create(this);
+        mFilterYuv = new RsYuv(mRS);
+        mOutputView.setSurfaceTextureListener(mFilterYuv);
     }
 
     @Override
@@ -227,8 +229,8 @@
 
         // Set initial values
 
-        mNextPreviewSize = mPreviewSizes.get(0);
-        mResolutionSpinner.setSelection(0);
+        mNextPreviewSize = mPreviewSizes.get(15);
+        mResolutionSpinner.setSelection(15);
 
         if (mPreviewTexture != null) {
             startPreview();
@@ -271,6 +273,7 @@
                 mPreviewTexHeight * (1 - heightRatio/widthRatio)/2);
 
         mPreviewView.setTransform(transform);
+        mOutputView.setTransform(transform);
 
         mPreviewSize   = mNextPreviewSize;
 
@@ -305,7 +308,7 @@
 
             long t1 = java.lang.System.currentTimeMillis();
 
-            mFilterYuv.execute(data, mCallbackBitmap);
+            mFilterYuv.execute(data);
 
             long t2 = java.lang.System.currentTimeMillis();
             mTiming[mTimingSlot++] = t2 - t1;
@@ -325,7 +328,7 @@
         }
 
         protected void onPostExecute(Boolean result) {
-            mFormatView.invalidate();
+            mOutputView.invalidate();
         }
 
     }
@@ -355,21 +358,13 @@
 
         mProcessInProgress = true;
 
-        if (mCallbackBitmap == null ||
-                mPreviewSize.width != mCallbackBitmap.getWidth() ||
-                mPreviewSize.height != mCallbackBitmap.getHeight() ) {
-            mCallbackBitmap =
-                    Bitmap.createBitmap(
-                        mPreviewSize.width, mPreviewSize.height,
-                        Bitmap.Config.ARGB_8888);
-            mFilterYuv = new RsYuv(mRS, getResources(), mPreviewSize.width, mPreviewSize.height);
-            mFormatView.setImageBitmap(mCallbackBitmap);
+        if ((mFilterYuv == null) ||
+            (mPreviewSize.width != mFilterYuv.getWidth()) ||
+            (mPreviewSize.height != mFilterYuv.getHeight()) ) {
+
+            mFilterYuv.reset(mPreviewSize.width, mPreviewSize.height);
         }
 
-
-        mFormatView.invalidate();
-
-        mCamera.addCallbackBuffer(data);
         mProcessInProgress = true;
         new ProcessPreviewDataTask().execute(data);
     }
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java
index 978ae12..12d3185 100644
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java
+++ b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
 
 import android.graphics.Bitmap;
 
-public class RsYuv
+public class RsYuv implements TextureView.SurfaceTextureListener
 {
     private int mHeight;
     private int mWidth;
@@ -43,36 +43,109 @@
     private Allocation mAllocationIn;
     private ScriptC_yuv mScript;
     private ScriptIntrinsicYuvToRGB mYuv;
+    private boolean mHaveSurface;
+    private SurfaceTexture mSurface;
+    private ScriptGroup mGroup;
 
-    RsYuv(RenderScript rs, Resources res, int width, int height) {
+    RsYuv(RenderScript rs) {
+        mRS = rs;
+        mScript = new ScriptC_yuv(mRS);
+        mYuv = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(mRS));
+    }
+
+    void setupSurface() {
+        if (mAllocationOut != null) {
+            mAllocationOut.setSurfaceTexture(mSurface);
+        }
+        if (mSurface != null) {
+            mHaveSurface = true;
+        } else {
+            mHaveSurface = false;
+        }
+    }
+
+    void reset(int width, int height) {
+        if (mAllocationOut != null) {
+            mAllocationOut.destroy();
+        }
+
+        android.util.Log.v("cpa", "reset " + width + ", " + height);
         mHeight = height;
         mWidth = width;
-        mRS = rs;
-        mScript = new ScriptC_yuv(mRS, res, R.raw.yuv);
         mScript.invoke_setSize(mWidth, mHeight);
 
-        mYuv = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(mRS));
-
         Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
         tb.setX(mWidth);
         tb.setY(mHeight);
+        Type t = tb.create();
+        mAllocationOut = Allocation.createTyped(mRS, t, Allocation.USAGE_SCRIPT |
+                                                        Allocation.USAGE_IO_OUTPUT);
 
-        mAllocationOut = Allocation.createTyped(rs, tb.create());
-        mAllocationIn = Allocation.createSized(rs, Element.U8(mRS), (mHeight * mWidth) +
-                                               ((mHeight / 2) * (mWidth / 2) * 2));
 
+        tb = new Type.Builder(mRS, Element.createPixel(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV));
+        tb.setX(mWidth);
+        tb.setY(mHeight);
+        tb.setYuvFormat(android.graphics.ImageFormat.NV21);
+        mAllocationIn = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_SCRIPT);
         mYuv.setInput(mAllocationIn);
+        setupSurface();
+
+
+        ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
+        b.addKernel(mScript.getKernelID_root());
+        b.addKernel(mYuv.getKernelID());
+        b.addConnection(t, mYuv.getKernelID(), mScript.getKernelID_root());
+        mGroup = b.create();
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+    public int getHeight() {
+        return mHeight;
     }
 
     private long mTiming[] = new long[50];
     private int mTimingSlot = 0;
 
-    void execute(byte[] yuv, Bitmap b) {
+    void execute(byte[] yuv) {
         mAllocationIn.copyFrom(yuv);
-        mYuv.forEach(mAllocationOut);
-        mScript.forEach_root(mAllocationOut, mAllocationOut);
-        mAllocationOut.copyTo(b);
+        if (mHaveSurface) {
+            mGroup.setOutput(mScript.getKernelID_root(), mAllocationOut);
+            mGroup.execute();
+
+            //mYuv.forEach(mAllocationOut);
+            //mScript.forEach_root(mAllocationOut, mAllocationOut);
+            mAllocationOut.ioSendOutput();
+        }
     }
 
+
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        android.util.Log.v("cpa", "onSurfaceTextureAvailable " + surface);
+        mSurface = surface;
+        setupSurface();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        android.util.Log.v("cpa", "onSurfaceTextureSizeChanged " + surface);
+        mSurface = surface;
+        setupSurface();
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        android.util.Log.v("cpa", "onSurfaceTextureDestroyed " + surface);
+        mSurface = surface;
+        setupSurface();
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+    }
 }
 
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs
index 884812d..c4f698f 100644
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs
+++ b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs
@@ -1,7 +1,7 @@
 
 #pragma version(1)
 #pragma rs java_package_name(com.android.rs.livepreview)
-#pragma rs_fp_relaxed
+//#pragma rs_fp_relaxed
 
 static int gWidth;
 static int gHeight;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
index 782f788..97f3a32 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
@@ -33,6 +33,10 @@
         Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
         int X = 5;
         int Y = 7;
+        final int xStart = 2;
+        final int xEnd = 5;
+        final int yStart = 3;
+        final int yEnd = 6;
         s.set_dimX(X);
         s.set_dimY(Y);
         typeBuilder.setX(X).setY(Y);
@@ -41,12 +45,16 @@
         s.set_s(s);
         s.set_ain(A);
         s.set_aout(A);
-        s.set_xStart(2);
-        s.set_xEnd(5);
-        s.set_yStart(3);
-        s.set_yEnd(6);
+        s.set_xStart(xStart);
+        s.set_xEnd(xEnd);
+        s.set_yStart(yStart);
+        s.set_yEnd(yEnd);
         s.forEach_zero(A);
 
+        Script.LaunchOptions sc = new Script.LaunchOptions();
+        sc.setX(xStart, xEnd).setY(yStart, yEnd);
+        s.forEach_root(A, sc);
+
         return;
     }
 
@@ -55,6 +63,7 @@
         ScriptC_foreach_bounds s = new ScriptC_foreach_bounds(pRS);
         pRS.setMessageHandler(mRsMessage);
         initializeGlobals(pRS, s);
+        s.invoke_verify_root();
         s.invoke_foreach_bounds_test();
         pRS.finish();
         waitForMessage();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
index 89df090..fa76390 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
@@ -7,6 +7,8 @@
 int yStart = 0;
 int yEnd = 0;
 
+static bool failed = false;
+
 rs_script s;
 rs_allocation aRaw;
 rs_allocation ain;
@@ -27,9 +29,6 @@
     for (j = 0; j < dimY; j++) {
         for (i = 0; i < dimX; i++) {
             int v = rsGetElementAt_int(aRaw, i, j);
-            rsDebug("i: ", i);
-            rsDebug("j: ", j);
-            rsDebug("a[j][i]: ", v);
             if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
                 _RS_ASSERT(v == 0);
             } else {
@@ -48,20 +47,11 @@
     return failed;
 }
 
-void foreach_bounds_test() {
-    static bool failed = false;
-
-    rs_script_call_t rssc = {0};
-    rssc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    rssc.xStart = xStart;
-    rssc.xEnd = xEnd;
-    rssc.yStart = yStart;
-    rssc.yEnd = yEnd;
-
-    rsForEach(s, ain, aout, NULL, 0, &rssc);
-
+void verify_root() {
     failed |= test_root_output();
+}
 
+void foreach_bounds_test() {
     if (failed) {
         rsSendToClientBlocking(RS_MSG_TEST_FAILED);
     }
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 746ac06..03871f6 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -222,37 +222,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
-        try {
-            mWm.moveAppToken(0, null);
-            fail("IWindowManager.moveAppToken did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-        
-        try {
-            mWm.moveAppTokensToTop(null);
-            fail("IWindowManager.moveAppTokensToTop did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-        
-        try {
-            mWm.moveAppTokensToBottom(null);
-            fail("IWindowManager.moveAppTokensToBottom did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-	}    
+    }
 
     @SmallTest
     public void testDISABLE_KEYGUARD() {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 8701cc8..2414d70 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -188,6 +188,11 @@
         return delegate.mStyle;
     }
 
+    @LayoutlibDelegate
+    /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
+        // This is for device testing only: pass
+    }
+
     // ---- Private delegate/helper methods ----
 
     private Typeface_Delegate(String family, int style) {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 9f116fc..278413e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -110,6 +110,12 @@
     }
 
     @Override
+    public void setOverscan(int displayId, int left, int top, int right, int bottom)
+            throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void closeSystemDialogs(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
@@ -204,24 +210,6 @@
     }
 
     @Override
-    public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
     public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index bf82792..b971fc33 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -277,7 +277,6 @@
     /**
      * The enterprise configuration details specifying the EAP method,
      * certificates and other settings associated with the EAP.
-     * @hide
      */
     public WifiEnterpriseConfig enterpriseConfig;
 
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 7313e7e..95ffb1c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -42,7 +42,10 @@
 import java.util.HashMap;
 import java.util.Map;
 
-/** Enterprise configuration details for Wi-Fi @hide */
+/** 
+ * Enterprise configuration details for Wi-Fi. Stores details about the EAP method
+ * and any associated credentials.
+ */
 public class WifiEnterpriseConfig implements Parcelable {
     private static final String TAG = "WifiEnterpriseConfig";
     /**
@@ -211,22 +214,32 @@
                 }
             };
 
+    /** The Extensible Authentication Protocol method used */
     public static final class Eap {
-        /* NONE represents an empty enterprise config */
+        /** No EAP method used. Represents an empty config */
         public static final int NONE    = -1;
+        /** Protected EAP */
         public static final int PEAP    = 0;
+        /** EAP-Transport Layer Security */
         public static final int TLS     = 1;
+        /** EAP-Tunneled Transport Layer Security */
         public static final int TTLS    = 2;
+        /** EAP-Password */
         public static final int PWD     = 3;
         /** @hide */
         public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD" };
     }
 
+    /** The inner authentication method used */
     public static final class Phase2 {
         public static final int NONE        = 0;
+        /** Password Authentication Protocol */
         public static final int PAP         = 1;
+        /** Microsoft Challenge Handshake Authentication Protocol */
         public static final int MSCHAP      = 2;
+        /** Microsoft Challenge Handshake Authentication Protocol v2 */
         public static final int MSCHAPV2    = 3;
+        /** Generic Token Card */
         public static final int GTC         = 4;
         private static final String PREFIX = "auth=";
         /** @hide */
@@ -249,6 +262,7 @@
      * Set the EAP authentication method.
      * @param  eapMethod is one {@link Eap#PEAP}, {@link Eap#TLS}, {@link Eap#TTLS} or
      *                   {@link Eap#PWD}
+     * @throws IllegalArgumentException on an invalid eap method
      */
     public void setEapMethod(int eapMethod) {
         switch (eapMethod) {
@@ -279,6 +293,7 @@
      * @param phase2Method is the inner authentication method and can be one of {@link Phase2#NONE},
      *                     {@link Phase2#PAP}, {@link Phase2#MSCHAP}, {@link Phase2#MSCHAPV2},
      *                     {@link Phase2#GTC}
+     * @throws IllegalArgumentException on an invalid phase2 method
      *
      */
     public void setPhase2Method(int phase2Method) {
@@ -378,7 +393,10 @@
      * Specify a X.509 certificate that identifies the server.
      *
      * <p>A default name is automatically assigned to the certificate and used
-     * with this configuration.
+     * with this configuration. The framework takes care of installing the
+     * certificate when the config is saved and removing the certificate when
+     * the config is removed.
+     *
      * @param cert X.509 CA certificate
      * @throws IllegalArgumentException if not a CA certificate
      */
@@ -425,9 +443,13 @@
      * Specify a private key and client certificate for client authorization.
      *
      * <p>A default name is automatically assigned to the key entry and used
-     * with this configuration.
+     * with this configuration.  The framework takes care of installing the
+     * key entry when the config is saved and removing the key entry when
+     * the config is removed.
+
      * @param privateKey
      * @param clientCertificate
+     * @throws IllegalArgumentException for an invalid key or certificate.
      */
     public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
         if (clientCertificate != null) {