Merge "Remove surfaceTextureOpaque test."
diff --git a/api/current.txt b/api/current.txt
index d661daa..369cfeb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26289,6 +26289,10 @@
     field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
     field public static final deprecated int MEMORY_TYPE_NORMAL = 0; // 0x0
     field public static final deprecated int MEMORY_TYPE_PUSH_BUFFERS = 3; // 0x3
+    field public static final int ROTATION_ANIMATION_CHANGED = 4096; // 0x1000
+    field public static final int ROTATION_ANIMATION_CROSSFADE = 1; // 0x1
+    field public static final int ROTATION_ANIMATION_JUMPCUT = 2; // 0x2
+    field public static final int ROTATION_ANIMATION_ROTATE = 0; // 0x0
     field public static final int SCREEN_BRIGHTNESS_CHANGED = 2048; // 0x800
     field public static final int SCREEN_ORIENTATION_CHANGED = 1024; // 0x400
     field public static final int SOFT_INPUT_ADJUST_NOTHING = 48; // 0x30
@@ -26339,6 +26343,7 @@
     field public float horizontalWeight;
     field public deprecated int memoryType;
     field public java.lang.String packageName;
+    field public int rotationAnimation;
     field public float screenBrightness;
     field public int screenOrientation;
     field public int softInputMode;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4a0ee48..ebca041 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -448,7 +448,7 @@
      * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
      * @hide
      */
-    private static class Action implements Parcelable {
+    public static class Action implements Parcelable {
         public int icon;
         public CharSequence title;
         public PendingIntent actionIntent;
@@ -500,7 +500,10 @@
         };
     }
 
-    private Action[] actions;
+    /**
+     * @hide
+     */
+    public Action[] actions;
 
     /**
      * Constructs a Notification object with default values.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index b678df7..44aa06f 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -24,6 +24,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -227,7 +228,6 @@
         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>();
@@ -259,8 +259,17 @@
         // 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);
+        // IOExceptions and similar, and treats them as non-fatal, so we rely on that; and
+        // we know a priori that processes running as the system UID are not permitted to
+        // access external storage, so we check for that as well to avoid nastygrams in
+        // the log.
+        if (Process.myUid() != Process.SYSTEM_UID) {
+            File efLocation = getExternalFilesDir(null);
+            if (efLocation != null) {
+                fullBackupFileTree(packageName, FullBackup.MANAGED_EXTERNAL_TREE_TOKEN,
+                        efLocation.getCanonicalPath(), null, data);
+            }
+        }
     }
 
     /**
@@ -281,7 +290,7 @@
         String spDir;
         String cacheDir;
         String libDir;
-        String efDir;
+        String efDir = null;
         String filePath;
 
         ApplicationInfo appInfo = getApplicationInfo();
@@ -295,7 +304,14 @@
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
-            efDir = getExternalFilesDir(null).getCanonicalPath();
+
+            // may or may not have external files access to attempt backup/restore there
+            if (Process.myUid() != Process.SYSTEM_UID) {
+                File efLocation = getExternalFilesDir(null);
+                if (efLocation != null) {
+                    efDir = efLocation.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.
@@ -324,7 +340,7 @@
         } else if (filePath.startsWith(mainDir)) {
             domain = FullBackup.ROOT_TREE_TOKEN;
             rootpath = mainDir;
-        } else if (filePath.startsWith(efDir)) {
+        } else if ((efDir != null) && filePath.startsWith(efDir)) {
             domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
             rootpath = efDir;
         } else {
@@ -451,7 +467,13 @@
         } else if (domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
             basePath = getCacheDir().getCanonicalPath();
         } else if (domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
-            basePath = getExternalFilesDir(null).getCanonicalPath();
+            // make sure we can try to restore here before proceeding
+            if (Process.myUid() != Process.SYSTEM_UID) {
+                File efLocation = getExternalFilesDir(null);
+                if (efLocation != null) {
+                    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/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 000c56c..3a04c27 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -62,7 +62,7 @@
      * NetworkInfo for the new network is also passed as an extra. This lets
      * any receivers of the broadcast know that they should not necessarily
      * tell the user that no data traffic will be possible. Instead, the
-     * reciever should expect another broadcast soon, indicating either that
+     * receiver should expect another broadcast soon, indicating either that
      * the failover attempt succeeded (and so there is still overall data
      * connectivity), or that the failover attempt failed, meaning that all
      * connectivity has been lost.
@@ -70,6 +70,7 @@
      * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
      * is set to {@code true} if there are no connected networks at all.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
@@ -78,6 +79,7 @@
      *
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String CONNECTIVITY_ACTION_IMMEDIATE =
             "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE";
 
@@ -149,8 +151,8 @@
     /**
      * Broadcast action to indicate the change of data activity status
      * (idle or active) on a network in a recent period.
-     * The network becomes active when data transimission is started, or
-     * idle if there is no data transimition for a period of time.
+     * The network becomes active when data transmission is started, or
+     * idle if there is no data transmission for a period of time.
      * {@hide}
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -198,32 +200,42 @@
      * the network and it's condition.
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String INET_CONDITION_ACTION =
             "android.net.conn.INET_CONDITION_ACTION";
 
     /**
-     * Broadcast Action: A tetherable connection has come or gone
-     * TODO - finish the doc
+     * Broadcast Action: A tetherable connection has come or gone.
+     * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
+     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and
+     * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
+     * the current state of tethering.  Each include a list of
+     * interface names in that state (may be empty).
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TETHER_STATE_CHANGED =
             "android.net.conn.TETHER_STATE_CHANGED";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces configured for
+     * tethering and currently available for tethering.
      */
     public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces currently tethered
+     * (ie, has dhcp support and packets potentially forwarded/NATed)
      */
     public static final String EXTRA_ACTIVE_TETHER = "activeArray";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces we tried to tether and
+     * failed.  Use {@link #getLastTetherError} to find the error code
+     * for any interfaces listed here.
      */
     public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
@@ -233,6 +245,7 @@
      * notification.
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED =
             "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED";
     /**
@@ -243,61 +256,63 @@
     public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal";
 
     /**
-     * The absence of APN..
+     * The absence of a connection type.
      * @hide
      */
     public static final int TYPE_NONE        = -1;
 
     /**
-     * The Default Mobile data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The Mobile data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route)
      */
     public static final int TYPE_MOBILE      = 0;
     /**
-     * The Default WIFI data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The WIFI data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_WIFI        = 1;
     /**
-     * An MMS-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applications needing to talk to the carrier's Multimedia Messaging
-     * Service servers.  It may coexist with default data connections.
+     * An MMS-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is used by applications needing to talk to the carrier's
+     * Multimedia Messaging Service servers.
      */
     public static final int TYPE_MOBILE_MMS  = 2;
     /**
-     * A SUPL-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applications needing to talk to the carrier's Secure User Plane
-     * Location servers for help locating the device.  It may coexist with
-     * default data connections.
+     * A SUPL-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is used by applications needing to talk to the carrier's
+     * Secure User Plane Location servers for help locating the device.
      */
     public static final int TYPE_MOBILE_SUPL = 3;
     /**
-     * A DUN-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applicaitons performing a Dial Up Networking bridge so that
-     * the carrier is aware of DUN traffic.  It may coexist with default data
-     * connections.
+     * A DUN-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is sometimes by the system when setting up an upstream connection
+     * for tethering so that the carrier is aware of DUN traffic.
      */
     public static final int TYPE_MOBILE_DUN  = 4;
     /**
-     * A High Priority Mobile data connection.  This connection is typically
-     * the same as {@link #TYPE_MOBILE} but the routing setup is different.
-     * Only requesting processes will have access to the Mobile DNS servers
-     * and only IP's explicitly requested via {@link #requestRouteToHost}
-     * will route over this interface if a default route exists.
+     * A High Priority Mobile data connection.  This network type uses the
+     * same network interface as {@link #TYPE_MOBILE} but the routing setup
+     * is different.  Only requesting processes will have access to the
+     * Mobile DNS servers and only IP's explicitly requested via {@link #requestRouteToHost}
+     * will route over this interface if no default route exists.
      */
     public static final int TYPE_MOBILE_HIPRI = 5;
     /**
-     * The Default WiMAX data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The WiMAX data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_WIMAX       = 6;
 
     /**
-     * The Default Bluetooth data connection. When active, all data traffic
-     * will use this connection by default.
+     * The Bluetooth data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_BLUETOOTH   = 7;
 
@@ -307,25 +322,26 @@
     public static final int TYPE_DUMMY       = 8;
 
     /**
-     * The Default Ethernet data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The Ethernet data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_ETHERNET    = 9;
 
     /**
-     * Over the air Adminstration.
+     * Over the air Administration.
      * {@hide}
      */
     public static final int TYPE_MOBILE_FOTA = 10;
 
     /**
-     * IP Multimedia Subsystem
+     * IP Multimedia Subsystem.
      * {@hide}
      */
     public static final int TYPE_MOBILE_IMS  = 11;
 
     /**
-     * Carrier Branded Services
+     * Carrier Branded Services.
      * {@hide}
      */
     public static final int TYPE_MOBILE_CBS  = 12;
@@ -349,7 +365,7 @@
      *
      * @deprecated Since we support so many more networks now, the single
      *             network default network preference can't really express
-     *             the heirarchy.  Instead, the default is defined by the
+     *             the hierarchy.  Instead, the default is defined by the
      *             networkAttributes in config.xml.  You can determine
      *             the current value by calling {@link #getNetworkPreference()}
      *             from an App.
@@ -359,7 +375,11 @@
 
     /**
      * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in
-     * milliseconds.
+     * milliseconds.  This was introduced because IPv6 routes seem to take a
+     * moment to settle - trying network activity before the routes are adjusted
+     * can lead to packets using the wrong interface or having the wrong IP address.
+     * This delay is a bit crude, but in the future hopefully we will have kernel
+     * notifications letting us know when it's safe to use the new network.
      *
      * @hide
      */
@@ -367,11 +387,23 @@
 
     private final IConnectivityManager mService;
 
+    /**
+     * Tests if a given integer represents a valid network type.
+     * @param networkType the type to be tested
+     * @return a boolean.  {@code true} if the type is valid, else {@code false}
+     */
     public static boolean isNetworkTypeValid(int networkType) {
         return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
     }
 
-    /** {@hide} */
+    /**
+     * Returns a non-localized string representing a given network type.
+     * ONLY used for debugging output.
+     * @param type the type needing naming
+     * @return a String for the given type, or a string version of the type ("87")
+     * if no name is known.
+     * {@hide}
+     */
     public static String getNetworkTypeName(int type) {
         switch (type) {
             case TYPE_MOBILE:
@@ -407,7 +439,13 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Checks if a given type uses the cellular data connection.
+     * This should be replaced in the future by a network property.
+     * @param networkType the type to check
+     * @return a boolean - {@code true} if uses cellular network, else {@code false}
+     * {@hide}
+     */
     public static boolean isNetworkTypeMobile(int networkType) {
         switch (networkType) {
             case TYPE_MOBILE:
@@ -424,6 +462,17 @@
         }
     }
 
+    /**
+     * Specifies the preferred network type.  When the device has more
+     * than one type available the preferred network type will be used.
+     * Note that this made sense when we only had 2 network types,
+     * but with more and more default networks we need an array to list
+     * their ordering.  This will be deprecated soon.
+     *
+     * @param preference the network type to prefer over all others.  It is
+     *         unspecified what happens to the old preferred network in the
+     *         overall ordering.
+     */
     public void setNetworkPreference(int preference) {
         try {
             mService.setNetworkPreference(preference);
@@ -431,6 +480,17 @@
         }
     }
 
+    /**
+     * Retrieves the current preferred network type.
+     * Note that this made sense when we only had 2 network types,
+     * but with more and more default networks we need an array to list
+     * their ordering.  This will be deprecated soon.
+     *
+     * @return an integer representing the preferred network type
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public int getNetworkPreference() {
         try {
             return mService.getNetworkPreference();
@@ -440,11 +500,16 @@
     }
 
     /**
-     * Returns details about the currently active data network. When connected,
-     * this network is the default route for outgoing connections. You should
-     * always check {@link NetworkInfo#isConnected()} before initiating network
-     * traffic. This may return {@code null} when no networks are available.
-     * <p>This method requires the caller to hold the permission
+     * Returns details about the currently active default data network. When
+     * connected, this network is the default route for outgoing connections.
+     * You should always check {@link NetworkInfo#isConnected()} before initiating
+     * network traffic. This may return {@code null} when there is no default
+     * network.
+     *
+     * @return a {@link NetworkInfo} object for the current default network
+     *        or {@code null} if no network default network is currently active
+     *
+     * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public NetworkInfo getActiveNetworkInfo() {
@@ -455,7 +520,19 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns details about the currently active default data network
+     * for a given uid.  This is for internal use only to avoid spying
+     * other apps.
+     *
+     * @return a {@link NetworkInfo} object for the current default network
+     *        for the given uid or {@code null} if no default network is
+     *        available for the specified uid.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+     * {@hide}
+     */
     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
         try {
             return mService.getActiveNetworkInfoForUid(uid);
@@ -464,6 +541,19 @@
         }
     }
 
+    /**
+     * Returns connection status information about a particular
+     * network type.
+     *
+     * @param networkType integer specifying which networkType in
+     *        which you're interested.
+     * @return a {@link NetworkInfo} object for the requested
+     *        network type or {@code null} if the type is not
+     *        supported by the device.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public NetworkInfo getNetworkInfo(int networkType) {
         try {
             return mService.getNetworkInfo(networkType);
@@ -472,6 +562,16 @@
         }
     }
 
+    /**
+     * Returns connection status information about all network
+     * types supported by the device.
+     *
+     * @return an array of {@link NetworkInfo} objects.  Check each
+     * {@link NetworkInfo#getType} for which type each applies.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public NetworkInfo[] getAllNetworkInfo() {
         try {
             return mService.getAllNetworkInfo();
@@ -480,7 +580,17 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns the IP information for the current default network.
+     *
+     * @return a {@link LinkProperties} object describing the IP info
+     *        for the current default network, or {@code null} if there
+     *        is no current default network.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * {@hide}
+     */
     public LinkProperties getActiveLinkProperties() {
         try {
             return mService.getActiveLinkProperties();
@@ -489,7 +599,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns the IP information for a given network type.
+     *
+     * @param networkType the network type of interest.
+     * @return a {@link LinkProperties} object describing the IP info
+     *        for the given networkType, or {@code null} if there is
+     *        no current default network.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * {@hide}
+     */
     public LinkProperties getLinkProperties(int networkType) {
         try {
             return mService.getLinkProperties(networkType);
@@ -498,7 +619,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Tells each network type to set its radio power state as directed.
+     *
+     * @param turnOn a boolean, {@code true} to turn the radios on,
+     *        {@code false} to turn them off.
+     * @return a boolean, {@code true} indicating success.  All network types
+     *        will be tried, even if some fail.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+     * {@hide}
+     */
     public boolean setRadios(boolean turnOn) {
         try {
             return mService.setRadios(turnOn);
@@ -507,7 +639,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Tells a given networkType to set its radio power state as directed.
+     *
+     * @param networkType the int networkType of interest.
+     * @param turnOn a boolean, {@code true} to turn the radio on,
+     *        {@code} false to turn it off.
+     * @return a boolean, {@code true} indicating success.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+     * {@hide}
+     */
     public boolean setRadio(int networkType, boolean turnOn) {
         try {
             return mService.setRadio(networkType, turnOn);
@@ -642,6 +785,9 @@
      * network is active. Quota status can change rapidly, so these values
      * shouldn't be cached.
      *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
      * @hide
      */
     public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
@@ -656,6 +802,9 @@
      * Gets the value of the setting for enabling Mobile data.
      *
      * @return Whether mobile data is enabled.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public boolean getMobileDataEnabled() {
@@ -669,8 +818,8 @@
     /**
      * Sets the persisted value for enabling/disabling Mobile data.
      *
-     * @param enabled Whether the mobile data connection should be
-     *            used or not.
+     * @param enabled Whether the user wants the mobile data connection used
+     *            or not.
      * @hide
      */
     public void setMobileDataEnabled(boolean enabled) {
@@ -693,6 +842,13 @@
     }
 
     /**
+     * Get the set of tetherable, available interfaces.  This list is limited by
+     * device configuration and current interface existence.
+     *
+     * @return an array of 0 or more Strings of tetherable interface names.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableIfaces() {
@@ -704,6 +860,12 @@
     }
 
     /**
+     * Get the set of tethered interfaces.
+     *
+     * @return an array of 0 or more String of currently tethered interface names.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheredIfaces() {
@@ -715,6 +877,18 @@
     }
 
     /**
+     * Get the set of interface names which attempted to tether but
+     * failed.  Re-attempting to tether may cause them to reset to the Tethered
+     * state.  Alternatively, causing the interface to be destroyed and recreated
+     * may cause them to reset to the available state.
+     * {@link ConnectivityManager#getLastTetherError} can be used to get more
+     * information on the cause of the errors.
+     *
+     * @return an array of 0 or more String indicating the interface names
+     *        which failed to tether.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheringErroredIfaces() {
@@ -726,7 +900,19 @@
     }
 
     /**
-     * @return error A TETHER_ERROR value indicating success or failure type
+     * Attempt to tether the named interface.  This will setup a dhcp server
+     * on the interface, forward and NAT IP packets and forward DNS requests
+     * to the best active upstream network interface.  Note that if no upstream
+     * IP network interface is available, dhcp will still run and traffic will be
+     * allowed between the tethered devices and this device, though upstream net
+     * access will of course fail until an upstream network interface becomes
+     * active.
+     *
+     * @param iface the interface name to tether.
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int tether(String iface) {
@@ -738,7 +924,13 @@
     }
 
     /**
-     * @return error A TETHER_ERROR value indicating success or failure type
+     * Stop tethering the named interface.
+     *
+     * @param iface the interface name to untether.
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int untether(String iface) {
@@ -750,6 +942,14 @@
     }
 
     /**
+     * Check if the device allows for tethering.  It may be disabled via
+     * {@code ro.tether.denied} system property, {@link Settings#TETHER_SUPPORTED} or
+     * due to device configuration.
+     *
+     * @return a boolean - {@code true} indicating Tethering is supported.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public boolean isTetheringSupported() {
@@ -761,6 +961,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * USB network interfaces.  If USB tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable usb interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableUsbRegexs() {
@@ -772,6 +981,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * Wifi network interfaces.  If Wifi tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable wifi interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableWifiRegexs() {
@@ -783,6 +1001,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * Bluetooth network interfaces.  If Bluetooth tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable bluetooth interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableBluetoothRegexs() {
@@ -794,6 +1021,17 @@
     }
 
     /**
+     * Attempt to both alter the mode of USB and Tethering of USB.  A
+     * utility method to deal with some of the complexity of USB - will
+     * attempt to switch to Rndis and subsequently tether the resulting
+     * interface on {@code true} or turn off tethering and switch off
+     * Rndis on {@code false}.
+     *
+     * @param enable a boolean - {@code true} to enable tethering
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int setUsbTethering(boolean enable) {
@@ -828,9 +1066,15 @@
     public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
 
     /**
-     * @param iface The name of the interface we're interested in
+     * Get a more detailed error code after a Tethering or Untethering
+     * request asynchronously failed.
+     *
+     * @param iface The name of the interface of interest
      * @return error The error code of the last error tethering or untethering the named
      *               interface
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public int getLastTetherError(String iface) {
@@ -842,9 +1086,16 @@
     }
 
     /**
-     * Ensure the device stays awake until we connect with the next network
-     * @param forWhome The name of the network going down for logging purposes
+     * Try to ensure the device stays awake until we connect with the next network.
+     * Actually just holds a wakelock for a number of seconds while we try to connect
+     * to any default networks.  This will expire if the timeout passes or if we connect
+     * to a default after this is called.  For internal use only.
+     *
+     * @param forWhom the name of the network going down for logging purposes
      * @return {@code true} on success, {@code false} on failure
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public boolean requestNetworkTransitionWakelock(String forWhom) {
@@ -857,8 +1108,14 @@
     }
 
     /**
+     * Report network connectivity status.  This is currently used only
+     * to alter status bar UI.
+     *
      * @param networkType The type of network you want to report on
      * @param percentage The quality of the connection 0 is bad, 100 is good
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#STATUS_BAR}.
      * {@hide}
      */
     public void reportInetCondition(int networkType, int percentage) {
@@ -869,7 +1126,16 @@
     }
 
     /**
-     * @param proxyProperties The definition for the new global http proxy
+     * Set a network-independent global http proxy.  This is not normally what you want
+     * for typical HTTP proxies - they are general network dependent.  However if you're
+     * doing something unusual like general internal filtering this may be useful.  On
+     * a private network where the proxy is not accessible, you may break HTTP using this.
+     *
+     * @param proxyProperties The a {@link ProxyProperites} object defining the new global
+     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public void setGlobalProxy(ProxyProperties p) {
@@ -880,7 +1146,13 @@
     }
 
     /**
-     * @return proxyProperties for the current global proxy
+     * Retrieve any network-independent global HTTP proxy.
+     *
+     * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+     *        if no global HTTP proxy is set.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public ProxyProperties getGlobalProxy() {
@@ -892,7 +1164,14 @@
     }
 
     /**
-     * @return proxyProperties for the current proxy (global if set, network specific if not)
+     * Get the HTTP proxy settings for the current default network.  Note that
+     * if a global proxy is set, it will override any per-network setting.
+     *
+     * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+     *        HTTP proxy is active.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public ProxyProperties getProxy() {
@@ -904,8 +1183,15 @@
     }
 
     /**
+     * Sets a secondary requirement bit for the given networkType.
+     * This requirement bit is generally under the control of the carrier
+     * or its agents and is not directly controlled by the user.
+     *
      * @param networkType The network who's dependence has changed
-     * @param met Boolean - true if network use is ok, false if not
+     * @param met Boolean - true if network use is OK, false if not
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public void setDataDependency(int networkType, boolean met) {
@@ -919,11 +1205,15 @@
      * Returns true if the hardware supports the given network type
      * else it returns false.  This doesn't indicate we have coverage
      * or are authorized onto a network, just whether or not the
-     * hardware supports it.  For example a gsm phone without a sim
-     * should still return true for mobile data, but a wifi only tablet
-     * would return false.
-     * @param networkType The nework type we'd like to check
-     * @return true if supported, else false
+     * hardware supports it.  For example a GSM phone without a SIM
+     * should still return {@code true} for mobile data, but a wifi only
+     * tablet would return {@code false}.
+     *
+     * @param networkType The network type we'd like to check
+     * @return {@code true} if supported, else {@code false}
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public boolean isNetworkSupported(int networkType) {
@@ -936,9 +1226,16 @@
     /**
      * Returns if the currently active data network is metered. A network is
      * classified as metered when the user is sensitive to heavy data usage on
-     * that connection. You should check this before doing large data transfers,
-     * and warn the user or delay the operation until another network is
-     * available.
+     * that connection due to monetary costs, data limitations or
+     * battery/performance issues. You should check this before doing large
+     * data transfers, and warn the user or delay the operation until another
+     * network is available.
+     *
+     * @return {@code true} if large transfers should be avoided, otherwise
+     *        {@code false}.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public boolean isActiveNetworkMetered() {
         try {
@@ -948,7 +1245,15 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * If the LockdownVpn mechanism is enabled, updates the vpn
+     * with a reload of its profile.
+     *
+     * @return a boolean with {@code} indicating success
+     *
+     * <p>This method can only be called by the system UID
+     * {@hide}
+     */
     public boolean updateLockdownVpn() {
         try {
             return mService.updateLockdownVpn();
@@ -958,6 +1263,14 @@
     }
 
     /**
+     * Signal that the captive portal check on the indicated network
+     * is complete and we can turn the network on for general use.
+     *
+     * @param info the {@link NetworkInfo} object for the networkType
+     *        in question.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public void captivePortalCheckComplete(NetworkInfo info) {
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 152827d..9522112 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -169,10 +169,10 @@
      * </ul>
      */
     public static final Pattern PHONE
-        = Pattern.compile(                                  // sdd = space, dot, or dash
-                "(\\+[0-9]+[\\- \\.]*)?"                    // +<digits><sdd>*
-                + "(\\([0-9]+\\)[\\- \\.]*)?"               // (<digits>)<sdd>*
-                + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> 
+        = Pattern.compile(                      // sdd = space, dot, or dash
+                "(\\+[0-9]+[\\- \\.]*)?"        // +<digits><sdd>*
+                + "(\\([0-9]+\\)[\\- \\.]*)?"   // (<digits>)<sdd>*
+                + "([0-9][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit>
 
     /**
      *  Convenience method to take all of the non-null matching groups in a
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 7ff8d09..6c48e43 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -497,22 +497,22 @@
 
     @Override
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
-        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
+        return nQuickReject(mRenderer, left, top, right, bottom);
     }
     
     private static native boolean nQuickReject(int renderer, float left, float top,
-            float right, float bottom, int edge);
+            float right, float bottom);
 
     @Override
     public boolean quickReject(Path path, EdgeType type) {
         path.computeBounds(mPathBounds, true);
         return nQuickReject(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom, type.nativeInt);
+                mPathBounds.right, mPathBounds.bottom);
     }
 
     @Override
     public boolean quickReject(RectF rect, EdgeType type) {
-        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom, type.nativeInt);
+        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index de64e14..03a9b09 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -75,7 +75,6 @@
 
     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.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 9f50065..7ef7e2b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -339,11 +339,6 @@
         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);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d236561..bf330f3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1193,6 +1193,37 @@
         public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
 
         /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will rotate in or out following a rotation.
+         */
+        public static final int ROTATION_ANIMATION_ROTATE = 0;
+
+        /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will fade in or out following a rotation.
+         */
+        public static final int ROTATION_ANIMATION_CROSSFADE = 1;
+
+        /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will immediately disappear or appear following
+         * a rotation.
+         */
+        public static final int ROTATION_ANIMATION_JUMPCUT = 2;
+
+        /**
+         * Define the animation used on this window for entry or exit following
+         * a rotation. This only works if the incoming and outgoing topmost
+         * opaque windows have the #FLAG_FULLSCREEN bit set and are not covered
+         * by other windows.
+         * 
+         * @see #ROTATION_ANIMATION_ROTATE
+         * @see #ROTATION_ANIMATION_CROSSFADE
+         * @see #ROTATION_ANIMATION_JUMPCUT
+         */
+        public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
+
+        /**
          * Identifier for this window.  This will usually be filled in for
          * you.
          */
@@ -1367,6 +1398,7 @@
             out.writeFloat(dimAmount);
             out.writeFloat(screenBrightness);
             out.writeFloat(buttonBrightness);
+            out.writeInt(rotationAnimation);
             out.writeStrongBinder(token);
             out.writeString(packageName);
             TextUtils.writeToParcel(mTitle, out, parcelableFlags);
@@ -1408,6 +1440,7 @@
             dimAmount = in.readFloat();
             screenBrightness = in.readFloat();
             buttonBrightness = in.readFloat();
+            rotationAnimation = in.readInt();
             token = in.readStrongBinder();
             packageName = in.readString();
             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -1432,18 +1465,19 @@
         public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
         public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
         public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
+        public static final int ROTATION_ANIMATION_CHANGED = 1<<12;
         /** {@hide} */
-        public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<12;
+        public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<13;
         /** {@hide} */
-        public static final int SYSTEM_UI_VISIBILITY_CHANGED = 1<<13;
+        public static final int SYSTEM_UI_VISIBILITY_CHANGED = 1<<14;
         /** {@hide} */
-        public static final int SYSTEM_UI_LISTENER_CHANGED = 1<<14;
+        public static final int SYSTEM_UI_LISTENER_CHANGED = 1<<15;
         /** {@hide} */
-        public static final int INPUT_FEATURES_CHANGED = 1<<15;
+        public static final int INPUT_FEATURES_CHANGED = 1<<16;
         /** {@hide} */
-        public static final int PRIVATE_FLAGS_CHANGED = 1<<16;
+        public static final int PRIVATE_FLAGS_CHANGED = 1<<17;
         /** {@hide} */
-        public static final int USER_ACTIVITY_TIMEOUT_CHANGED = 1<<17;
+        public static final int USER_ACTIVITY_TIMEOUT_CHANGED = 1<<18;
         /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
@@ -1543,6 +1577,10 @@
                 buttonBrightness = o.buttonBrightness;
                 changes |= BUTTON_BRIGHTNESS_CHANGED;
             }
+            if (rotationAnimation != o.rotationAnimation) {
+                rotationAnimation = o.rotationAnimation;
+                changes |= ROTATION_ANIMATION_CHANGED;
+            }
     
             if (screenOrientation != o.screenOrientation) {
                 screenOrientation = o.screenOrientation;
@@ -1645,6 +1683,10 @@
                 sb.append(" bbrt=");
                 sb.append(buttonBrightness);
             }
+            if (rotationAnimation != ROTATION_ANIMATION_ROTATE) {
+                sb.append(" rotAnim=");
+                sb.append(rotationAnimation);
+            }
             if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 sb.append(" compatible=true");
             }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 192eded..60779ce 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -684,6 +684,31 @@
     public int selectAnimationLw(WindowState win, int transit);
 
     /**
+     * Determine the animation to run for a rotation transition based on the
+     * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
+     * and whether it is currently fullscreen and frontmost.
+     * 
+     * @param anim The exiting animation resource id is stored in anim[0], the 
+     * entering animation resource id is stored in anim[1].
+     */
+    public void selectRotationAnimationLw(int anim[]);
+
+    /**
+     * Validate whether the current top fullscreen has specified the same
+     * {@link WindowManager.LayoutParams#rotationAnimation} value as that
+     * being passed in from the previous top fullscreen window.
+     *
+     * @param exitAnimId exiting resource id from the previous window.
+     * @param enterAnimId entering resource id from the previous window.
+     * @param forceDefault For rotation animations only, if true ignore the
+     * animation values and just return false.
+     * @return true if the previous values are still valid, false if they
+     * should be replaced with the default.
+     */
+    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+            boolean forceDefault);
+
+    /**
      * Create and return an animation to re-display a force hidden window.
      */
     public Animation createForceHideEnterAnimation(boolean onWallpaper);
@@ -909,6 +934,7 @@
      * @see android.app.KeyguardManager.KeyguardLock#disableKeyguard()
      * @see android.app.KeyguardManager.KeyguardLock#reenableKeyguard()
      */
+    @SuppressWarnings("javadoc")
     public void enableKeyguard(boolean enabled);
 
     /**
@@ -924,6 +950,7 @@
      * @param callback Callback to send the result back.
      * @see android.app.KeyguardManager#exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult)
      */
+    @SuppressWarnings("javadoc")
     void exitKeyguardSecurely(OnKeyguardExitResult callback);
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d0bfbe8..1321515 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -334,7 +334,8 @@
          * See {@link WebView#capturePicture} for details of the picture.
          *
          * @param view the WebView that owns the picture
-         * @param picture the new picture
+         * @param picture the new picture. Applications targetting Jelly
+         *         Bean MR2 or above will always receive a null Picture.
          * @deprecated Deprecated due to internal changes.
          */
         @Deprecated
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 3ded1cd..19784a4 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7909,7 +7909,11 @@
         if (mPictureListener != null) {
             // trigger picture listener for hardware layers. Software layers are
             // triggered in setNewPicture
-            mPictureListener.onNewPicture(getWebView(), capturePicture());
+            // TODO: Update CUR_DEVELOPMENT when appropriate JBMR2 constant is
+            // available.
+            Picture picture = mContext.getApplicationInfo().targetSdkVersion <
+                    Build.VERSION_CODES.CUR_DEVELOPMENT ? capturePicture() : null;
+            mPictureListener.onNewPicture(getWebView(), picture);
         }
     }
 
@@ -7994,7 +7998,11 @@
                     || mWebView.getLayerType() == View.LAYER_TYPE_SOFTWARE) {
                 // trigger picture listener for software layers. Hardware layers are
                 // triggered in pageSwapCallback
-                mPictureListener.onNewPicture(getWebView(), capturePicture());
+                // TODO: Update CUR_DEVELOPMENT when appropriate JBMR2 constant is
+                // available.
+                Picture picture = mContext.getApplicationInfo().targetSdkVersion <
+                        Build.VERSION_CODES.CUR_DEVELOPMENT ? capturePicture() : null;
+                mPictureListener.onNewPicture(getWebView(), picture);
             }
         }
     }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 69e3177..4436fbb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2429,7 +2429,9 @@
         View selectedView = getSelectedView();
         int selectedPos = mSelectedPosition;
 
-        int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
+        int nextSelectedPosition = (direction == View.FOCUS_DOWN) ?
+                lookForSelectablePosition(selectedPos + 1, true) :
+                lookForSelectablePosition(selectedPos - 1, false);
         int amountToScroll = amountToScroll(direction, nextSelectedPosition);
 
         // if we are moving focus, we may OVERRIDE the default behavior
@@ -2641,14 +2643,18 @@
         final int listBottom = getHeight() - mListPadding.bottom;
         final int listTop = mListPadding.top;
 
-        final int numChildren = getChildCount();
+        int numChildren = getChildCount();
 
         if (direction == View.FOCUS_DOWN) {
             int indexToMakeVisible = numChildren - 1;
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
-
+            while (numChildren <= indexToMakeVisible) {
+                // Child to view is not attached yet.
+                addViewBelow(getChildAt(numChildren - 1), mFirstPosition + numChildren - 1);
+                numChildren++;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
 
@@ -2682,6 +2688,12 @@
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
+            while (indexToMakeVisible < 0) {
+                // Child to view is not attached yet.
+                addViewAbove(getChildAt(0), mFirstPosition);
+                mFirstPosition--;
+                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
             int goalTop = listTop;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c6b7631..2544c54 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -162,7 +162,8 @@
 	external/skia/include/effects \
 	external/skia/include/images \
 	external/skia/include/ports \
-	external/skia/src/ports \
+	external/skia/src/core \
+	external/skia/src/images \
 	external/skia/include/utils \
 	external/sqlite/dist \
 	external/sqlite/android \
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index b7fdecf..daabce3 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(bitmap, !useExistingBitmap);
+    SkAutoTDelete<SkBitmap> adb(!useExistingBitmap ? bitmap : NULL);
 
     decoder->setPeeker(&peeker);
     if (!isPurgeable) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 886eb6e..6410bc3 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -65,6 +65,16 @@
         return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
     }
     
+    static void copyCanvasState(JNIEnv* env, jobject clazz,
+                                SkCanvas* srcCanvas, SkCanvas* dstCanvas) {
+        if (srcCanvas && dstCanvas) {
+            if (NULL != srcCanvas->getDevice() && NULL != dstCanvas->getDevice()) {
+                dstCanvas->clipRegion(srcCanvas->getTotalClip());
+            }
+            dstCanvas->setMatrix(srcCanvas->getTotalMatrix());
+        }
+    }
+
     static void freeCaches(JNIEnv* env, jobject) {
         // these are called in no particular order
         SkImageRef_GlobalPool::SetRAMUsed(0);
@@ -93,14 +103,6 @@
         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();
@@ -278,25 +280,25 @@
         canvas->setDrawFilter(filter);
     }
     
-    static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
-                                        jobject rect, int edgetype) {
+    static jboolean quickReject__RectF(JNIEnv* env, jobject, SkCanvas* canvas,
+                                        jobject rect) {
         SkRect rect_;
         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
-        return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
+        return canvas->quickReject(rect_);
     }
- 
-    static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
-                                       SkPath* path, int edgetype) {
-        return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
+
+    static jboolean quickReject__Path(JNIEnv* env, jobject, SkCanvas* canvas,
+                                       SkPath* path) {
+        return canvas->quickReject(*path);
     }
- 
-    static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
+
+    static jboolean quickReject__FFFF(JNIEnv* env, jobject, SkCanvas* canvas,
                                        jfloat left, jfloat top, jfloat right,
-                                       jfloat bottom, int edgetype) {
+                                       jfloat bottom) {
         SkRect r;
         r.set(SkFloatToScalar(left), SkFloatToScalar(top),
               SkFloatToScalar(right), SkFloatToScalar(bottom));
-        return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
+        return canvas->quickReject(r);
     }
  
     static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
@@ -930,12 +932,19 @@
                               jobject bounds) {
         SkRect   r;
         SkIRect ir;
-        bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
+        bool     result = canvas->getClipBounds(&r);
 
         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;
     }
@@ -949,10 +958,10 @@
 static JNINativeMethod gCanvasMethods[] = {
     {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
     {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
+    {"copyNativeCanvasState","(II)V", (void*) SkCanvasGlue::copyCanvasState},
     {"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",
@@ -984,10 +993,10 @@
     {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
         (void*) SkCanvasGlue::getClipBounds},
     {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
-    {"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_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_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
     {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
     {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index ff0eb45..01e7e3e 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, SkCanvas::kBW_EdgeType)) {
+    if (canvas && canvas->quickReject(bounds)) {
         return;
     }
 
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index ab7cf46..ded2186 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->unflatten(p->readInplace(size));
+    region->readFromMemory(p->readInplace(size));
 
     return region;
 }
@@ -190,9 +190,9 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    size_t size = region->flatten(NULL);
+    size_t size = region->writeToMemory(NULL);
     p->writeInt32(size);
-    region->flatten(p->writeInplace(size));
+    region->writeToMemory(p->writeInplace(size));
 
     return true;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 60c6183..1a8612e 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, NULL, 0, SkTypeface::kNormal);
+    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
 }
 
 void TextLayoutShaper::unrefTypefaces() {
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 7f4c37b..e056b61 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -147,25 +147,6 @@
     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[] = {
@@ -177,7 +158,6 @@
                                            (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 7c65662..c0e12da 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -537,7 +537,10 @@
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
     if (camera == 0) return;
 
-    sp<Surface> surface = android_view_Surface_getSurface(env, jSurface);
+    sp<Surface> surface;
+    if (jSurface) {
+        surface = android_view_Surface_getSurface(env, jSurface);
+    }
 
     if (camera->setPreviewDisplay(surface) != NO_ERROR) {
         jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 6724f36..56b687c 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -159,7 +159,8 @@
             name = line + name_pos;
             nameLen = strlen(name);
 
-            if (strstr(name, "[heap]") == name) {
+            if ((strstr(name, "[heap]") == name) ||
+                (strstr(name, "/dev/ashmem/libc malloc") == name)) {
                 whichHeap = HEAP_NATIVE;
             } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
                 whichHeap = HEAP_DALVIK;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index a6bb7c7..ba62f6d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -270,8 +270,7 @@
 // ----------------------------------------------------------------------------
 
 static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        SkCanvas::EdgeType edge) {
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
     return renderer->quickReject(left, top, right, bottom);
 }
 
@@ -961,7 +960,7 @@
     { "nSaveLayerAlpha",    "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
     { "nSaveLayerAlpha",    "(III)I",          (void*) android_view_GLES20Canvas_saveLayerAlphaClip },
 
-    { "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
+    { "nQuickReject",       "(IFFFF)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 },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab0d38e..b4a19f1 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -55,7 +55,6 @@
     jfieldID mNativeObject;
     jfieldID mGenerationId;
     jfieldID mCanvas;
-    jfieldID mCanvasSaveCount;
     jmethodID ctor;
 } gSurfaceClassInfo;
 
@@ -67,10 +66,15 @@
 } gRectClassInfo;
 
 static struct {
+    jfieldID mFinalizer;
     jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
 } gCanvasClassInfo;
 
+static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
 // ----------------------------------------------------------------------------
 
 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
@@ -112,8 +116,8 @@
 
 // ----------------------------------------------------------------------------
 
-static bool isSurfaceValid(const sp<Surface>& sur) {
-    return sur != 0 && sur->getISurfaceTexture() != 0;
+static inline bool isSurfaceValid(const sp<Surface>& sur) {
+    return Surface::isValid(sur);
 }
 
 // ----------------------------------------------------------------------------
@@ -180,6 +184,15 @@
     }
 }
 
+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));
 
@@ -219,8 +232,6 @@
     jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
     env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
 
-    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
-            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
     SkBitmap bitmap;
     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
     bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
@@ -233,7 +244,9 @@
         // be safe with an empty bitmap.
         bitmap.setPixels(NULL);
     }
-    nativeCanvas->setBitmapDevice(bitmap);
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
+    swapCanvasPtr(env, canvasObj, nativeCanvas);
 
     SkRegion clipReg;
     if (dirtyRegion.isRect()) { // very common case
@@ -250,9 +263,6 @@
 
     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);
@@ -277,12 +287,8 @@
     }
 
     // detach the canvas from the surface
-    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);
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvasObj, nativeCanvas);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -382,14 +388,16 @@
             env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
     gSurfaceClassInfo.mCanvas =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
-    gSurfaceClassInfo.mCanvasSaveCount =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
-    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
+    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()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");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e477e54..a218488 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -110,6 +110,7 @@
     virtual void onUnlockPixels() {
     }
 
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
 private:
     ScreenshotClient mScreenshot;
     SkColorTable*    fCTable;
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index e75a2d8..8a89db5 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -43,11 +43,16 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID nativeCanvas;
-    jfieldID surfaceFormat;
+    jfieldID mFinalizer;
+    jfieldID mNativeCanvas;
+    jfieldID mSurfaceFormat;
 } gCanvasClassInfo;
 
 static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
+static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -120,6 +125,15 @@
     }
 }
 
+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) {
 
@@ -157,9 +171,10 @@
         bitmap.setPixels(NULL);
     }
 
-    SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
-    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
-    nativeCanvas->setBitmapDevice(bitmap);
+    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
+    swapCanvasPtr(env, canvas, nativeCanvas);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -174,8 +189,8 @@
 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas) {
 
-    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
-    nativeCanvas->setBitmapDevice(SkBitmap());
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvas, nativeCanvas);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -226,8 +241,12 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
-    GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
+    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");
 
     FIND_CLASS(clazz, "android/view/TextureView");
     GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
diff --git a/core/res/res/anim/rotation_animation_enter.xml b/core/res/res/anim/rotation_animation_enter.xml
new file mode 100644
index 0000000..a674e1d
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_enter.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="0"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/anim/rotation_animation_jump_exit.xml b/core/res/res/anim/rotation_animation_jump_exit.xml
new file mode 100644
index 0000000..3338529
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_jump_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="0"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/anim/rotation_animation_xfade_exit.xml b/core/res/res/anim/rotation_animation_xfade_exit.xml
new file mode 100644
index 0000000..7300724
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_xfade_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="500"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 00c6f6d..5fc26fc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3512,8 +3512,8 @@
     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
     <!-- Notification title when error connecting to lockdown VPN. -->
     <string name="vpn_lockdown_error">Always-on VPN error</string>
-    <!-- Notification body that indicates user can touch to cycle lockdown VPN connection. -->
-    <string name="vpn_lockdown_reset">Touch to reset connection</string>
+    <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
+    <string name="vpn_lockdown_config">Touch to configure</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 412d4b9..c87cb27 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1487,6 +1487,9 @@
   <java-symbol type="anim" name="screen_user_exit" />
   <java-symbol type="anim" name="screen_user_enter" />
   <java-symbol type="anim" name="window_move_from_decor" />
+  <java-symbol type="anim" name="rotation_animation_jump_exit" />
+  <java-symbol type="anim" name="rotation_animation_xfade_exit" />
+  <java-symbol type="anim" name="rotation_animation_enter" />
   <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
@@ -1516,6 +1519,7 @@
   <java-symbol type="color" name="config_defaultNotificationColor" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_notify_wifidisplay" />
+  <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1649,7 +1653,7 @@
   <java-symbol type="string" name="vpn_lockdown_connecting" />
   <java-symbol type="string" name="vpn_lockdown_connected" />
   <java-symbol type="string" name="vpn_lockdown_error" />
-  <java-symbol type="string" name="vpn_lockdown_reset" />
+  <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
   <java-symbol type="string" name="wifi_display_notification_title" />
   <java-symbol type="string" name="wifi_display_notification_message" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 53876a5..e3c7cc4 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -167,7 +167,7 @@
                     ssidAppearInScanResultsCount, i));
             long startTime = System.currentTimeMillis();
             mAct.scanResultAvailable = false;
-            assertTrue("start scan failed", mAct.mWifiManager.startScanActive());
+            assertTrue("start scan failed", mAct.mWifiManager.startScan());
             while (true) {
                 if ((System.currentTimeMillis() - startTime) >
                 ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index d5fcc1c..dd60dd4 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -588,7 +588,7 @@
                 return true;
             } else {
                 // Start an active scan
-                mWifiManager.startScanActive();
+                mWifiManager.startScan();
                 mScanResultIsAvailable = false;
                 long startTime = System.currentTimeMillis();
                 while (!mScanResultIsAvailable) {
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 9519b9f..ebdbb0e 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -156,6 +156,8 @@
                 "Me: 16505551212 this\n",
                 "Me: 6505551212 this\n",
                 "Me: 5551212 this\n",
+                "Me: 2211 this\n",
+                "Me: 112 this\n",
 
                 "Me: 1-650-555-1212 this\n",
                 "Me: (650) 555-1212 this\n",
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index b5fd88b..61b537d 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
index 746e180..78883b4 100644
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ b/docs/html/distribute/googleplay/about/distribution.jd
@@ -24,17 +24,18 @@
 automatic updates of your app, so that your updates are delivered and installed
 as soon as you publish them.</p>
 
+
 <h2 id="targeting">Reaching the customers you want</h2>
 
+<div class="figure-right" style="width:400px;">
+<img src="{@docRoot}images/gp-dc-countries.png" class="frame">
+</div>
+
 <p>Google Play does more than connect your app with users&mdash;it helps you
 reach the broadest possible distribution across the Android ecosystem, while
 making sure that your app is only available to the audience that you want to
 reach.</p>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;margin:1.5em;">
-<img src="{@docRoot}images/gp-dc-countries.png" style="width:400px;padding:4px;margin-bottom:0;">
-</div>
-
 <h3 id="geotargeting">Geographic targeting</h3>
 
 <p>You can use controls in the Google Play Developer Console to easily
@@ -47,16 +48,15 @@
 and carrier targeting at any time just by saving changes in the Google Play
 Developer Console.</p>
 
+<div class="figure-right" style="width:400px;">
+<img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
+</div>
+
 <p>To help you market to users around the world, you
 can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
 your store listing</a>, including app details and description,
 promotional graphics, screenshots, and more.</p>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;margin:1.5em;">
-<img src="{@docRoot}images/gp-supported-dev-requirements.png"
-style="width:400px;padding:4px;margin-bottom:0;">
-</div>
-
 <h3 id="captargeting">Capabilities targeting</h3>
 
 <p>Google Play also lets you control distribution according to device features
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
index 8bafd53..8233a31 100644
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ b/docs/html/distribute/googleplay/about/monetizing.jd
@@ -116,8 +116,8 @@
 
 <h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-buyer-currency.png" style="width:240px;padding:4px;margin-bottom:1em;">
+<div class="figure-right" style="width:250px;">
+<img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
 </div>
 
 <p>Google Play gives you complete control over how you price your products. You
diff --git a/docs/html/distribute/googleplay/publish/console.jd b/docs/html/distribute/googleplay/publish/console.jd
index cd1fd80..069b2d2 100644
--- a/docs/html/distribute/googleplay/publish/console.jd
+++ b/docs/html/distribute/googleplay/publish/console.jd
@@ -1,4 +1,4 @@
-page.title=The Developer Console
+page.title=Developer Console
 @jd:body
 
 
@@ -9,41 +9,40 @@
 tools on Google Play. This sections below introduce a few of the key areas
 you'll find in the Developer Console.</p>
 
-<div style="width:610px;margin-left:">
-<div style="width:610px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-home.png" style="width:600px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">All applications page</span>: Gives you a quick
+<div class="figure" style="width:756px;">
+<img src="{@docRoot}images/gp-dc-home.png" class="frame">
+<p class="img-caption"><strong>All applications page</strong>: Gives you a quick
 overview of your apps, lets you jump to stats, reviews, and product details, or
 upload a new app. </p>
 </div>
 
-
-<h3 id="profile">Your Account Details</h3>
-
-<div style="width:408px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-profile.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Account details page</span>: Specifies your developer
+<div class="figure-right" style="width:450px;">
+<img src="{@docRoot}images/gp-dc-profile.png" class="frame">
+<p class="img-caption"><strong>Account details page</strong>: Specifies your developer
 identity and contact information, accounts for app testing, and more.</p>
 </div>
 
-<p>Your developer profile identifies you to Google Play and to your customers.
-During registration you must provide information for your profile, but you can go
-back at any time to edit the information and change your settings. </p>
+<h3 id="profile">Your account details</h3>
+
+<p>The account details page is where you specify basic information about yourself
+or your company in a developer profile. The information in your developer profile
+is important because it identifies you to Google Play and also to your customers.</p>
+
+<p>During registration you must provide the information for your profile, but you can
+go back at any time to edit the information and change your settings. </p>
 
 <p>Your developer profile contains:</p>
 <ul>
-<li>Your developer name &mdash; the name you want to show users on your product
-details page and elsewhere on Google Play. 
+<li>Your developer name &mdash; the name you want to show users on your store
+listing page and elsewhere on Google Play. </li>
 <li>Your developer contact information &mdash; how Google can contact you if
-needed (this information isn't exposed to users).
-<li>Merchant information, in-app billing information.</li>
+needed (this information isn't exposed to users).</li>
+<li>Your developer website URL &mdash; shown to users on your store listing page
+so they can learn more about your company or products.</li>
 </ul>
 
+<p>On the account details page you can also register for a merchant account, set
+up test accounts for Google Play licensing, and more. </p>
 
 <h3 id="user-accounts">Multiple user accounts</h3>
 
@@ -55,6 +54,13 @@
 app configuration, but not access to financial reports. </p>
 
 
+<div class="figure-right" style="width:450px;">
+<img src="{@docRoot}images/gp-dc-details.png" class="frame">
+<p class="img-caption"><strong>Store listing page</strong>: Lets you upload your
+graphic assets, description, support information, and other information to
+create the store listing page for a specific app.</p>
+</div>
+
 <h3 id="merchant">Linking your Merchant Account</h3>
 
 <p>If you want to sell apps or in-app products, you can link your Google
@@ -62,17 +68,6 @@
 Checkout account for financial and tax identification and monthly payouts of
 sales. </p>
 
-<div style="width:410px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-details.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Store Listing page</span>: Lets you upload your
-graphic assets, description, support information, and other information to
-create the product details page for a specific app.</p>
-</div>
-
-
 <h3 id="details">Your store listing details</h3>
 
 <p>The Developer Console lets you set up a colorful storefront page for your app
@@ -86,15 +81,14 @@
 notes about the latest version, and more. You can update your store listing at
 any time, even if you don’t have a new version of your application.</p>
 
-
 <h3 id="uploading">Uploading and publishing</h3>
 
 <p>From the Developer Console you can quickly upload a release-ready APK and
 publish it when you're ready. The app is a <em>draft</em> until you publish it,
-at which time Google Play makes your store listing and app available to
+at which time Google Play makes your store listing page and app available to
 users. You can unpublish the app at any time.</p>
 
-<h3 id="controls">Distribution Controls</h3>
+<h3 id="controls">Distribution controls</h3>
 
 <p>In the Developer Console you can manage what countries and territories the
 app is distributed to and, for some countries, you can choose what carriers you
@@ -103,8 +97,7 @@
 <p>You can also see the list of devices that your app is currently available to,
 based on any distribution rules declared in its manifest file.</p>
 
-
-<h3 id="profile">Selling and pricing your Products</h3>
+<h3 id="selling">Selling and pricing your products</h3>
 
 <p>The Developer Console gives you tools to set prices for your apps and in-app
 products. Your app can either be free to download or priced (charged before
@@ -149,17 +142,18 @@
 <a href="{@docRoot}google/play/billing/index.html">In-app Billing</span></a>
 developer documentation.</p></div></div>
 
-<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is a Google Play service that lets you monetize your apps in more ways by selling in-app products and subscriptions. In-app products are one-time purchases, while  subscriptions are recurring charges on an monthly or annual basis.</p>
+<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is
+a Google Play service that lets you monetize your apps in more ways by selling
+in-app products and subscriptions. In-app products are one-time purchases, while
+subscriptions are recurring charges on an monthly or annual basis.</p>
 
 <p>From the Developer Console you can create product lists for in-app
 products and subscriptions, set prices, and publish.</p>
 
-<div style="width:410px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-reviews.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span style="font-weight:500;">User
-reviews page</span>: Gives you access to user reviews for a specific app.
+<div class="figure-right" style="width:410px;">
+<img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
+<p class="img-caption"><strong>User
+reviews page</strong>: Gives you access to user reviews for a specific app.
 You can filter  reviews in a number of ways to locate issues more easily
 and support your customers more effectively.</p>
 </div>
@@ -182,7 +176,7 @@
 
 <p>You can view installations of your app measured by unique users, as well as
 by unique devices. For user installations, you can view active installs, total
-installs, daily installs and uninstalls, and metrics about the user reviews.
+installs, daily installs and uninstalls, and metrics about user ratings.
 For devices, you can see active
 installs as well as daily installs, uninstalls, and upgrades.</p>
 
@@ -197,12 +191,8 @@
 specific points (such as individual platform versions or languages) to the
 timeline.</p>
 
-<div style="width:610px;margin:1.5em;margin-left:0">
-<div style="width:610px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-stats.png" 
-style="width:600px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span style="font-weight:500;">App
-statistics page</span>: Shows you a variety of statistics about a
-specific app's installation performance over time.</p>
+<div style="width:530px;">
+<img src="{@docRoot}images/gp-dc-stats.png" class="frame">
+<p class="img-caption"><strong>App statistics page</strong>: Shows you a variety
+of statistics about a specific app's installation performance over time.</p>
 </div>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 406d412..0925f3c 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -422,8 +422,8 @@
 started on creating them and localizing them well in advance of your target
 publishing date. </p>
 
-<p class="note"><strong>Note:</strong> Localized promotional graphics and videos are supported
-only in the new Developer Console design.</p>
+<p class="note"><strong>Note:</strong> Localized promotional graphics and videos
+are supported only in the new Developer Console design.</p>
 
 <table>
 <tr>
@@ -547,7 +547,7 @@
 <h2 id="final-checks">16. Final checks and publishing</h2> 
 
 <p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
-final checks:</p>
+final checks.</p>
 
 <p>Make sure that: </p>
 
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index cfa7a30..91883da1 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -492,7 +492,7 @@
 <div style="margin:1em;">
 <img style="border:1px solid #ddd;padding-bottom:.5em" src="{@docRoot}images/in-app-billing/billing_app_key.png" xheight="510" id="figure4" />
 <p class="img-caption" style="padding-left:.5em;">
-  <strong>Figure 4.</strong> You can find the license key for each app in the <strong>Services & APIs</strong> panel.
+  <strong>Figure 4.</strong> You can find the license key for each app in the <strong>Services &amp; APIs</strong> panel.
 </p>
 </div>
 
diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
index 7b748a3..c065ffb 100755
--- a/docs/html/google/play/billing/v2/billing_integrate.jd
+++ b/docs/html/google/play/billing/v2/billing_integrate.jd
@@ -170,15 +170,14 @@
 following:</p>
 
 <ol>
-  <li><strong>Add your Google Play public key to the sample application code.</strong>
+  <li><strong>Add your app's public key to the sample application code.</strong>
     <p>This enables the application to verify the signature of the transaction information that is
     returned from Google Play. To add your public key to the sample application code, do the
     following:</p>
     <ol>
-      <li>Log in to your Google Play <a href="http://play.google.com/apps/publish">publisher
-      account</a>.</li>
-      <li>On the upper left part of the page, under your name, click <strong>Edit
-      Profile</strong>.</li>
+      <li>Log in to your Google Play <a href="http://play.google.com/apps/publish">Developer
+      console</a>.</li>
+      <li>On the upper left part of the page, All Applications, click the application name.</strong>.</li>
       <li>On the Edit Profile page, scroll down to the <strong>Licensing &amp; In-app
       Billing</strong> panel.</li>
       <li>Copy your public key.</li>
@@ -512,7 +511,7 @@
 three keys that are required for all requests: <code>BILLING_REQUEST</code>,
 <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. If you are offering subscriptions in
 your app, set the API_VERSION key to a value of "2", to confirm that In-app Billing v2 is
-available. For an examnple, see
+available. For an example, see
 <a href="{@docRoot}google/play/billing/v2/billing_subscriptions.html#version">Subscriptions</a>.</p>
 
 <p>The <code>CHECK_BILLING_SUPPORTED</code> request returns a synchronous {@link
@@ -1044,14 +1043,14 @@
 
 <p>You will need to use your Google Play public key to perform the signature verification. The
 following procedure shows you how to retrieve Base64-encoded public key from the Google Play
-publisher site.</p>
+Developer Console.</p>
 
 <ol>
   <li>Log in to your <a href="http://play.google.com/apps/publish">publisher account</a>.</li>
-  <li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
-  <li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure
-  2).</li>
-  <li>Copy your public key.</li>
+  <li>On the upper left part of the page, click <strong>All applications</strong> and then click
+  the app name in the listing.</li>
+  <li>Click <em>Services &amp; APIs</em> and find "Your License Key for this Application" on the page. </li>
+  <li>Copy the app's public key.</li>
 </ol>
 
 <p class="caution"><strong>Important</strong>: To keep your public key safe from malicious users and
@@ -1060,11 +1059,13 @@
 actual key. The key itself is not secret information, but you do not want to make it easy for a
 hacker or malicious user to replace the public key with another key.</p>
 
-<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure2" />
-<p class="img-caption">
-  <strong>Figure 2.</strong> The Licensing and In-app Billing panel of your account's Edit Profile
-  page lets you see your public key.
-</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_public_key.png" class="frame">
+<p class="img-caption"><strong>Figure
+2.</strong> An app's license key is available from the Services &amp; APIs page in
+the Developer Console.</p>
+</div>
+
 
 <h2 id="billing-implement">Modifying Your Application Code</h2>
 
diff --git a/docs/html/google/play/licensing/setting-up.jd b/docs/html/google/play/licensing/setting-up.jd
index 1d4e775..d83f91b 100644
--- a/docs/html/google/play/licensing/setting-up.jd
+++ b/docs/html/google/play/licensing/setting-up.jd
@@ -32,29 +32,25 @@
 </div>
 
 <p>Before you start adding license verification to your application, you need to set up your Google
-Play publishing account, your development environment, and test accounts required to verify
+Play publishing account, your development environment, and any test accounts required to verify
 your implementation.</p>
 
 
 <h2 id="account">Setting Up a Publisher Account</h2>
 
 <p>If you don't already have a publisher account for Google Play, you need to register for one
-using your Google account and agree to the terms of service on the Google Play publisher site:</p>
-
-<p style="margin-left:2em;"><a
-href="http://play.google.com/apps/publish">http://play.google.com/apps/publish</a>
-</p>
+using your Google account and agree to the Google Play terms of service.</p>
 
 <p>For more information, see <a
 href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with Publishing</a>.</p>
 
-<p>If you already have a publisher account on Google Play, use your existing
-account to set up licensing.</p>
+<p>If you already have a publisher account on Google Play, use your
+Developer Console to set up licensing.</p>
 
-<p>Using your publisher account on Google Play, you can:</p>
+<p>Using the Google Play Developer Console, you can:</p>
 
 <ul>
-<li>Obtain a public key for licensing</li>
+<li>Obtain an app-specific public key for licensing</li>
 <li>Debug and test an application's licensing implementation, prior to
 publishing the application</li>
 <li>Publish the applications to which you have added licensing support</li>
@@ -63,33 +59,35 @@
 <h4>Administrative settings for licensing</h4>
 
 <p>You can manage several
-administrative controls for Google Play licensing on the publisher site. The controls are available
-in the Edit Profile page, in the "Licensing" panel, shown in figure 1. The controls
+administrative controls for Google Play licensing in the Developer Console. The controls
 let you: </p>
 
 <ul>
 <li>Set up multiple "test accounts," identified by email address. The licensing
 server allows users signed in to test accounts on a device or emulator to send
-license checks and receive static test responses.</li>
-<li>Obtain the account's public key for licensing. When you are implementing
-licensing in an application, you must copy the public key string into the
-application.</li>
+license checks and receive static test responses. You can set up accounts in the
+Account Details page of the Developer Console.</li>
 <li>Configure static test responses that the server sends, when it receives a
 license check for an application uploaded to the publisher account, from a user
-signed in to the publisher account or a test account.</li>
+signed in to the publisher account or a test account. You can set test responses
+in the Account Details page of the Developer Console.</li>
+<li>Obtain the app's public key for licensing. When you are implementing
+licensing in an application, you must copy the public key string into the
+application. You can obtain the app's public key for licensing in the Services
+& APIs page (under All Applications).</li>
 </ul>
 
-
-<img src="{@docRoot}images/licensing_public_key.png" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> The Licensing
-panel of your account's Edit Profile page lets you manage administrative
-settings for licensing.</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_public_key.png" class="frame">
+<p class="img-caption"><strong>Figure
+2.</strong> An app's license key is available from the Services &amp; APIs page in
+the Developer Console.</p>
+</div>
 
 <p>For more information about how to work with test accounts and static test
 responses, see <a href="#test-env">Setting Up a Testing Environment</a>, below.
 
 
-
 <h2 id="dev-setup">Setting Up the Development Environment</h2>
 
 <p>Setting up your environment for licensing involves these tasks:</p>
@@ -432,9 +430,9 @@
 
 <h2 id="test-env">Setting Up the Testing Environment</h2>
 
-<p>The Google Play publisher site provides configuration tools that let you
+<p>The Google Play Developer Console provides configuration tools that let you
 and others test licensing on your application before it is published. As you are
-implementing licensing, you can make use of the publisher site tools to test
+implementing licensing, you can make use of the Developer Console tools to test
 your application's Policy and handling of different licensing responses and
 error conditions.</p>
 
@@ -487,10 +485,12 @@
 Response Codes</a> in the <a
 href="{@docRoot}google/play/licensing/licensing-reference.html">Licensing Reference</a>.</p>
 
-<img src="{@docRoot}images/licensing_test_response.png" alt=""/>
-<p class="img-caption"><strong>Figure 4.</strong> The Licensing
-panel of your account's Edit Profile page, showing the Test Accounts field and the
-Test Response menu.</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_test_response.png" class="frame">
+<p class="img-caption"><strong>Figure 4.</strong> The License Testing
+panel of your Account details page lets you set up test accounts and
+manage test responses.</p>
+</div>
 
 <p>Note that the test response that you configure applies account-wide &mdash;
 that is, it applies not to a single application, but to <em>all</em>
@@ -516,7 +516,7 @@
 <p>In some cases, you might want to let multiple teams of developers test
 licensing on applications that will ultimately be published through your
 publisher account, but without giving them access to your publisher account's
-sign-in credentials. To meet that need, the Google Play publisher site lets
+sign-in credentials. To meet that need, the Google Play Developer Console lets
 you set up one or more optional <em>test accounts</em> &mdash; accounts that are
 authorized to query the licensing server and receive static test responses from
 your publisher account.</p>
@@ -609,13 +609,13 @@
 
 <p>The licensing server handles static test responses in the normal way,
 including signing the license response data, adding extras parameters, and so
-on. To support developers who are implementing licensing using test accounts,
+on. To support developers who are implementing licensing using test accounts
 rather than the publisher account, you will need to distribute
-your public key to them. Developers without access to the publisher site do not
-have access to your public key, and without the key they won't be able to
-verify license responses. </p>
+the app's public key for licensing to them. Developers without access to the
+Developer Console do not have access to the app's public key, and without
+the key they won't be able to verify license responses. </p>
 
-<p>Note that if you decide to generate a new licensing key pair for your account
+<p>Note that if you decide to generate a new licensing key pair for the app
 for some reason, you need to notify all users of test accounts. For
 testers, you can embed the new key in the application package and distribute it
 to users. For developers, you will need to distribute the new key to them
@@ -661,7 +661,7 @@
 
 <p>Signing in using a publisher account offers the advantage of letting your
 applications receive static test responses even before the applications are
-uploaded to the publisher site.</p>
+uploaded to the Developer Console.</p>
 
 <p>If you are part of a larger organization or are working with external groups
 on applications that will be published through your site, you will more likely
diff --git a/docs/html/images/billing_public_key.png b/docs/html/images/billing_public_key.png
deleted file mode 100644
index a0620f8..0000000
--- a/docs/html/images/billing_public_key.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-buyer-currency.png b/docs/html/images/gp-buyer-currency.png
index 51b8108..96d7e65 100644
--- a/docs/html/images/gp-buyer-currency.png
+++ b/docs/html/images/gp-buyer-currency.png
Binary files differ
diff --git a/docs/html/images/gp-dc-countries.png b/docs/html/images/gp-dc-countries.png
index 00d0d5e..72ce796 100644
--- a/docs/html/images/gp-dc-countries.png
+++ b/docs/html/images/gp-dc-countries.png
Binary files differ
diff --git a/docs/html/images/gp-dc-details.png b/docs/html/images/gp-dc-details.png
index 567567e..5b7eba4 100644
--- a/docs/html/images/gp-dc-details.png
+++ b/docs/html/images/gp-dc-details.png
Binary files differ
diff --git a/docs/html/images/gp-dc-home.png b/docs/html/images/gp-dc-home.png
index 381d0db..5ed46c9 100644
--- a/docs/html/images/gp-dc-home.png
+++ b/docs/html/images/gp-dc-home.png
Binary files differ
diff --git a/docs/html/images/gp-dc-profile.png b/docs/html/images/gp-dc-profile.png
index e526369..e254e5d 100644
--- a/docs/html/images/gp-dc-profile.png
+++ b/docs/html/images/gp-dc-profile.png
Binary files differ
diff --git a/docs/html/images/gp-dc-reviews.png b/docs/html/images/gp-dc-reviews.png
index cab175a..4290136 100644
--- a/docs/html/images/gp-dc-reviews.png
+++ b/docs/html/images/gp-dc-reviews.png
Binary files differ
diff --git a/docs/html/images/gp-dc-stats-mini.png b/docs/html/images/gp-dc-stats-mini.png
index d29a270..211b5ea 100644
--- a/docs/html/images/gp-dc-stats-mini.png
+++ b/docs/html/images/gp-dc-stats-mini.png
Binary files differ
diff --git a/docs/html/images/gp-dc-stats.png b/docs/html/images/gp-dc-stats.png
index 06f88e5..7df6266 100644
--- a/docs/html/images/gp-dc-stats.png
+++ b/docs/html/images/gp-dc-stats.png
Binary files differ
diff --git a/docs/html/images/gp-devconsole-home.png b/docs/html/images/gp-devconsole-home.png
index 1d758fd..b29dc25 100644
--- a/docs/html/images/gp-devconsole-home.png
+++ b/docs/html/images/gp-devconsole-home.png
Binary files differ
diff --git a/docs/html/images/gp-supported-dev-requirements.png b/docs/html/images/gp-supported-dev-requirements.png
index d84f34e..c38b8aa 100644
--- a/docs/html/images/gp-supported-dev-requirements.png
+++ b/docs/html/images/gp-supported-dev-requirements.png
Binary files differ
diff --git a/docs/html/images/licensing_public_key.png b/docs/html/images/licensing_public_key.png
index 1630209..a3cd785 100644
--- a/docs/html/images/licensing_public_key.png
+++ b/docs/html/images/licensing_public_key.png
Binary files differ
diff --git a/docs/html/images/licensing_test_response.png b/docs/html/images/licensing_test_response.png
index ead2152..219ae24 100644
--- a/docs/html/images/licensing_test_response.png
+++ b/docs/html/images/licensing_test_response.png
Binary files differ
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
index 8ff9fec..f07adfd 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
@@ -687,9 +687,7 @@
             
               <a href="/reference/com/google/android/gms/panorama/PanoramaClient.html">PanoramaClient</a>,
             
-              <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a>,
-            
-              <a href="/reference/com/google/android/gms/wallet/WalletClient.html">WalletClient</a>
+              <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a>
             
           
       </div>
@@ -705,10 +703,6 @@
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></td>
               <td class="jd-descrcol" width="100%">The main entry point for Google+ integration.&nbsp;</td>
           </tr>
-        <tr class="alt-color api apilevel-" >
-              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/wallet/WalletClient.html">WalletClient</a></td>
-              <td class="jd-descrcol" width="100%">The main entry point for Google Wallet integration.&nbsp;</td>
-          </tr>
   </table>
       </div>
   </div>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e94ddae..fc84715 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, freed in finalizer
-    final int mNativeCanvas;
+    // assigned in constructors or setBitmap, freed in finalizer
+    int mNativeCanvas;
     
     // may be null
     private Bitmap mBitmap;
@@ -71,7 +71,7 @@
     private final CanvasFinalizer mFinalizer;
 
     private static class CanvasFinalizer {
-        private final int mNativeCanvas;
+        private int mNativeCanvas;
 
         public CanvasFinalizer(int nativeCanvas) {
             mNativeCanvas = nativeCanvas;
@@ -131,6 +131,18 @@
     }
 
     /**
+     * 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;
+        copyNativeCanvasState(oldCanvas, mNativeCanvas);
+        finalizer(oldCanvas);
+    }
+    
+    /**
      * Returns null.
      * 
      * @deprecated This method is not supported and should not be invoked.
@@ -156,11 +168,11 @@
     }
 
     /**
-     * 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.
+     * 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.
      *
      * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
-     * 
      * @see #setDensity(int)
      * @see #getDensity()
      */
@@ -169,17 +181,19 @@
             throw new RuntimeException("Can't set a bitmap device on a GL canvas");
         }
 
-        int pointer = 0;
-        if (bitmap != null) {
+        if (bitmap == null) {
+            safeCanvasSwap(initRaster(0));
+            mDensity = Bitmap.DENSITY_NONE;
+        } else {
             if (!bitmap.isMutable()) {
                 throw new IllegalStateException();
             }
             throwIfRecycled(bitmap);
+
+            safeCanvasSwap(initRaster(bitmap.ni()));
             mDensity = bitmap.mDensity;
-            pointer = bitmap.ni();
         }
 
-        native_setBitmap(mNativeCanvas, pointer);
         mBitmap = bitmap;
     }
     
@@ -694,7 +708,7 @@
      *              does not intersect with the canvas' clip
      */
     public boolean quickReject(RectF rect, EdgeType type) {
-        return native_quickReject(mNativeCanvas, rect, type.nativeInt);
+        return native_quickReject(mNativeCanvas, rect);
     }
 
     /**
@@ -714,7 +728,7 @@
      *                    does not intersect with the canvas' clip
      */
     public boolean quickReject(Path path, EdgeType type) {
-        return native_quickReject(mNativeCanvas, path.ni(), type.nativeInt);
+        return native_quickReject(mNativeCanvas, path.ni());
     }
 
     /**
@@ -737,9 +751,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,
-                                  type.nativeInt);
+    public boolean quickReject(float left, float top, float right, float bottom,
+                               EdgeType type) {
+        return native_quickReject(mNativeCanvas, left, top, right, bottom);
     }
 
     /**
@@ -1599,7 +1613,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 void copyNativeCanvasState(int srcCanvas, int dstCanvas);
     private static native int native_saveLayer(int nativeCanvas, RectF bounds,
                                                int paint, int layerFlags);
     private static native int native_saveLayer(int nativeCanvas, float l,
@@ -1630,15 +1644,12 @@
                                                        Rect bounds);
     private static native void native_getCTM(int canvas, int matrix);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     RectF rect,
-                                                     int native_edgeType);
+                                                     RectF rect);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     int path,
-                                                     int native_edgeType);
+                                                     int path);
     private static native boolean native_quickReject(int nativeCanvas,
                                                      float left, float top,
-                                                     float right, float bottom,
-                                                     int native_edgeType);
+                                                     float right, float bottom);
     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/Path.java b/graphics/java/android/graphics/Path.java
index f6b5ffc..157c7d1 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -375,9 +375,9 @@
      */
     public enum Direction {
         /** clockwise */
-        CW  (0),    // must match enum in SkPath.h
+        CW  (1),    // must match enum in SkPath.h
         /** counter-clockwise */
-        CCW (1);    // must match enum in SkPath.h
+        CCW (2);    // 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 4487a3c..c68c9f7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -225,16 +225,4 @@
     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/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 2f3e48c..a99cdad 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -1261,6 +1261,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setSurfaceTexture(SurfaceTexture st) {
+        setSurface(new Surface(st));
+    }
+
+    /**
      * Associate a surface for io output with this allocation
      *
      * @param sur Surface to associate with allocation
diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
index d3fb98d..1dfec23 100644
--- a/libs/androidfw/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -23,6 +23,23 @@
 #include <string.h>
 #include <stddef.h>
 #include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
 
@@ -135,7 +152,7 @@
             // if we don't have any data to decode, read some in.  If we're working
             // from mmapped data this won't happen, because the clipping to total size
             // will prevent reading off the end of the mapped input chunk.
-            if (mInflateState.avail_in == 0) {
+            if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) {
                 int err = readNextChunk();
                 if (err < 0) {
                     ALOGE("Unable to access asset data: %d", err);
@@ -191,11 +208,10 @@
     if (mInNextChunkOffset < mInTotalSize) {
         size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
         if (toRead > 0) {
-            ssize_t didRead = ::read(mFd, mInBuf, toRead);
+            ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
             //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
             if (didRead < 0) {
-                // TODO: error
-                ALOGE("Error reading asset data");
+                ALOGE("Error reading asset data: %s", strerror(errno));
                 return didRead;
             } else {
                 mInNextChunkOffset += didRead;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5f2a4d5..33d8063 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -48,6 +48,7 @@
 		external/skia/include/core \
 		external/skia/include/effects \
 		external/skia/include/images \
+		external/skia/src/core \
 		external/skia/src/ports \
 		external/skia/include/utils \
 		$(intermediates) \
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 398f719..744edca 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -251,16 +251,18 @@
  * 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,
+    ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
             mName.string(), isRenderable());
+    ALOGD("%*s%s %d", level * 2, "", "Save",
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
-    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());
+
+    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
 }
 
 float DisplayList::getPivotX() {
@@ -356,7 +358,9 @@
     }
 }
 
-void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
+status_t DisplayList::setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
+        int32_t flags, uint32_t level, DeferredDisplayList* deferredList) {
+    status_t status = DrawGlInfo::kStatusDone;
 #if DEBUG_DISPLAYLIST
     outputViewProperties(level);
 #endif
@@ -377,6 +381,9 @@
         }
     }
     if (mAlpha < 1 && !mCaching) {
+        // flush since we'll either enter a Layer, or set alpha, both not supported in deferral
+        status |= deferredList->flush(renderer, dirty, flags, level);
+
         if (!mHasOverlappingRendering) {
             renderer.setAlpha(mAlpha);
         } else {
@@ -392,9 +399,14 @@
         }
     }
     if (mClipChildren && !mCaching) {
+        if (CC_UNLIKELY(!renderer.hasRectToRectTransform())) {
+            // flush, since clip will likely be a region
+            status |= deferredList->flush(renderer, dirty, flags, level);
+        }
         renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
                 SkRegion::kIntersect_Op);
     }
+    return status;
 }
 
 status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
@@ -414,12 +426,7 @@
     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);
+    drawGlStatus |= setViewProperties(renderer, dirty, flags, level, deferredList);
 
     if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
         DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 86c9ec0..feee69c 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -17,6 +17,10 @@
 #ifndef ANDROID_HWUI_DISPLAY_LIST_H
 #define ANDROID_HWUI_DISPLAY_LIST_H
 
+#ifndef LOG_TAG
+    #define LOG_TAG "OpenGLRenderer"
+#endif
+
 #include <SkCamera.h>
 #include <SkMatrix.h>
 
@@ -75,7 +79,8 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
+    status_t setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
+            int32_t flags, uint32_t level, DeferredDisplayList* deferredList);
     void outputViewProperties(uint32_t level);
 
     ANDROID_API size_t getSize();
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 1bae0ff..97812d4 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -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.
@@ -17,6 +17,10 @@
 #ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
 #define ANDROID_HWUI_DISPLAY_OPERATION_H
 
+#ifndef LOG_TAG
+    #define LOG_TAG "OpenGLRenderer"
+#endif
+
 #include <SkXfermode.h>
 
 #include <private/hwui/DrawGlInfo.h>
@@ -100,7 +104,7 @@
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
             uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
         status_t status = DrawGlInfo::kStatusDone;
-        if (deferredList && requiresDrawOpFlush()) {
+        if (deferredList && requiresDrawOpFlush(renderer)) {
             // will be setting renderer state that affects ops in deferredList, so flush list first
             status |= deferredList->flush(renderer, dirty, flags, level);
         }
@@ -114,7 +118,7 @@
      * Returns true if it affects renderer drawing state in such a way to break deferral
      * see OpenGLRenderer::disallowDeferral()
      */
-    virtual bool requiresDrawOpFlush() { return false; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return false; }
 };
 
 class DrawOp : public DisplayListOp {
@@ -272,7 +276,7 @@
     }
 
     virtual const char* name() { return "SaveLayer"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     Rect mArea;
@@ -294,7 +298,7 @@
     }
 
     virtual const char* name() { return "SaveLayerAlpha"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     Rect mArea;
@@ -434,7 +438,16 @@
 
     virtual const char* name() { return "ClipRect"; }
 
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) {
+        // TODO: currently, we flush when we *might* cause a clip region to exist. Ideally, we
+        // should only flush when a non-rectangular clip would result
+        return !renderer.hasRectToRectTransform() || !hasRectToRectOp();
+    }
+
 private:
+    inline bool hasRectToRectOp() {
+        return mOp == SkRegion::kIntersect_Op || mOp == SkRegion::kReplace_Op;
+    }
     Rect mArea;
     SkRegion::Op mOp;
 };
@@ -455,7 +468,7 @@
     }
 
     virtual const char* name() { return "ClipPath"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkPath* mPath;
@@ -478,7 +491,7 @@
     }
 
     virtual const char* name() { return "ClipRegion"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkRegion* mRegion;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1d9eb0e..8eb2aeb 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
+#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include <cutils/properties.h>
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 664b2f8..ccf1da5 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -23,6 +23,7 @@
 
 #include <ui/Region.h>
 
+#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include "Rect.h"
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6b614a7..1afeaf0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -81,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::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
 };
 
@@ -102,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::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
 };
 
@@ -1284,6 +1284,10 @@
     }
 }
 
+bool OpenGLRenderer::hasRectToRectTransform() {
+    return CC_LIKELY(mSnapshot->transform->rectToRect());
+}
+
 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
     mSnapshot->transform->copyTo(*matrix);
 }
@@ -1505,8 +1509,10 @@
     if (clear) clearLayerRegions();
     // Make sure setScissor & setStencil happen at the beginning of
     // this method
-    if (mDirtyClip && mCaches.scissorEnabled) {
-        setScissorFromClip();
+    if (mDirtyClip) {
+        if (mCaches.scissorEnabled) {
+            setScissorFromClip();
+        }
         setStencilFromClip();
     }
     mDescription.reset();
@@ -1801,7 +1807,7 @@
 
 void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
     if (displayList) {
-        displayList->output(0);
+        displayList->output(1);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e12083c..80f2081 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -198,6 +198,7 @@
     virtual void scale(float sx, float sy);
     virtual void skew(float sx, float sy);
 
+    bool hasRectToRectTransform();
     ANDROID_API void getMatrix(SkMatrix* matrix);
     virtual void setMatrix(SkMatrix* matrix);
     virtual void concatMatrix(SkMatrix* matrix);
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 19a5db7..923913e 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -132,15 +132,6 @@
             }
             break;
         }
-        case SkRegion::kUnion_Op: {
-            if (CC_UNLIKELY(!clipRegion->isEmpty())) {
-                ensureClipRegion();
-                clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kUnion_Op);
-            } else {
-                clipped = clipRect->unionWith(r);
-            }
-            break;
-        }
         case SkRegion::kReplace_Op: {
             setClip(r.left, r.top, r.right, r.bottom);
             clipped = true;
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index f653592..24b0523 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -14,6 +14,7 @@
  * 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 8c5a8ff..1a75ea8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -20,6 +20,7 @@
 
 #include <utils/JenkinsHash.h>
 
+#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include "Debug.h"
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.h b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
index afedcbd..374604c 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.h
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
@@ -33,6 +33,7 @@
      //! 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/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 24d9c39..493c168 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">"Kurejesha kila kitu"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejeza kamili"</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 kurejesha..."</string>
-    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejesha kumekamilika"</string>
+    <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejeza..."</string>
+    <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejeza kumekamilika"</string>
     <string name="toast_timeout" msgid="5276598587087626877">"Muda wa uendeshaji umeisha"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 48edc73..c40e26d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -189,7 +189,7 @@
     <string name="quick_settings_location_label" msgid="3292451598267467545">"الموقع المستخدم"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"جهاز الوسائط"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
-    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"مكالمات طوارئ فقط"</string>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"مكالمات الطوارئ فقط"</string>
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"الإعدادات"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"الوقت"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"أنا"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 580bfe7..8c2dd8e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -147,7 +147,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Mode silenci."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
-    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Àrea de notificacions"</string>
+    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Capa de notificació."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configuració ràpida."</string>
     <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Aplicacions recents."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Usuari <xliff:g id="USER">%s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0789b29..d619de1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -133,7 +133,7 @@
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"No hay tarjeta SIM."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Conexión mediante Bluetooth"</string>
-    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo avión"</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo de avión"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
     <skip />
@@ -154,7 +154,7 @@
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Móvil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Batería <xliff:g id="STATE">%s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Modo avión <xliff:g id="STATE">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Modo de avión <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarma: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datos de 2G-3G inhabilitados"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index fff1aa0..c454bb1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -157,14 +157,14 @@
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm ustawiony na <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Wyłączono transmisję danych 2G/3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Wyłączono transmisję danych 4G"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Transmisja danych została wyłączona"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Wyłączono komórkową transmisję danych"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Wyłączono transmisję danych"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Ustawiony limit transmisji danych został osiągnięty."\n\n"Jeśli ponownie włączysz przesyłanie danych, operator może naliczyć dodatkowe opłaty."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Osiągnięto określony limit wykorzystania transmisji danych."\n\n"Jeśli ponownie włączysz przesyłanie danych, operator może naliczyć opłaty."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Włącz transmisję danych"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
-    <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string>
+    <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja ustawiona według GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string>
     <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string>
     <string name="close_universe" msgid="3736513750241754348">"Zamknij"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3d0ddd4..ccf4fd48 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -77,7 +77,7 @@
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Установить как камеру (PTP)"</string>
     <string name="installer_cd_button_title" msgid="2312667578562201583">"Установить приложение"</string>
     <string name="accessibility_back" msgid="567011538994429120">"Назад"</string>
-    <string name="accessibility_home" msgid="8217216074895377641">"Домой"</string>
+    <string name="accessibility_home" msgid="8217216074895377641">"Главная страница"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Меню"</string>
     <string name="accessibility_recent" msgid="8571350598987952883">"Недавние приложения"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
@@ -118,8 +118,8 @@
     <string name="accessibility_two_bars" msgid="6437363648385206679">"два деления"</string>
     <string name="accessibility_three_bars" msgid="2648241415119396648">"три деления"</string>
     <string name="accessibility_signal_full" msgid="9122922886519676839">"надежный сигнал"</string>
-    <string name="accessibility_desc_on" msgid="2385254693624345265">"Вкл."</string>
-    <string name="accessibility_desc_off" msgid="6475508157786853157">"Выкл."</string>
+    <string name="accessibility_desc_on" msgid="2385254693624345265">"ВКЛ"</string>
+    <string name="accessibility_desc_off" msgid="6475508157786853157">"ВЫКЛ"</string>
     <string name="accessibility_desc_connected" msgid="8366256693719499665">"Подключено"</string>
     <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
     <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a58c9a0..91214d1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -181,7 +181,7 @@
     <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Laddat"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
-    <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth av"</string>
+    <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth inaktivt"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Ljusstyrka"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotera automatiskt"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotationen har låsts"</string>
@@ -196,9 +196,9 @@
     <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ej ansluten"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
-    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi av"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Trådlös skärm"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös skärm"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi är inaktiverat"</string>
+    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi visas"</string>
+    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös visning"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f43eabe..7750e77 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -35,10 +35,10 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Поточні"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
     <string name="battery_low_title" msgid="2783104807551211639">"Підключіть зарядний пристрій"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Акумулятор розряджається."</string>
+    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея виснажується."</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується."\n"Використовуйте лише наданий у комплекті зарядний пристрій."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Використання акумулятора"</string>
+    <string name="battery_low_why" msgid="7279169609518386372">"Викор. батареї"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
@@ -85,11 +85,11 @@
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth від’єднано."</string>
-    <string name="accessibility_no_battery" msgid="358343022352820946">"Акумулятор розряджений."</string>
-    <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Заряд акумулятора: одна смужка."</string>
-    <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Заряд акумулятора: дві смужки."</string>
-    <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Заряд акумулятора: три смужки."</string>
-    <string name="accessibility_battery_full" msgid="8909122401720158582">"Акумулятор заряджений."</string>
+    <string name="accessibility_no_battery" msgid="358343022352820946">"Немає заряду батареї."</string>
+    <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Одна смужка заряду батареї."</string>
+    <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Дві смужки заряду батареї."</string>
+    <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Три смужки заряду батареї."</string>
+    <string name="accessibility_battery_full" msgid="8909122401720158582">"Повний заряд батареї"</string>
     <string name="accessibility_no_phone" msgid="4894708937052611281">"Немає сигналу телефону."</string>
     <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Одна смужка сигналу телефону."</string>
     <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Дві смужки сигналу телефону."</string>
@@ -134,7 +134,7 @@
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Немає SIM-карти."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Прив’язка Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Режим польоту."</string>
-    <string name="accessibility_battery_level" msgid="7451474187113371965">"Заряд акумулятора: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="accessibility_battery_level" msgid="7451474187113371965">"Відсотків батареї: <xliff:g id="NUMBER">%d</xliff:g>."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Налаштування системи."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Сповіщення."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Очистити сповіщення."</string>
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 024faf7..f0b1d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -429,7 +429,7 @@
         mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel);
 
         mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
-        if (mHasFlipSettings) {
+        if (mDateTimeView != null) {
             mDateTimeView.setOnClickListener(mClockClickListener);
             mDateTimeView.setEnabled(true);
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index acbde9b..7b4d3d0 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1737,6 +1737,51 @@
         return 0;
     }
 
+    @Override
+    public void selectRotationAnimationLw(int anim[]) {
+        if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
+                + mTopFullscreenOpaqueWindowState + " rotationAnimation="
+                + (mTopFullscreenOpaqueWindowState == null ?
+                        "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation));
+        if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) {
+            switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) {
+                case ROTATION_ANIMATION_CROSSFADE:
+                    anim[0] = R.anim.rotation_animation_xfade_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_JUMPCUT:
+                    anim[0] = R.anim.rotation_animation_jump_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_ROTATE:
+                default:
+                    anim[0] = anim[1] = 0;
+                    break;
+            }
+        } else {
+            anim[0] = anim[1] = 0;
+        }
+    }
+
+    @Override
+    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+            boolean forceDefault) {
+        switch (exitAnimId) {
+            case R.anim.rotation_animation_xfade_exit:
+            case R.anim.rotation_animation_jump_exit:
+                // These are the only cases that matter.
+                if (forceDefault) {
+                    return false;
+                }
+                int anim[] = new int[2];
+                selectRotationAnimationLw(anim);
+                return (exitAnimId == anim[0] && enterAnimId == anim[1]);
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Animation createForceHideEnterAnimation(boolean onWallpaper) {
         return AnimationUtils.loadAnimation(mContext, onWallpaper
                 ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
index 3c3b919..fd9c66b 100644
--- a/services/input/SpriteController.cpp
+++ b/services/input/SpriteController.cpp
@@ -210,8 +210,7 @@
                         outBuffer.width, outBuffer.height, bpr);
                 surfaceBitmap.setPixels(outBuffer.bits);
 
-                SkCanvas surfaceCanvas;
-                surfaceCanvas.setBitmapDevice(surfaceBitmap);
+                SkCanvas surfaceCanvas(surfaceBitmap);
 
                 SkPaint paint;
                 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index dfde692..401a25f 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -3897,6 +3897,7 @@
                                     && !info.domain.equals(FullBackup.DATABASE_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.ROOT_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)
+                                    && !info.domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.OBB_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
                                 throw new IOException("Unrecognized domain " + info.domain);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6d817a1..7abd530 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1823,6 +1823,7 @@
     }
 
     public void sendConnectedBroadcast(NetworkInfo info) {
+        enforceConnectivityInternalPermission();
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
@@ -2107,6 +2108,7 @@
 
     /** @hide */
     public void captivePortalCheckComplete(NetworkInfo info) {
+        enforceConnectivityInternalPermission();
         mNetTrackers[info.getType()].captivePortalCheckComplete();
     }
 
@@ -2365,7 +2367,7 @@
      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
      * wide use
      */
-   public void updateNetworkSettings(NetworkStateTracker nt) {
+   private void updateNetworkSettings(NetworkStateTracker nt) {
         String key = nt.getTcpBufferSizesPropName();
         String bufferSizes = key == null ? null : SystemProperties.get(key);
 
@@ -2844,7 +2846,7 @@
     }
 
     public int setUsbTethering(boolean enable) {
-        enforceTetherAccessPermission();
+        enforceTetherChangePermission();
         if (isTetheringSupported()) {
             return mTethering.setUsbTethering(enable);
         } else {
@@ -2997,6 +2999,7 @@
     }
 
     public ProxyProperties getProxy() {
+        enforceAccessPermission();
         synchronized (mDefaultProxyLock) {
             return mDefaultProxyDisabled ? null : mDefaultProxy;
         }
@@ -3048,6 +3051,7 @@
     }
 
     public ProxyProperties getGlobalProxy() {
+        enforceAccessPermission();
         synchronized (mGlobalProxyLock) {
             return mGlobalProxy;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 949c2ed..8ef247e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -62,6 +62,7 @@
 import com.android.server.power.ShutdownThread;
 import com.android.server.search.SearchManagerService;
 import com.android.server.usb.UsbService;
+import com.android.server.wifi.WifiService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 30a7e23..e0b8015 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -4850,44 +4850,8 @@
      * @return Returns true if the move completed, false if not.
      */
     final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
-        if (!newMoveTaskToBackLocked(task, reason)) {
-            return false;
-        }
-
-        final int N = mHistory.size();
-        int bottom = 0;
-        int pos = 0;
-
-        // Shift all activities with this task down to the bottom
-        // of the stack, keeping them in the same internal order.
-        while (pos < N) {
-            ActivityRecord r = mHistory.get(pos);
-            if (localLOGV) Slog.v(
-                TAG, "At " + pos + " ckp " + r.task + ": " + r);
-            if (r.task.taskId == task) {
-                if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
-                if (DEBUG_ADD_REMOVE) {
-                    RuntimeException here = new RuntimeException("here");
-                    here.fillInStackTrace();
-                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
-                            + bottom, here);
-                }
-                mHistory.remove(pos);
-                mHistory.add(bottom, r);
-                bottom++;
-            }
-            pos++;
-        }
-        if (VALIDATE_TASK_REPLACE) {
-            verifyActivityRecords(true);
-        }
-
-        return true;
-    }
-
-    final boolean newMoveTaskToBackLocked(int task, ActivityRecord reason) {
         Slog.i(TAG, "moveTaskToBack: " + task);
-        
+
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
@@ -4917,6 +4881,36 @@
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
 
+        // BEGIN REGION TO REMOVE.
+        final int N = mHistory.size();
+        int bottom = 0;
+        int pos = 0;
+
+        // Shift all activities with this task down to the bottom
+        // of the stack, keeping them in the same internal order.
+        while (pos < N) {
+            ActivityRecord r = mHistory.get(pos);
+            if (localLOGV) Slog.v(
+                TAG, "At " + pos + " ckp " + r.task + ": " + r);
+            if (r.task.taskId == task) {
+                if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
+                if (DEBUG_ADD_REMOVE) {
+                    RuntimeException here = new RuntimeException("here");
+                    here.fillInStackTrace();
+                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
+                            + bottom, here);
+                }
+                mHistory.remove(pos);
+                mHistory.add(bottom, r);
+                bottom++;
+            }
+            pos++;
+        }
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
+        // END REGION TO REMOVE
+
         if (reason != null &&
                 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
             mService.mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -4929,6 +4923,7 @@
                     AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
         mService.mWindowManager.moveTaskToBottom(task);
+
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index bb7334a..533db46 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -462,6 +462,7 @@
      * secondary thread to perform connection work, returning quickly.
      */
     public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+        enforceControlPermission();
         if (!keyStore.isUnlocked()) {
             throw new IllegalStateException("KeyStore isn't unlocked");
         }
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index f32dd09..5b6e485 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -56,7 +56,9 @@
     private static final int MAX_ERROR_COUNT = 4;
 
     private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
+
     private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
+    private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
 
     private final Context mContext;
     private final INetworkManagementService mNetService;
@@ -66,7 +68,8 @@
 
     private final Object mStateLock = new Object();
 
-    private PendingIntent mResetIntent;
+    private final PendingIntent mConfigIntent;
+    private final PendingIntent mResetIntent;
 
     private String mAcceptedEgressIface;
     private String mAcceptedIface;
@@ -86,6 +89,10 @@
         mVpn = Preconditions.checkNotNull(vpn);
         mProfile = Preconditions.checkNotNull(profile);
 
+        final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
+        configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true);
+        mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
+
         final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET);
         resetIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0);
@@ -193,6 +200,7 @@
             // TODO: support non-standard port numbers
             mNetService.setFirewallEgressDestRule(mProfile.server, 500, true);
             mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true);
+            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true);
         } catch (RemoteException e) {
             throw new RuntimeException("Problem setting firewall rules", e);
         }
@@ -218,6 +226,7 @@
         try {
             mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
             mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
+            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false);
         } catch (RemoteException e) {
             throw new RuntimeException("Problem setting firewall rules", e);
         }
@@ -281,10 +290,13 @@
         builder.setWhen(0);
         builder.setSmallIcon(iconRes);
         builder.setContentTitle(mContext.getString(titleRes));
-        builder.setContentText(mContext.getString(R.string.vpn_lockdown_reset));
-        builder.setContentIntent(mResetIntent);
+        builder.setContentText(mContext.getString(R.string.vpn_lockdown_config));
+        builder.setContentIntent(mConfigIntent);
         builder.setPriority(Notification.PRIORITY_LOW);
         builder.setOngoing(true);
+        builder.addAction(
+                R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), mResetIntent);
+
         NotificationManager.from(mContext).notify(TAG, 0, builder.build());
     }
 
diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/java/com/android/server/wifi/WifiNotificationController.java
new file mode 100644
index 0000000..17ef7c8
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiNotificationController.java
@@ -0,0 +1,292 @@
+/*
+ * 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.wifi;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.TaskStackBuilder;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.NetworkInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiStateMachine;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/* Takes care of handling the "open wi-fi network available" notification @hide */
+final class WifiNotificationController {
+    /**
+     * The icon to show in the 'available networks' notification. This will also
+     * be the ID of the Notification given to the NotificationManager.
+     */
+    private static final int ICON_NETWORKS_AVAILABLE =
+            com.android.internal.R.drawable.stat_notify_wifi_in_range;
+    /**
+     * When a notification is shown, we wait this amount before possibly showing it again.
+     */
+    private final long NOTIFICATION_REPEAT_DELAY_MS;
+    /**
+     * Whether the user has set the setting to show the 'available networks' notification.
+     */
+    private boolean mNotificationEnabled;
+    /**
+     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
+     */
+    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
+    /**
+     * The {@link System#currentTimeMillis()} must be at least this value for us
+     * to show the notification again.
+     */
+    private long mNotificationRepeatTime;
+    /**
+     * The Notification object given to the NotificationManager.
+     */
+    private Notification mNotification;
+    /**
+     * Whether the notification is being shown, as set by us. That is, if the
+     * user cancels the notification, we will not receive the callback so this
+     * will still be true. We only guarantee if this is false, then the
+     * notification is not showing.
+     */
+    private boolean mNotificationShown;
+    /**
+     * The number of continuous scans that must occur before consider the
+     * supplicant in a scanning state. This allows supplicant to associate with
+     * remembered networks that are in the scan results.
+     */
+    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
+    /**
+     * The number of scans since the last network state change. When this
+     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
+     * supplicant to actually be scanning. When the network state changes to
+     * something other than scanning, we reset this to 0.
+     */
+    private int mNumScansSinceNetworkStateChange;
+
+    private final Context mContext;
+    private final WifiStateMachine mWifiStateMachine;
+    private NetworkInfo mNetworkInfo;
+
+    WifiNotificationController(Context context, WifiStateMachine wsm) {
+        mContext = context;
+        mWifiStateMachine = wsm;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                            resetNotification();
+                        } else if (intent.getAction().equals(
+                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                            // reset & clear notification on a network connect & disconnect
+                            switch(mNetworkInfo.getDetailedState()) {
+                                case CONNECTED:
+                                case DISCONNECTED:
+                                case CAPTIVE_PORTAL_CHECK:
+                                    resetNotification();
+                                    break;
+                            }
+                        } else if (intent.getAction().equals(
+                                WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                            checkAndSetNotification(mNetworkInfo,
+                                    mWifiStateMachine.syncGetScanResultsList());
+                        }
+                    }
+                }, filter);
+
+        // Setting is in seconds
+        NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
+        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
+        mNotificationEnabledSettingObserver.register();
+    }
+
+    private synchronized void checkAndSetNotification(NetworkInfo networkInfo,
+            List<ScanResult> scanResults) {
+        // TODO: unregister broadcast so we do not have to check here
+        // If we shouldn't place a notification on available networks, then
+        // don't bother doing any of the following
+        if (!mNotificationEnabled) return;
+        if (networkInfo == null) return;
+
+        NetworkInfo.State state = networkInfo.getState();
+        if ((state == NetworkInfo.State.DISCONNECTED)
+                || (state == NetworkInfo.State.UNKNOWN)) {
+            if (scanResults != null) {
+                int numOpenNetworks = 0;
+                for (int i = scanResults.size() - 1; i >= 0; i--) {
+                    ScanResult scanResult = scanResults.get(i);
+
+                    //A capability of [ESS] represents an open access point
+                    //that is available for an STA to connect
+                    if (scanResult.capabilities != null &&
+                            scanResult.capabilities.equals("[ESS]")) {
+                        numOpenNetworks++;
+                    }
+                }
+
+                if (numOpenNetworks > 0) {
+                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
+                        /*
+                         * We've scanned continuously at least
+                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
+                         * probably does not have a remembered network in range,
+                         * since otherwise supplicant would have tried to
+                         * associate and thus resetting this counter.
+                         */
+                        setNotificationVisible(true, numOpenNetworks, false, 0);
+                    }
+                    return;
+                }
+            }
+        }
+
+        // No open networks in range, remove the notification
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Clears variables related to tracking whether a notification has been
+     * shown recently and clears the current notification.
+     */
+    private synchronized void resetNotification() {
+        mNotificationRepeatTime = 0;
+        mNumScansSinceNetworkStateChange = 0;
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Display or don't display a notification that there are open Wi-Fi networks.
+     * @param visible {@code true} if notification should be visible, {@code false} otherwise
+     * @param numNetworks the number networks seen
+     * @param force {@code true} to force notification to be shown/not-shown,
+     * even if it is already shown/not-shown.
+     * @param delay time in milliseconds after which the notification should be made
+     * visible or invisible.
+     */
+    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
+            int delay) {
+
+        // Since we use auto cancel on the notification, when the
+        // mNetworksAvailableNotificationShown is true, the notification may
+        // have actually been canceled.  However, when it is false we know
+        // for sure that it is not being shown (it will not be shown any other
+        // place than here)
+
+        // If it should be hidden and it is already hidden, then noop
+        if (!visible && !mNotificationShown && !force) {
+            return;
+        }
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        Message message;
+        if (visible) {
+
+            // Not enough time has passed to show the notification again
+            if (System.currentTimeMillis() < mNotificationRepeatTime) {
+                return;
+            }
+
+            if (mNotification == null) {
+                // Cache the Notification object.
+                mNotification = new Notification();
+                mNotification.when = 0;
+                mNotification.icon = ICON_NETWORKS_AVAILABLE;
+                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+                mNotification.contentIntent = TaskStackBuilder.create(mContext)
+                        .addNextIntentWithParentStack(
+                                new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
+                        .getPendingIntent(0, 0, null, UserHandle.CURRENT);
+            }
+
+            CharSequence title = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available, numNetworks);
+            CharSequence details = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
+            mNotification.tickerText = title;
+            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
+
+            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
+
+            notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
+                    UserHandle.ALL);
+        } else {
+            notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
+        }
+
+        mNotificationShown = visible;
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mNotificationEnabled " + mNotificationEnabled);
+        pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
+        pw.println("mNotificationShown " + mNotificationShown);
+        pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange);
+    }
+
+    private class NotificationEnabledSettingObserver extends ContentObserver {
+        public NotificationEnabledSettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void register() {
+            ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+            synchronized (WifiNotificationController.this) {
+                mNotificationEnabled = getValue();
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+
+            synchronized (WifiNotificationController.this) {
+                mNotificationEnabled = getValue();
+                resetNotification();
+            }
+        }
+
+        private boolean getValue() {
+            return Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+        }
+    }
+
+}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
similarity index 70%
rename from services/java/com/android/server/WifiService.java
rename to services/java/com/android/server/wifi/WifiService.java
index ad6eb4d..94b3ed3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -14,45 +14,33 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.wifi;
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
-import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.TaskStackBuilder;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.database.ContentObserver;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
-import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiStateMachine;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiWatchdogStateMachine;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WpsInfo;
-import android.net.wifi.WpsResult;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
-import android.net.TrafficStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Messenger;
@@ -61,12 +49,10 @@
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 
@@ -75,11 +61,7 @@
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.TelephonyIntents;
@@ -97,13 +79,13 @@
 // as a SM to track soft AP/client/adhoc bring up based
 // on device idle state, airplane mode and boot.
 
-public class WifiService extends IWifiManager.Stub {
+public final class WifiService extends IWifiManager.Stub {
     private static final String TAG = "WifiService";
     private static final boolean DBG = false;
 
     private final WifiStateMachine mWifiStateMachine;
 
-    private Context mContext;
+    private final Context mContext;
 
     private AlarmManager mAlarmManager;
     private PendingIntent mIdleIntent;
@@ -130,19 +112,14 @@
     private final IBatteryStats mBatteryStats;
     private final AppOpsManager mAppOps;
 
-    private boolean mEnableTrafficStatsPoll = false;
-    private int mTrafficStatsPollToken = 0;
-    private long mTxPkts;
-    private long mRxPkts;
-    /* Tracks last reported data activity */
-    private int mDataActivity;
     private String mInterfaceName;
 
-    /**
-     * Interval in milliseconds between polling for traffic
-     * statistics
-     */
-    private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
+    /* Tracks the open wi-fi network notification */
+    private WifiNotificationController mNotificationController;
+    /* Polls traffic stats and notifies clients */
+    private WifiTrafficPoller mTrafficPoller;
+    /* Tracks the persisted states for wi-fi & airplane mode */
+    private WifiSettingsStore mSettingsStore;
 
     /**
      * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
@@ -156,78 +133,14 @@
     private static final String ACTION_DEVICE_IDLE =
             "com.android.server.WifiManager.action.DEVICE_IDLE";
 
-    private static final int WIFI_DISABLED                  = 0;
-    private static final int WIFI_ENABLED                   = 1;
-    /* Wifi enabled while in airplane mode */
-    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
-    /* Wifi disabled due to airplane mode on */
-    private static final int WIFI_DISABLED_AIRPLANE_ON      = 3;
-
-    /* Persisted state that tracks the wifi & airplane interaction from settings */
-    private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
-    /* Tracks current airplane mode state */
-    private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
-    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
-    private boolean mWifiEnabled;
-
     /* The work source (UID) that triggered the current WIFI scan, synchronized
      * on this */
     private WorkSource mScanWorkSource;
 
     private boolean mIsReceiverRegistered = false;
 
-
     NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
 
-    // Variables relating to the 'available networks' notification
-    /**
-     * The icon to show in the 'available networks' notification. This will also
-     * be the ID of the Notification given to the NotificationManager.
-     */
-    private static final int ICON_NETWORKS_AVAILABLE =
-            com.android.internal.R.drawable.stat_notify_wifi_in_range;
-    /**
-     * When a notification is shown, we wait this amount before possibly showing it again.
-     */
-    private final long NOTIFICATION_REPEAT_DELAY_MS;
-    /**
-     * Whether the user has set the setting to show the 'available networks' notification.
-     */
-    private boolean mNotificationEnabled;
-    /**
-     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
-     */
-    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
-    /**
-     * The {@link System#currentTimeMillis()} must be at least this value for us
-     * to show the notification again.
-     */
-    private long mNotificationRepeatTime;
-    /**
-     * The Notification object given to the NotificationManager.
-     */
-    private Notification mNotification;
-    /**
-     * Whether the notification is being shown, as set by us. That is, if the
-     * user cancels the notification, we will not receive the callback so this
-     * will still be true. We only guarantee if this is false, then the
-     * notification is not showing.
-     */
-    private boolean mNotificationShown;
-    /**
-     * The number of continuous scans that must occur before consider the
-     * supplicant in a scanning state. This allows supplicant to associate with
-     * remembered networks that are in the scan results.
-     */
-    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
-    /**
-     * The number of scans since the last network state change. When this
-     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
-     * supplicant to actually be scanning. When the network state changes to
-     * something other than scanning, we reset this to 0.
-     */
-    private int mNumScansSinceNetworkStateChange;
-
     /**
      * Asynchronous channel to WifiStateMachine
      */
@@ -241,9 +154,9 @@
     /**
      * Handles client connections
      */
-    private class AsyncServiceHandler extends Handler {
+    private class ClientHandler extends Handler {
 
-        AsyncServiceHandler(android.os.Looper looper) {
+        ClientHandler(android.os.Looper looper) {
             super(looper);
         }
 
@@ -273,48 +186,13 @@
                     ac.connect(mContext, this, msg.replyTo);
                     break;
                 }
-                case WifiManager.ENABLE_TRAFFIC_STATS_POLL: {
-                    mEnableTrafficStatsPoll = (msg.arg1 == 1);
-                    mTrafficStatsPollToken++;
-                    if (mEnableTrafficStatsPoll) {
-                        notifyOnDataActivity();
-                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
-                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
-                    }
-                    break;
-                }
-                case WifiManager.TRAFFIC_STATS_POLL: {
-                    if (msg.arg1 == mTrafficStatsPollToken) {
-                        notifyOnDataActivity();
-                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
-                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
-                    }
-                    break;
-                }
-                case WifiManager.CONNECT_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.SAVE_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.FORGET_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.START_WPS: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.CANCEL_WPS: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.DISABLE_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
+                /* Client commands are forwarded to state machine */
+                case WifiManager.CONNECT_NETWORK:
+                case WifiManager.SAVE_NETWORK:
+                case WifiManager.FORGET_NETWORK:
+                case WifiManager.START_WPS:
+                case WifiManager.CANCEL_WPS:
+                case WifiManager.DISABLE_NETWORK:
                 case WifiManager.RSSI_PKTCNT_FETCH: {
                     mWifiStateMachine.sendMessage(Message.obtain(msg));
                     break;
@@ -326,7 +204,7 @@
             }
         }
     }
-    private AsyncServiceHandler mAsyncServiceHandler;
+    private ClientHandler mClientHandler;
 
     /**
      * Handles interaction with WifiStateMachine
@@ -375,7 +253,7 @@
     private final WorkSource mTmpWorkSource = new WorkSource();
     private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
 
-    WifiService(Context context) {
+    public WifiService(Context context) {
         mContext = context;
 
         mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
@@ -389,65 +267,36 @@
         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
 
+        mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
+        mTrafficPoller = new WifiTrafficPoller(mContext, mClients, mInterfaceName);
+        mSettingsStore = new WifiSettingsStore(mContext);
+
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        mAirplaneModeOn.set(isAirplaneModeOn());
-                        handleAirplaneModeToggled(mAirplaneModeOn.get());
-                        updateWifiState();
+                        if (mSettingsStore.handleAirplaneModeToggled()) {
+                            updateWifiState();
+                        }
                     }
                 },
                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                                    WifiManager.WIFI_STATE_DISABLED);
-
-                            mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
-
-                           // reset & clear notification on any wifi state change
-                            resetNotification();
-                        } else if (intent.getAction().equals(
-                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
-                                    WifiManager.EXTRA_NETWORK_INFO);
-                            // reset & clear notification on a network connect & disconnect
-                            switch(mNetworkInfo.getDetailedState()) {
-                                case CONNECTED:
-                                case DISCONNECTED:
-                                case CAPTIVE_PORTAL_CHECK:
-                                    evaluateTrafficStatsPolling();
-                                    resetNotification();
-                                    break;
-                            }
-                        } else if (intent.getAction().equals(
+                        if (intent.getAction().equals(
                                 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                             noteScanEnd();
-                            checkAndSetNotification();
                         }
                     }
-                }, filter);
+                }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
 
         HandlerThread wifiThread = new HandlerThread("WifiService");
         wifiThread.start();
-        mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
+        mClientHandler = new ClientHandler(wifiThread.getLooper());
         mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
-
-        // Setting is in seconds
-        NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
-        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
-        mNotificationEnabledSettingObserver.register();
     }
 
     /** Tell battery stats about a new WIFI scan */
@@ -495,10 +344,8 @@
      * This function is used only at boot time
      */
     public void checkAndStartWifi() {
-        mAirplaneModeOn.set(isAirplaneModeOn());
-        mPersistWifiState.set(getPersistedWifiState());
-        /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
-        boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
+        /* Check if wi-fi needs to be enabled */
+        boolean wifiEnabled = mSettingsStore.shouldWifiBeEnabled();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
 
@@ -511,75 +358,6 @@
 
     }
 
-    private boolean testAndClearWifiSavedState() {
-        final ContentResolver cr = mContext.getContentResolver();
-        int wifiSavedState = 0;
-        try {
-            wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
-            if(wifiSavedState == 1)
-                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-        } catch (Settings.SettingNotFoundException e) {
-            ;
-        }
-        return (wifiSavedState == 1);
-    }
-
-    private int getPersistedWifiState() {
-        final ContentResolver cr = mContext.getContentResolver();
-        try {
-            return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
-        } catch (Settings.SettingNotFoundException e) {
-            Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
-            return WIFI_DISABLED;
-        }
-    }
-
-    private boolean shouldWifiBeEnabled() {
-        if (mAirplaneModeOn.get()) {
-            return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
-        } else {
-            return mPersistWifiState.get() != WIFI_DISABLED;
-        }
-    }
-
-    private void handleWifiToggled(boolean wifiEnabled) {
-        boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable();
-        if (wifiEnabled) {
-            if (airplaneEnabled) {
-                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
-            } else {
-                persistWifiState(WIFI_ENABLED);
-            }
-        } else {
-            // When wifi state is disabled, we do not care
-            // if airplane mode is on or not. The scenario of
-            // wifi being disabled due to airplane mode being turned on
-            // is handled handleAirplaneModeToggled()
-            persistWifiState(WIFI_DISABLED);
-        }
-    }
-
-    private void handleAirplaneModeToggled(boolean airplaneEnabled) {
-        if (airplaneEnabled) {
-            // Wifi disabled due to airplane on
-            if (mWifiEnabled) {
-                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
-            }
-        } else {
-            /* On airplane mode disable, restore wifi state if necessary */
-            if (testAndClearWifiSavedState() ||
-                    mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
-                persistWifiState(WIFI_ENABLED);
-            }
-        }
-    }
-
-    private void persistWifiState(int state) {
-        final ContentResolver cr = mContext.getContentResolver();
-        mPersistWifiState.set(state);
-        Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
-    }
-
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
      * @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -597,9 +375,9 @@
     /**
      * see {@link android.net.wifi.WifiManager#startScan()}
      */
-    public void startScan(boolean forceActive) {
+    public void startScan() {
         enforceChangePermission();
-        mWifiStateMachine.startScan(forceActive);
+        mWifiStateMachine.startScan();
         noteScanStart();
     }
 
@@ -640,24 +418,28 @@
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
 
-        if (enable) {
-            reportStartWorkSource();
-        }
-        mWifiStateMachine.setWifiEnabled(enable);
-
         /*
-         * Caller might not have WRITE_SECURE_SETTINGS,
-         * only CHANGE_WIFI_STATE is enforced
-         */
+        * Caller might not have WRITE_SECURE_SETTINGS,
+        * only CHANGE_WIFI_STATE is enforced
+        */
 
         long ident = Binder.clearCallingIdentity();
         try {
-            handleWifiToggled(enable);
+            if (! mSettingsStore.handleWifiToggled(enable)) {
+                // Nothing to do if wifi cannot be toggled
+                return true;
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
 
         if (enable) {
+            reportStartWorkSource();
+        }
+
+        mWifiStateMachine.setWifiEnabled(enable);
+
+        if (enable) {
             if (!mIsReceiverRegistered) {
                 registerForBroadcasts();
                 mIsReceiverRegistered = true;
@@ -1047,7 +829,7 @@
     public Messenger getWifiServiceMessenger() {
         enforceAccessPermission();
         enforceChangePermission();
-        return new Messenger(mAsyncServiceHandler);
+        return new Messenger(mClientHandler);
     }
 
     /** Get a reference to WifiStateMachine handler for AsyncChannel communication */
@@ -1082,14 +864,12 @@
                 }
                 mAlarmManager.cancel(mIdleIntent);
                 mScreenOff = false;
-                evaluateTrafficStatsPolling();
                 setDeviceIdleAndUpdateWifi(false);
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 if (DBG) {
                     Slog.d(TAG, "ACTION_SCREEN_OFF");
                 }
                 mScreenOff = true;
-                evaluateTrafficStatsPolling();
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
@@ -1221,11 +1001,11 @@
         }
 
         /* Disable tethering when airplane mode is enabled */
-        if (mAirplaneModeOn.get()) {
+        if (mSettingsStore.isAirplaneModeOn()) {
             mWifiStateMachine.setWifiApEnabled(null, false);
         }
 
-        if (shouldWifiBeEnabled()) {
+        if (mSettingsStore.shouldWifiBeEnabled()) {
             if (wifiShouldBeStarted) {
                 reportStartWorkSource();
                 mWifiStateMachine.setWifiEnabled(true);
@@ -1253,30 +1033,6 @@
         mContext.registerReceiver(mReceiver, intentFilter);
     }
 
-    private boolean isAirplaneSensitive() {
-        String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_RADIOS);
-        return airplaneModeRadios == null
-            || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
-    }
-
-    private boolean isAirplaneToggleable() {
-        String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
-        return toggleableRadios != null
-            && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
-    }
-
-    /**
-     * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
-     * currently on.
-     * @return {@code true} if airplane mode is on.
-     */
-    private boolean isAirplaneModeOn() {
-        return isAirplaneSensitive() && Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -1296,18 +1052,9 @@
         pw.println("mEmergencyCallbackMode " + mEmergencyCallbackMode);
         pw.println("mMulticastEnabled " + mMulticastEnabled);
         pw.println("mMulticastDisabled " + mMulticastDisabled);
-        pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
-        pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
-        pw.println("mTxPkts " + mTxPkts);
-        pw.println("mRxPkts " + mRxPkts);
-        pw.println("mDataActivity " + mDataActivity);
-        pw.println("mPersistWifiState " + mPersistWifiState.get());
-        pw.println("mAirplaneModeOn " + mAirplaneModeOn.get());
-        pw.println("mWifiEnabled " + mWifiEnabled);
-        pw.println("mNotificationEnabled " + mNotificationEnabled);
-        pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
-        pw.println("mNotificationShown " + mNotificationShown);
-        pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange);
+        mSettingsStore.dump(fd, pw, args);
+        mNotificationController.dump(fd, pw, args);
+        mTrafficPoller.dump(fd, pw, args);
 
         pw.println("Latest scan results:");
         List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
@@ -1700,194 +1447,4 @@
             return (mMulticasters.size() > 0);
         }
     }
-
-    /**
-     * Evaluate if traffic stats polling is needed based on
-     * connection and screen on status
-     */
-    private void evaluateTrafficStatsPolling() {
-        Message msg;
-        if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
-            msg = Message.obtain(mAsyncServiceHandler,
-                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0);
-        } else {
-            msg = Message.obtain(mAsyncServiceHandler,
-                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0);
-        }
-        msg.sendToTarget();
-    }
-
-    private void notifyOnDataActivity() {
-        long sent, received;
-        long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
-        int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
-
-        mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
-        mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
-
-        if (preTxPkts > 0 || preRxPkts > 0) {
-            sent = mTxPkts - preTxPkts;
-            received = mRxPkts - preRxPkts;
-            if (sent > 0) {
-                dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
-            }
-            if (received > 0) {
-                dataActivity |= WifiManager.DATA_ACTIVITY_IN;
-            }
-
-            if (dataActivity != mDataActivity && !mScreenOff) {
-                mDataActivity = dataActivity;
-                for (AsyncChannel client : mClients) {
-                    client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
-                }
-            }
-        }
-    }
-
-
-    private void checkAndSetNotification() {
-        // If we shouldn't place a notification on available networks, then
-        // don't bother doing any of the following
-        if (!mNotificationEnabled) return;
-
-        State state = mNetworkInfo.getState();
-        if ((state == NetworkInfo.State.DISCONNECTED)
-                || (state == NetworkInfo.State.UNKNOWN)) {
-            // Look for an open network
-            List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
-            if (scanResults != null) {
-                int numOpenNetworks = 0;
-                for (int i = scanResults.size() - 1; i >= 0; i--) {
-                    ScanResult scanResult = scanResults.get(i);
-
-                    //A capability of [ESS] represents an open access point
-                    //that is available for an STA to connect
-                    if (scanResult.capabilities != null &&
-                            scanResult.capabilities.equals("[ESS]")) {
-                        numOpenNetworks++;
-                    }
-                }
-
-                if (numOpenNetworks > 0) {
-                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
-                        /*
-                         * We've scanned continuously at least
-                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
-                         * probably does not have a remembered network in range,
-                         * since otherwise supplicant would have tried to
-                         * associate and thus resetting this counter.
-                         */
-                        setNotificationVisible(true, numOpenNetworks, false, 0);
-                    }
-                    return;
-                }
-            }
-        }
-
-        // No open networks in range, remove the notification
-        setNotificationVisible(false, 0, false, 0);
-    }
-
-    /**
-     * Clears variables related to tracking whether a notification has been
-     * shown recently and clears the current notification.
-     */
-    private void resetNotification() {
-        mNotificationRepeatTime = 0;
-        mNumScansSinceNetworkStateChange = 0;
-        setNotificationVisible(false, 0, false, 0);
-    }
-
-    /**
-     * Display or don't display a notification that there are open Wi-Fi networks.
-     * @param visible {@code true} if notification should be visible, {@code false} otherwise
-     * @param numNetworks the number networks seen
-     * @param force {@code true} to force notification to be shown/not-shown,
-     * even if it is already shown/not-shown.
-     * @param delay time in milliseconds after which the notification should be made
-     * visible or invisible.
-     */
-    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
-            int delay) {
-
-        // Since we use auto cancel on the notification, when the
-        // mNetworksAvailableNotificationShown is true, the notification may
-        // have actually been canceled.  However, when it is false we know
-        // for sure that it is not being shown (it will not be shown any other
-        // place than here)
-
-        // If it should be hidden and it is already hidden, then noop
-        if (!visible && !mNotificationShown && !force) {
-            return;
-        }
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        Message message;
-        if (visible) {
-
-            // Not enough time has passed to show the notification again
-            if (System.currentTimeMillis() < mNotificationRepeatTime) {
-                return;
-            }
-
-            if (mNotification == null) {
-                // Cache the Notification object.
-                mNotification = new Notification();
-                mNotification.when = 0;
-                mNotification.icon = ICON_NETWORKS_AVAILABLE;
-                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
-                mNotification.contentIntent = TaskStackBuilder.create(mContext)
-                        .addNextIntentWithParentStack(
-                                new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
-                        .getPendingIntent(0, 0, null, UserHandle.CURRENT);
-            }
-
-            CharSequence title = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available, numNetworks);
-            CharSequence details = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
-            mNotification.tickerText = title;
-            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
-
-            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
-            notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
-                    UserHandle.ALL);
-        } else {
-            notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
-        }
-
-        mNotificationShown = visible;
-    }
-
-    private class NotificationEnabledSettingObserver extends ContentObserver {
-
-        public NotificationEnabledSettingObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void register() {
-            ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
-            mNotificationEnabled = getValue();
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-
-            mNotificationEnabled = getValue();
-            resetNotification();
-        }
-
-        private boolean getValue() {
-            return Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
-        }
-    }
-
-
 }
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/java/com/android/server/wifi/WifiSettingsStore.java
new file mode 100644
index 0000000..d7c8752
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiSettingsStore.java
@@ -0,0 +1,178 @@
+/*
+ * 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.wifi;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/* Tracks persisted settings for Wi-Fi and airplane mode interaction */
+final class WifiSettingsStore {
+    /* Values tracked in Settings.Global.WIFI_ON */
+    private static final int WIFI_DISABLED                      = 0;
+    private static final int WIFI_ENABLED                       = 1;
+    /* Wifi enabled while in airplane mode */
+    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE     = 2;
+    /* Wifi disabled due to airplane mode on */
+    private static final int WIFI_DISABLED_AIRPLANE_ON          = 3;
+
+    /* Persisted state that tracks the wifi & airplane interaction from settings */
+    private int mPersistWifiState = WIFI_DISABLED;
+    /* Tracks current airplane mode state */
+    private boolean mAirplaneModeOn = false;
+    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
+    private final Context mContext;
+
+    /* Tracks if we have checked the saved wi-fi state after boot */
+    private boolean mCheckSavedStateAtBoot = false;
+
+    WifiSettingsStore(Context context) {
+        mContext = context;
+        mAirplaneModeOn = getPersistedAirplaneModeOn();
+        mPersistWifiState = getPersistedWifiState();
+    }
+
+    synchronized boolean shouldWifiBeEnabled() {
+        if (!mCheckSavedStateAtBoot) {
+            mCheckSavedStateAtBoot = true;
+            if (testAndClearWifiSavedState()) return true;
+        }
+
+        if (mAirplaneModeOn) {
+            return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+        } else {
+            return mPersistWifiState != WIFI_DISABLED;
+        }
+    }
+
+    /**
+     * Returns true if airplane mode is currently on.
+     * @return {@code true} if airplane mode is on.
+     */
+    synchronized boolean isAirplaneModeOn() {
+       return mAirplaneModeOn;
+    }
+
+    synchronized boolean handleWifiToggled(boolean wifiEnabled) {
+        // Can Wi-Fi be toggled in airplane mode ?
+        if (mAirplaneModeOn && !isAirplaneToggleable()) {
+            return false;
+        }
+
+        if (wifiEnabled) {
+            if (mAirplaneModeOn) {
+                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+            } else {
+                persistWifiState(WIFI_ENABLED);
+            }
+        } else {
+            // When wifi state is disabled, we do not care
+            // if airplane mode is on or not. The scenario of
+            // wifi being disabled due to airplane mode being turned on
+            // is handled handleAirplaneModeToggled()
+            persistWifiState(WIFI_DISABLED);
+        }
+        return true;
+    }
+
+    synchronized boolean handleAirplaneModeToggled() {
+        // Is Wi-Fi sensitive to airplane mode changes ?
+        if (!isAirplaneSensitive()) {
+            return false;
+        }
+
+        mAirplaneModeOn = getPersistedAirplaneModeOn();
+        if (mAirplaneModeOn) {
+            // Wifi disabled due to airplane on
+            if (mPersistWifiState == WIFI_ENABLED) {
+                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
+            }
+        } else {
+            /* On airplane mode disable, restore wifi state if necessary */
+            if (testAndClearWifiSavedState() ||
+                    mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
+                persistWifiState(WIFI_ENABLED);
+            }
+        }
+        return true;
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mPersistWifiState " + mPersistWifiState);
+        pw.println("mAirplaneModeOn " + mAirplaneModeOn);
+    }
+
+    private void persistWifiState(int state) {
+        final ContentResolver cr = mContext.getContentResolver();
+        mPersistWifiState = state;
+        Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
+    }
+
+    /* Does Wi-Fi need to be disabled when airplane mode is on ? */
+    private boolean isAirplaneSensitive() {
+        String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_RADIOS);
+        return airplaneModeRadios == null
+                || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
+    }
+
+    /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */
+    private boolean isAirplaneToggleable() {
+        String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        return toggleableRadios != null
+                && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
+    }
+
+     /* After a reboot, we restore wi-fi to be on if it was turned off temporarily for tethering.
+      * The settings app tracks the saved state, but the framework has to check it at boot to
+      * make sure the wi-fi is turned on in case it was turned off for the purpose of tethering.
+      *
+      * Note that this is not part of the regular WIFI_ON setting because this only needs to
+      * be controlled through the settings app and not the Wi-Fi public API.
+      */
+    private boolean testAndClearWifiSavedState() {
+        final ContentResolver cr = mContext.getContentResolver();
+        int wifiSavedState = 0;
+        try {
+            wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
+            if(wifiSavedState == 1)
+                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+        } catch (Settings.SettingNotFoundException e) {
+            ;
+        }
+        return (wifiSavedState == 1);
+    }
+
+    private int getPersistedWifiState() {
+        final ContentResolver cr = mContext.getContentResolver();
+        try {
+            return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
+        } catch (Settings.SettingNotFoundException e) {
+            Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
+            return WIFI_DISABLED;
+        }
+    }
+
+    private boolean getPersistedAirplaneModeOn() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+    }
+}
diff --git a/services/java/com/android/server/wifi/WifiTrafficPoller.java b/services/java/com/android/server/wifi/WifiTrafficPoller.java
new file mode 100644
index 0000000..3fcb6c1
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiTrafficPoller.java
@@ -0,0 +1,163 @@
+/*
+ * 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.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import static android.net.NetworkInfo.DetailedState.CONNECTED;
+import android.net.TrafficStats;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.android.internal.util.AsyncChannel;
+
+/* Polls for traffic stats and notifies the clients */
+final class WifiTrafficPoller {
+    /**
+     * Interval in milliseconds between polling for traffic
+     * statistics
+     */
+    private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
+
+    private boolean mEnableTrafficStatsPoll = false;
+    private int mTrafficStatsPollToken = 0;
+    private long mTxPkts;
+    private long mRxPkts;
+    /* Tracks last reported data activity */
+    private int mDataActivity;
+
+    private final List<AsyncChannel> mClients;
+    // err on the side of updating at boot since screen on broadcast may be missed
+    // the first time
+    private AtomicBoolean mScreenOn = new AtomicBoolean(true);
+    private final TrafficHandler mTrafficHandler;
+    private NetworkInfo mNetworkInfo;
+    private final String mInterface;
+
+    WifiTrafficPoller(Context context, List<AsyncChannel> clients, String iface) {
+        mClients = clients;
+        mInterface = iface;
+        mTrafficHandler = new TrafficHandler();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_SCREEN_ON);
+
+        context.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (intent.getAction().equals(
+                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+                            mScreenOn.set(false);
+                        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+                            mScreenOn.set(true);
+                        }
+                        evaluateTrafficStatsPolling();
+                    }
+                }, filter);
+    }
+
+
+    private class TrafficHandler extends Handler {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case WifiManager.ENABLE_TRAFFIC_STATS_POLL: {
+                    mEnableTrafficStatsPoll = (msg.arg1 == 1);
+                    mTrafficStatsPollToken++;
+                    if (mEnableTrafficStatsPoll) {
+                        notifyOnDataActivity();
+                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
+                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
+                    }
+                    break;
+                }
+                case WifiManager.TRAFFIC_STATS_POLL: {
+                    if (msg.arg1 == mTrafficStatsPollToken) {
+                        notifyOnDataActivity();
+                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
+                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
+                    }
+                    break;
+                }
+            }
+
+        }
+    }
+
+    private void evaluateTrafficStatsPolling() {
+        Message msg;
+        if (mNetworkInfo == null) return;
+        if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) {
+            msg = Message.obtain(mTrafficHandler,
+                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0);
+        } else {
+            msg = Message.obtain(mTrafficHandler,
+                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0);
+        }
+        msg.sendToTarget();
+    }
+
+    private void notifyOnDataActivity() {
+        long sent, received;
+        long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
+        int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
+
+        mTxPkts = TrafficStats.getTxPackets(mInterface);
+        mRxPkts = TrafficStats.getRxPackets(mInterface);
+
+        if (preTxPkts > 0 || preRxPkts > 0) {
+            sent = mTxPkts - preTxPkts;
+            received = mRxPkts - preRxPkts;
+            if (sent > 0) {
+                dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
+            }
+            if (received > 0) {
+                dataActivity |= WifiManager.DATA_ACTIVITY_IN;
+            }
+
+            if (dataActivity != mDataActivity && mScreenOn.get()) {
+                mDataActivity = dataActivity;
+                for (AsyncChannel client : mClients) {
+                    client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
+                }
+            }
+        }
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
+        pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
+        pw.println("mTxPkts " + mTxPkts);
+        pw.println("mRxPkts " + mRxPkts);
+        pw.println("mDataActivity " + mDataActivity);
+    }
+
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 5d4ab56..ae110dd 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -49,7 +49,6 @@
     BlackFrame mExitingBlackFrame;
     BlackFrame mEnteringBlackFrame;
     int mWidth, mHeight;
-    int mExitAnimId, mEnterAnimId;
 
     int mOriginalRotation;
     int mOriginalWidth, mOriginalHeight;
@@ -190,12 +189,9 @@
     }
 
     public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
-            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation,
-            int exitAnim, int enterAnim) {
+            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
         mContext = context;
         mDisplay = display;
-        mExitAnimId = exitAnim;
-        mEnterAnimId = enterAnim;
 
         // Screenshot does NOT include rotation!
         if (originalRotation == Surface.ROTATION_90
@@ -321,7 +317,7 @@
         setRotationInTransaction(rotation);
         if (TWO_PHASE_ANIMATION) {
             return startAnimation(session, maxAnimationDuration, animationScale,
-                    finalWidth, finalHeight, false);
+                    finalWidth, finalHeight, false, 0, 0);
         }
 
         // Don't start animation yet.
@@ -332,7 +328,8 @@
      * Returns true if animating.
      */
     private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
-            float animationScale, int finalWidth, int finalHeight, boolean dismissing) {
+            float animationScale, int finalWidth, int finalHeight, boolean dismissing,
+            int exitAnim, int enterAnim) {
         if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
@@ -375,10 +372,10 @@
                 + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
 
         final boolean customAnim;
-        if (mExitAnimId != 0 && mEnterAnimId != 0) {
+        if (exitAnim != 0 && enterAnim != 0) {
             customAnim = true;
-            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, mExitAnimId);
-            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, mEnterAnimId);
+            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
+            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
         } else {
             customAnim = false;
             switch (delta) {
@@ -578,7 +575,7 @@
      * Returns true if animating.
      */
     public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
-            float animationScale, int finalWidth, int finalHeight) {
+            float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
         if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
         if (mSurfaceControl == null) {
             // Can't do animation.
@@ -586,7 +583,7 @@
         }
         if (!mStarted) {
             startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
-                    true);
+                    true, exitAnim, enterAnim);
         }
         if (!mStarted) {
             return false;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 0159877..6cc02a5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -544,6 +544,9 @@
 
     DragState mDragState = null;
 
+    // For frozen screen animations.
+    int mExitAnimId, mEnterAnimId;
+
     /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
      * methods. */
     class LayoutFields {
@@ -3158,6 +3161,7 @@
             if (mismatch || iterator.hasNext()) {
                 Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks);
                 Slog.w(TAG, "validateAppTokens: Mismatch! WindowManager=" + iterator);
+                Slog.w(TAG, "validateAppTokens: Mismatch! Callers=" + Debug.getCallers(4));
             }
         }
     }
@@ -3336,12 +3340,17 @@
         }
 
         synchronized(mWindowMap) {
-            AppWindowToken atoken = findAppWindowToken(token);
+            final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
-            mTaskIdToDisplayContents.get(atoken.groupId).setAppTaskId(atoken, groupId);
+            DisplayContent displayContent = mTaskIdToDisplayContents.get(atoken.groupId);
+            if (displayContent == null) {
+                Slog.w(TAG, "setAppGroupId: No DisplayContent for taskId=" + atoken.groupId);
+                displayContent = getDefaultDisplayContentLocked();
+            }
+            displayContent.setAppTaskId(atoken, groupId);
         }
     }
 
@@ -3500,7 +3509,13 @@
                 if (currentConfig.diff(mTempConfiguration) != 0) {
                     mWaitingForConfig = true;
                     getDefaultDisplayContentLocked().layoutNeeded = true;
-                    startFreezingDisplayLocked(false, 0, 0);
+                    int anim[] = new int[2];
+                    if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+                        anim[0] = anim[1] = 0;
+                    } else {
+                        mPolicy.selectRotationAnimationLw(anim);
+                    }
+                    startFreezingDisplayLocked(false, anim[0], anim[1]);
                     config = new Configuration(mTempConfiguration);
                 }
             }
@@ -5480,7 +5495,13 @@
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
         getDefaultDisplayContentLocked().layoutNeeded = true;
-        startFreezingDisplayLocked(inTransaction, 0, 0);
+        final int[] anim = new int[2];
+        if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+            anim[0] = anim[1] = 0;
+        } else {
+            mPolicy.selectRotationAnimationLw(anim);
+        }
+        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
         // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
         screenRotationAnimation =
                 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
@@ -9241,8 +9262,7 @@
         return null;
     }
 
-    private void startFreezingDisplayLocked(boolean inTransaction,
-            int exitAnim, int enterAnim) {
+    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
         if (mDisplayFrozen) {
             return;
         }
@@ -9274,6 +9294,8 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
+            mExitAnimId = exitAnim;
+            mEnterAnimId = enterAnim;
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             final int displayId = displayContent.getDisplayId();
             ScreenRotationAnimation screenRotationAnimation =
@@ -9287,8 +9309,7 @@
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             screenRotationAnimation = new ScreenRotationAnimation(mContext,
                     display, mFxSession, inTransaction, displayInfo.logicalWidth,
-                    displayInfo.logicalHeight, display.getRotation(),
-                    exitAnim, enterAnim);
+                    displayInfo.logicalHeight, display.getRotation());
             mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
         }
     }
@@ -9326,9 +9347,14 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             // TODO(multidisplay): rotation on main screen only.
             DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            // Get rotation animation again, with new top window
+            boolean isDimming = mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY);
+            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
+                mExitAnimId = mEnterAnimId = 0;
+            }
             if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, displayInfo.logicalWidth,
-                        displayInfo.logicalHeight)) {
+                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
                 scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 2414d70..8701cc8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -188,11 +188,6 @@
         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/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0be453c..bef5824 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -43,7 +43,7 @@
 
     boolean pingSupplicant();
 
-    void startScan(boolean forceActive);
+    void startScan();
 
     List<ScanResult> getScanResults(String callingPackage);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c08db07..008a81b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -733,26 +733,7 @@
      */
     public boolean startScan() {
         try {
-            mService.startScan(false);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Request a scan for access points. Returns immediately. The availability
-     * of the results is made known later by means of an asynchronous event sent
-     * on completion of the scan.
-     * This is a variant of startScan that forces an active scan, even if passive
-     * scans are the current default
-     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
-     *
-     * @hide
-     */
-    public boolean startScanActive() {
-        try {
-            mService.startScan(true);
+            mService.startScan();
             return true;
         } catch (RemoteException e) {
             return false;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 7a9f106..59f1889 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -42,11 +42,14 @@
 
     private static final boolean DBG = false;
     private final String mTAG;
-    private static final int DEFAULT_GROUP_OWNER_INTENT = 6;
+    private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
 
-    static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0;
-    static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
-    static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2;
+    static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
+    static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
+    static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
+
+    static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
+    static final int SCAN_WITH_CONNECTION_SETUP             = 2;
 
     String mInterface = "";
     private boolean mSuspendOptEnabled = false;
@@ -116,15 +119,13 @@
         return (pong != null && pong.equals("PONG"));
     }
 
-    public boolean scan() {
-       return doBooleanCommand("SCAN");
-    }
-
-    public boolean setScanMode(boolean setActive) {
-        if (setActive) {
-            return doBooleanCommand("DRIVER SCAN-ACTIVE");
+    public boolean scan(int type) {
+        if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
+            return doBooleanCommand("SCAN TYPE=ONLY");
+        } else if (type == SCAN_WITH_CONNECTION_SETUP) {
+            return doBooleanCommand("SCAN");
         } else {
-            return doBooleanCommand("DRIVER SCAN-PASSIVE");
+            throw new IllegalArgumentException("Invalid scan type");
         }
     }
 
@@ -332,12 +333,7 @@
     }
 
     public boolean saveConfig() {
-        // Make sure we never write out a value for AP_SCAN other than 1
-        return doBooleanCommand("AP_SCAN 1") && doBooleanCommand("SAVE_CONFIG");
-    }
-
-    public boolean setScanResultHandling(int mode) {
-        return doBooleanCommand("AP_SCAN " + mode);
+        return doBooleanCommand("SAVE_CONFIG");
     }
 
     public boolean addToBlacklist(String bssid) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index ed8b99b..7da4caa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -139,8 +139,6 @@
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
     private boolean mScanResultIsPending = false;
-    /* Tracks if the current scan settings are active */
-    private boolean mSetScanActive = false;
     /* Tracks if state machine has received any screen state change broadcast yet.
      * We can miss one of these at boot.
      */
@@ -305,14 +303,12 @@
     static final int CMD_START_SCAN                       = BASE + 71;
     /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
     static final int CMD_SET_SCAN_MODE                    = BASE + 72;
-    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
-    static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
     /* Disconnect from a network */
-    static final int CMD_DISCONNECT                       = BASE + 74;
+    static final int CMD_DISCONNECT                       = BASE + 73;
     /* Reconnect to a network */
-    static final int CMD_RECONNECT                        = BASE + 75;
+    static final int CMD_RECONNECT                        = BASE + 74;
     /* Reassociate to a network */
-    static final int CMD_REASSOCIATE                      = BASE + 76;
+    static final int CMD_REASSOCIATE                      = BASE + 75;
     /* Controls suspend mode optimizations
      *
      * When high perf mode is enabled, suspend mode optimizations are disabled
@@ -365,9 +361,6 @@
     private static final int CONNECT_MODE   = 1;
     private static final int SCAN_ONLY_MODE = 2;
 
-    private static final int SCAN_ACTIVE = 1;
-    private static final int SCAN_PASSIVE = 2;
-
     private static final int SUCCESS = 1;
     private static final int FAILURE = -1;
 
@@ -632,7 +625,7 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        startScan(false);
+                        startScan();
                     }
                 },
                 new IntentFilter(ACTION_START_SCAN));
@@ -743,9 +736,13 @@
     /**
      * TODO: doc
      */
-    public void startScan(boolean forceActive) {
-        sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
-                SCAN_ACTIVE : SCAN_PASSIVE, 0));
+    public void startScan() {
+        sendMessage(CMD_START_SCAN);
+    }
+
+    private void startScanNative(int type) {
+        mWifiNative.scan(type);
+        mScanResultIsPending = true;
     }
 
     /**
@@ -889,17 +886,6 @@
     /**
      * TODO: doc
      */
-    public void setScanType(boolean active) {
-        if (active) {
-            sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
-        } else {
-            sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
-        }
-    }
-
-    /**
-     * TODO: doc
-     */
     public List<ScanResult> syncGetScanResultsList() {
         synchronized (mScanResultCache) {
             List<ScanResult> scanList = new ArrayList<ScanResult>();
@@ -1931,7 +1917,6 @@
                 case CMD_BLACKLIST_NETWORK:
                 case CMD_CLEAR_BLACKLIST:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_RSSI_POLL:
@@ -2101,7 +2086,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2237,7 +2221,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2365,7 +2348,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2585,7 +2567,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2649,7 +2630,6 @@
                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                 case WifiMonitor.WPS_OVERLAP_EVENT:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2700,11 +2680,9 @@
             }
 
             if (mIsScanMode) {
-                mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
                 mWifiNative.disconnect();
                 transitionTo(mScanModeState);
             } else {
-                mWifiNative.setScanResultHandling(CONNECT_MODE);
                 mWifiNative.reconnect();
                 // Status pulls in the current supplicant state and network connection state
                 // events over the monitor connection. This helps framework sync up with
@@ -2731,20 +2709,8 @@
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
             switch(message.what) {
-               case CMD_SET_SCAN_TYPE:
-                    mSetScanActive = (message.arg1 == SCAN_ACTIVE);
-                    mWifiNative.setScanMode(mSetScanActive);
-                    break;
                 case CMD_START_SCAN:
-                    boolean forceActive = (message.arg1 == SCAN_ACTIVE);
-                    if (forceActive && !mSetScanActive) {
-                        mWifiNative.setScanMode(forceActive);
-                    }
-                    mWifiNative.scan();
-                    if (forceActive && !mSetScanActive) {
-                        mWifiNative.setScanMode(mSetScanActive);
-                    }
-                    mScanResultIsPending = true;
+                    startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
@@ -2759,7 +2725,7 @@
                     if (mWifiNative.setBand(band)) {
                         mFrequencyBand.set(band);
                         //Fetch the latest scan results when frequency band is set
-                        startScan(true);
+                        startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     } else {
                         loge("Failed to set frequency band " + band);
                     }
@@ -2906,7 +2872,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2942,7 +2907,6 @@
                     /* Queue driver commands */
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3005,12 +2969,14 @@
                         /* Ignore */
                         return HANDLED;
                     } else {
-                        mWifiNative.setScanResultHandling(message.arg1);
                         mWifiNative.reconnect();
                         mIsScanMode = false;
                         transitionTo(mDisconnectedState);
                     }
                     break;
+                case CMD_START_SCAN:
+                    startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
+                    break;
                     /* Ignore */
                 case CMD_DISCONNECT:
                 case CMD_RECONNECT:
@@ -3139,11 +3105,6 @@
                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
                     }
                     break;
-                case WifiMonitor.SCAN_RESULTS_EVENT:
-                    /* Set the scan setting back to "connect" mode */
-                    mWifiNative.setScanResultHandling(CONNECT_MODE);
-                    /* Handle scan results */
-                    return NOT_HANDLED;
                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
                     if (DBG) log("Network connection established");
                     mLastNetworkId = message.arg1;
@@ -3216,14 +3177,9 @@
                     }
                     break;
                 case CMD_START_SCAN:
-                    /* When the network is connected, re-scanning can trigger
-                     * a reconnection. Put it in scan-only mode during scan.
-                     * When scan results are received, the mode is switched
-                     * back to CONNECT_MODE.
-                     */
-                    mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
-                    /* Have the parent state handle the rest */
-                    return NOT_HANDLED;
+                    /* Do not attempt to connect when we are already connected */
+                    startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
+                    break;
                     /* Ignore connection to same network */
                 case WifiManager.CONNECT_NETWORK:
                     int netId = message.arg1;
@@ -3290,16 +3246,6 @@
 
             return HANDLED;
         }
-
-        @Override
-        public void exit() {
-            /* If a scan result is pending in connected state, the supplicant
-             * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
-             */
-            if (mScanResultIsPending) {
-                mWifiNative.setScanResultHandling(CONNECT_MODE);
-            }
-        }
     }
 
     class ObtainingIpState extends State {
@@ -3586,7 +3532,6 @@
                     break;
                 case CMD_SET_SCAN_MODE:
                     if (message.arg1 == SCAN_ONLY_MODE) {
-                        mWifiNative.setScanResultHandling(message.arg1);
                         //Supplicant disconnect to prevent further connects
                         mWifiNative.disconnect();
                         mIsScanMode = true;
@@ -3788,7 +3733,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3896,7 +3840,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3986,7 +3929,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING: