Merge "Fix race conditions in WakeLocks."
diff --git a/core/java/android/net/NetworkStats.aidl b/core/java/android/net/NetworkStats.aidl
new file mode 100644
index 0000000..d06ca65
--- /dev/null
+++ b/core/java/android/net/NetworkStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkStats;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
new file mode 100644
index 0000000..4430e00
--- /dev/null
+++ b/core/java/android/net/NetworkStats.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+
+/**
+ * Collection of network statistics. Can contain summary details across all
+ * interfaces, or details with per-UID granularity. Designed to parcel quickly
+ * across process boundaries.
+ *
+ * @hide
+ */
+public class NetworkStats implements Parcelable {
+    /** {@link #iface} value when entry is summarized over all interfaces. */
+    public static final String IFACE_ALL = null;
+    /** {@link #uid} value when entry is summarized over all UIDs. */
+    public static final int UID_ALL = 0;
+
+    /**
+     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
+     * generated.
+     */
+    public final long elapsedRealtime;
+    public final String[] iface;
+    public final int[] uid;
+    public final long[] rx;
+    public final long[] tx;
+
+    // TODO: add fg/bg stats and tag granularity
+
+    private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
+        this.elapsedRealtime = elapsedRealtime;
+        this.iface = iface;
+        this.uid = uid;
+        this.rx = rx;
+        this.tx = tx;
+    }
+
+    public NetworkStats(Parcel parcel) {
+        elapsedRealtime = parcel.readLong();
+        iface = parcel.createStringArray();
+        uid = parcel.createIntArray();
+        rx = parcel.createLongArray();
+        tx = parcel.createLongArray();
+    }
+
+    public static class Builder {
+        private long mElapsedRealtime;
+        private final String[] mIface;
+        private final int[] mUid;
+        private final long[] mRx;
+        private final long[] mTx;
+
+        private int mIndex = 0;
+
+        public Builder(long elapsedRealtime, int size) {
+            mElapsedRealtime = elapsedRealtime;
+            mIface = new String[size];
+            mUid = new int[size];
+            mRx = new long[size];
+            mTx = new long[size];
+        }
+
+        public void addEntry(String iface, int uid, long rx, long tx) {
+            mIface[mIndex] = iface;
+            mUid[mIndex] = uid;
+            mRx[mIndex] = rx;
+            mTx[mIndex] = tx;
+            mIndex++;
+        }
+
+        public NetworkStats build() {
+            if (mIndex != mIface.length) {
+                throw new IllegalArgumentException("unexpected number of entries");
+            }
+            return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
+        }
+    }
+
+    /**
+     * Find first stats index that matches the requested parameters.
+     */
+    public int findIndex(String iface, int uid) {
+        for (int i = 0; i < this.iface.length; i++) {
+            if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private static boolean equal(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
+    }
+
+    /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
+        for (int i = 0; i < iface.length; i++) {
+            pw.print(prefix);
+            pw.print("  iface="); pw.print(iface[i]);
+            pw.print(" uid="); pw.print(uid[i]);
+            pw.print(" rx="); pw.print(rx[i]);
+            pw.print(" tx="); pw.println(tx[i]);
+        }
+    }
+
+    @Override
+    public String toString() {
+        final CharArrayWriter writer = new CharArrayWriter();
+        dump("", new PrintWriter(writer));
+        return writer.toString();
+    }
+
+    /** {@inheritDoc} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(elapsedRealtime);
+        dest.writeStringArray(iface);
+        dest.writeIntArray(uid);
+        dest.writeLongArray(rx);
+        dest.writeLongArray(tx);
+    }
+
+    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+        public NetworkStats createFromParcel(Parcel in) {
+            return new NetworkStats(in);
+        }
+
+        public NetworkStats[] newArray(int size) {
+            return new NetworkStats[size];
+        }
+    };
+}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 212c5fb..fe36786 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@
 
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
 import android.net.wifi.WifiConfiguration;
 
 /**
@@ -65,7 +66,6 @@
      ** TETHERING RELATED
      **/
 
-
     /**
      * Returns true if IP forwarding is enabled
      */
@@ -181,17 +181,23 @@
     void setAccessPoint(in WifiConfiguration wifiConfig, String wlanIface, String softapIface);
 
     /**
-     * Read number of bytes sent over an interface
-     */
-    long getInterfaceTxCounter(String iface);
+     ** DATA USAGE RELATED
+     **/
 
     /**
-     * Read number of bytes received over an interface
+     * Return global network statistics summarized at an interface level,
+     * without any UID-level granularity.
      */
-    long getInterfaceRxCounter(String iface);
+    NetworkStats getNetworkStatsSummary();
 
     /**
-     * Configures bandwidth throttling on an interface
+     * Return detailed network statistics with UID-level granularity,
+     * including interface and tag details.
+     */
+    NetworkStats getNetworkStatsDetail();
+
+    /**
+     * Configures bandwidth throttling on an interface.
      */
     void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
 
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 984102a..2b79a76 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -261,6 +261,13 @@
     private static native boolean nDrawDisplayList(int renderer, int displayList,
             int width, int height, Rect dirty);
 
+    @Override
+    void outputDisplayList(DisplayList displayList) {
+        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    }
+
+    private static native void nOutputDisplayList(int renderer, int displayList);
+
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index caa7b74..23b3abc 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -64,6 +64,14 @@
     abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
 
     /**
+     * Outputs the specified display list to the log. This method exists for use by
+     * tools to output display lists for selected nodes to the log.
+     *
+     * @param displayList The display list to be logged.
+     */
+    abstract void outputDisplayList(DisplayList displayList);
+
+    /**
      * Draws the specified layer onto this canvas.
      *
      * @param layer The layer to composite on this canvas
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 3f05b29..d751d29 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,6 +375,7 @@
     private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
     private static final String REMOTE_PROFILE = "PROFILE";
     private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
+    private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
 
     private static HashMap<Class<?>, Field[]> sFieldsForClasses;
     private static HashMap<Class<?>, Method[]> sMethodsForClasses;
@@ -885,6 +886,8 @@
             final String[] params = parameters.split(" ");
             if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
                 capture(view, clientStream, params[0]);
+            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
+                outputDisplayList(view, params[0]);
             } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
                 invalidate(view, params[0]);
             } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
@@ -1156,6 +1159,11 @@
         }
     }
 
+    private static void outputDisplayList(View root, String parameter) throws IOException {
+        final View view = findView(root, parameter);
+        view.getViewRoot().outputDisplayList(view);
+    }
+
     private static void capture(View root, final OutputStream clientStream, String parameter)
             throws IOException {
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index f929a0e..d43a27f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -519,6 +519,11 @@
     return redraw;
 }
 
+static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
+    renderer->outputDisplayList(displayList);
+}
+
 // ----------------------------------------------------------------------------
 // Layers
 // ----------------------------------------------------------------------------
@@ -714,7 +719,7 @@
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
-
+    { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 565f183..620d293 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -150,8 +150,8 @@
          does not require auto-restore. -->
     <!-- the 6th element indicates boot-time dependency-met value. -->
     <string-array translatable="false" name="networkAttributes">
-        <item>"wifi,1,1,1,true"</item>
-        <item>"mobile,0,0,0,true"</item>
+        <item>"wifi,1,1,1,-1,true"</item>
+        <item>"mobile,0,0,0,-1,true"</item>
         <item>"mobile_mms,2,0,2,60000,true"</item>
         <item>"mobile_supl,3,0,2,60000,true"</item>
         <item>"mobile_hipri,5,0,3,60000,true"</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index b86a5f0..7dddd9a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -128,6 +128,60 @@
 combination of letters and numbers. They may include symbolic characters.
     </td>
   </tr>
+  
+  <tr>
+    <td>Complex password required</td>
+    <td>Requires that passwords must contain at least a letter, a numerical digit, and a special symbol. Introduced in Android 3.0.
+    </td>
+  </tr>
+  
+<tr> 
+  <td>Minimum letters required in password</td> <td>The minimum number of
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+  
+  <tr> 
+  <td>Minimum lowercase letters required in password</td> 
+  <td>The minimum number of lowercase 
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+  <tr> 
+  <td>Minimum non-letter characters required in password</td> 
+  <td>The minimum number of
+non-letter characters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+  
+<tr> 
+  <td>Minimum numerical digits required in password</td> 
+  <td>The minimum number of numerical digits required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Minimum symbols required in password</td> 
+  <td>The minimum number of symbols required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Minimum uppercase letters required in password</td> 
+  <td>The minimum number of uppercase letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Password expiration timeout</td> 
+  <td>When the password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. Introduced in Android 3.0.</td> 
+</tr>
+
+<tr> 
+  <td>Password history restriction</td> 
+  <td>This policy prevents users from reusing the last <em>n</em> unique passwords.
+ This policy is typically used in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}, which forces
+users to update their passwords after a specified amount of time has elapsed.
+Introduced in Android 3.0.</td> 
+</tr>
+  
   <tr>
     <td>Maximum failed password attempts </td>
     <td>Specifies how many times a user can enter the wrong password before the
@@ -141,6 +195,12 @@
 pressed a button before the device locks the screen. When this happens, users
 need to enter their PIN or passwords again before they can use their devices and
 access data.  The value can be between 1 and 60 minutes.</td> </tr>
+
+<tr> 
+<td>Require storage encryption</td> 
+<td>Specifies that the storage area should be encrypted, if the device supports it. 
+Introduced in Android 3.0.</td> </tr>
+
 </table>
 
 <h4>Other features</h4>
@@ -172,18 +232,28 @@
 to do the following:</p>
 <ul>
   <li>Set password quality.</li>
-  <li>Specify the minimum length for the user's password.</li>
+  <li>Specify requirements for the user's password, such as minimum length, the minimum number of
+  numeric characters it must contain, and so on.</li>
   <li>Set the password. If the password does not conform to the specified
 policies, the system  returns an error.</li>
   <li>Set how many failed password attempts can occur before the device is wiped
 (that is, restored to factory settings).</li>
+<li>Set how long from now the password will expire.</li>
+<li>Set the password history length (<em>length</em> refers to number of old passwords stored in the history). 
+This prevents users from reusing 
+one of the last <em>n</em> passwords they previously used.</li>
+<li>Specify that the storage area should be encrypted, if the device supports it.</li>
   <li>Set the maximum amount of inactive time that can elapse before the device
 locks.</li>
   <li>Make the device lock immediately.</li>
   <li>Wipe the device's data (that is, restore factory settings).</li>
+  
 </ul>
 
+
+
 <img src="{@docRoot}images/admin/device-admin-app.png"/>
+
 <p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
 
 
@@ -469,7 +539,13 @@
 other symbol) characters.</dd>
   <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a   password
 containing at least numeric characters.</dd>
-  <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_COMPLEX}</dt><dd>The user
+must have entered a password containing at least a letter, a numerical digit and
+a special symbol.</dd> 
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The
+policy requires some kind
 of password, but doesn't care what it is.</dd>
   <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
   The policy has no requirements   for the password. </dd>
@@ -482,6 +558,36 @@
 mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
 </pre>
 
+<h5>Set password content requirements</h5>
+
+<p>Beginning with Android 3.0, the {@link android.app.admin.DevicePolicyManager} class
+includes methods that let you fine-tune the contents of the password. For
+example, you could set a policy that states that passwords must contain at least
+<em>n</em> uppercase letters. Here are the methods for fine-tuning a password's
+contents:</p>
+<ul>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLetters(android.content.ComponentName,int) setPasswordMinimumLetters()}</li> 
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLowerCase(android.content.ComponentName,int) setPasswordMinimumLowerCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumUpperCase(android.content.ComponentName,int) setPasswordMinimumUpperCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNonLetter(android.content.ComponentName,int) setPasswordMinimumNonLetter()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNumeric(android.content.ComponentName,int) setPasswordMinimumNumeric()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumSymbols(android.content.ComponentName,int) setPasswordMinimumSymbols()}</li>
+</ul>
+<p>For example, this snippet states that the password must have at least 2 uppercase letters:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwMinUppercase = 2;
+...
+mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, pwMinUppercase);</pre>
+
+
 <h5>Set the minimum password length</h5>
 <p>You can specify that a password must be at least the specified minimum
 length. For example:</p>
@@ -501,7 +607,86 @@
  ...
 mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
 
-<h4 id="lock">Set  device lock</h4>
+<h5 id="expiration">Set password expiration timeout</h5>
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()} 
+method to set when a password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. For example:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+long pwExpiration;
+...
+mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, pwExpiration);
+</pre>
+
+<p>From the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/
+DeviceAdminSample.html"> Device Administration API sample</a>, here is the code
+that updates the password expiration status:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+private TextView mPasswordExpirationStatus;
+...
+void updatePasswordExpirationStatus() {
+    boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+    String statusText;
+    if (active) {
+        long now = System.currentTimeMillis();
+        // Query the DevicePolicyManager twice - first for the expiration values
+        // set by the sample app, and later, for the system values (which may be different
+        // if there is another administrator active.)
+        long expirationDate = mDPM.getPasswordExpiration(mDeviceAdminSample);
+        long mSecUntilExpiration = expirationDate - now;
+        if (mSecUntilExpiration &gt;= 0) {
+            statusText = &quot;Expiration in &quot; + countdownString(mSecUntilExpiration);
+        } else {
+            statusText = &quot;Expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+        }
+
+        // expirationTimeout is the cycle time between required password refresh
+        long expirationTimeout = mDPM.getPasswordExpirationTimeout(mDeviceAdminSample);
+        statusText += &quot; / timeout period &quot; + countdownString(expirationTimeout);
+
+        // Now report the aggregate (global) expiration time
+        statusText += &quot; / Aggregate &quot;;
+        expirationDate = mDPM.getPasswordExpiration(null);
+        mSecUntilExpiration = expirationDate - now;
+        if (mSecUntilExpiration &gt;= 0) {
+            statusText += &quot;expiration in &quot; + countdownString(mSecUntilExpiration);
+        } else {
+            statusText += &quot;expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+        }
+    } else {
+        statusText = &quot;&lt;inactive&gt;&quot;;
+    }
+    mPasswordExpirationStatus.setText(statusText);</pre>
+    
+<h5 id="history">Restrict password based on history</h5>
+
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setPasswordHistoryLength(android.content.ComponentName,int) setPasswordHistoryLength()} 
+method to limit users'
+ability to reuse old passwords. This method takes a <em>length</em>
+parameter, which specifies how many old
+passwords are stored. When this policy is active, users cannot enter a new
+password that matches the last <em>n</em> passwords. This prevents
+users from using the same password over and over. This policy is typically used
+in conjunction with 
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()},
+which forces users
+to update their passwords after a specified amount of time has elapsed. </p>
+
+<p>For example, this snippet prohibits users from reusing any of their last 5 passwords:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwHistoryLength = 5;
+...
+mDPM.setPasswordHistoryLength(mDeviceAdminSample, pwHistoryLength);
+</pre>
+
+<h4 id="lock">Set device lock</h4>
 <p>You can set the maximum period of user inactivity that can occur before the
 device locks. For example:</p>
 <pre>
@@ -516,6 +701,8 @@
 DevicePolicyManager mDPM;
 mDPM.lockNow();</pre>
 
+
+
 <h4 id="wipe">Perform data wipe</h4>
 
 <p>You can use the {@link android.app.admin.DevicePolicyManager} method
@@ -530,3 +717,20 @@
 mDPM.wipeData(0);</pre>
 <p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
 additional options. Currently the value must be 0. </p>
+
+<h4 id=storage">Storage encryption</h4>
+<p>Beginning with Android 3.0, you can use the 
+{@link android.app.admin.DevicePolicyManager#setStorageEncryption(android.content.ComponentName,boolean) setStorageEncryption()} 
+method to set a policy requiring encryption of the storage area, where supported.</p>
+
+<p>For example:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setStorageEncryption(mDeviceAdminSample, true);
+</pre>
+<p>
+See the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html"> Device Administration API sample</a> for a complete
+example of how to enable storage encryption.</p>
diff --git a/docs/html/guide/topics/usb/accessory.jd b/docs/html/guide/topics/usb/accessory.jd
index 7638e30..b0f4881 100644
--- a/docs/html/guide/topics/usb/accessory.jd
+++ b/docs/html/guide/topics/usb/accessory.jd
@@ -50,9 +50,9 @@
     </div>
   </div>
 
-  <p><a href="http://accessories.android.com/demokit">USB accessory mode allows users to connect
+  <p>USB accessory mode allows users to connect
   USB host hardware specifically designed for Android-powered devices. The accessories must adhere
-  to the Android accessory protocol outlined in</a> <a href=
+  to the Android accessory protocol outlined in the <a href=
   "http://accessories.android.com/demokit">Android Accessory Development Kit</a> documentation.
   This allows Android-powered devices that cannot act as a USB host to still interact with USB
   hardware. When an Android-powered device is in USB accessory mode, the attached Android USB
@@ -445,7 +445,7 @@
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction(); 
 
-      if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+        if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
             UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
             if (accessory != null) {
                 // call your method that cleans up and closes communication with the accessory
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
old mode 100755
new mode 100644
index fd001bd..2851194
--- a/docs/html/images/admin/device-admin-activate-prompt.png
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
old mode 100755
new mode 100644
index d966a28..c96defc
--- a/docs/html/images/admin/device-admin-app.png
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5d7b651..368164d 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.7,3.5,27.2,63.9,0.8,1.7,0.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.3,3.0,24.5,65.9,1.0,3.0,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -60,16 +60,16 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>2.7%</td></tr> 
-<tr><td>Android 1.6</td><td>4</td><td>3.5%</td></tr> 
-<tr><td>Android 2.1</td><td>7</td><td>27.2%</td></tr> 
-<tr><td>Android 2.2</td><td>8</td><td>63.9%</td></tr> 
-<tr><td>Android 2.3</td><td>9</td><td>0.8%</td></tr> 
-<tr><td>Android 2.3.3</td><td>10</td><td>1.7%</td></tr> 
-<tr><td>Android 3.0</td><td>11</td><td>0.2%</td></tr> 
+<tr><td>Android 1.5</td><td>3</td><td>2.3%</td></tr> 
+<tr><td>Android 1.6</td><td>4</td><td>3.0%</td></tr> 
+<tr><td>Android 2.1</td><td>7</td><td>24.5%</td></tr> 
+<tr><td>Android 2.2</td><td>8</td><td>65.9%</td></tr> 
+<tr><td>Android 2.3</td><td>9</td><td>1.0%</td></tr> 
+<tr><td>Android 2.3.3</td><td>10</td><td>3.0%</td></tr> 
+<tr><td>Android 3.0</td><td>11</td><td>0.3%</td></tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Data collected during two weeks ending on May 2, 2011</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -98,9 +98,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.9,99.9,100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7|90.2,91.1,92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0|73.8,75.3,77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5|33.4,34.5,37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.3|0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C1%3A%7C2010%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6|92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3|77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3|37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8|0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Last historical dataset collected during two weeks ending on May 2, 2011</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 34dda9a..f8582d8 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -177,6 +177,331 @@
 void DisplayList::init() {
 }
 
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
+    TextContainer text;
+
+    uint32_t count = (level + 1) * 2;
+    char indent[count + 1];
+    for (uint32_t i = 0; i < count; i++) {
+        indent[i] = ' ';
+    }
+    indent[count] = '\0';
+    LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+
+    int saveCount = renderer.getSaveCount() - 1;
+
+    mReader.rewind();
+
+    while (!mReader.eof()) {
+        int op = mReader.readInt();
+
+        switch (op) {
+            case DrawGLFunction: {
+                Functor *functor = (Functor *) getInt();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+            }
+            break;
+            case Save: {
+                int rendererNum = getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
+            }
+            break;
+            case Restore: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case RestoreToCount: {
+                int restoreCount = saveCount + getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
+            }
+            break;
+            case SaveLayer: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+            }
+            break;
+            case SaveLayerAlpha: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int alpha = getInt();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+            }
+            break;
+            case Translate: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
+            }
+            break;
+            case Rotate: {
+                float rotation = getFloat();
+                LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
+            }
+            break;
+            case Scale: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case Skew: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case SetMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ConcatMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ClipRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int regionOp = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, regionOp);
+            }
+            break;
+            case DrawDisplayList: {
+                DisplayList* displayList = getDisplayList();
+                uint32_t width = getUInt();
+                uint32_t height = getUInt();
+                LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, level + 1);
+                renderer.outputDisplayList(displayList, level + 1);
+            }
+            break;
+            case DrawLayer: {
+                Layer* layer = (Layer*) getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    layer, x, y, paint);
+            }
+            break;
+            case DrawBitmap: {
+                SkBitmap* bitmap = getBitmap();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, x, y, paint);
+            }
+            break;
+            case DrawBitmapMatrix: {
+                SkBitmap* bitmap = getBitmap();
+                SkMatrix* matrix = getMatrix();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, matrix, paint);
+            }
+            break;
+            case DrawBitmapRect: {
+                SkBitmap* bitmap = getBitmap();
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                float f7 = getFloat();
+                float f8 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+            }
+            break;
+            case DrawBitmapMesh: {
+                int verticesCount = 0;
+                uint32_t colorsCount = 0;
+                SkBitmap* bitmap = getBitmap();
+                uint32_t meshWidth = getInt();
+                uint32_t meshHeight = getInt();
+                float* vertices = getFloats(verticesCount);
+                bool hasColors = getInt();
+                int* colors = hasColors ? getInts(colorsCount) : NULL;
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPatch: {
+                int32_t* xDivs = NULL;
+                int32_t* yDivs = NULL;
+                uint32_t* colors = NULL;
+                uint32_t xDivsCount = 0;
+                uint32_t yDivsCount = 0;
+                int8_t numColors = 0;
+                SkBitmap* bitmap = getBitmap();
+                xDivs = getInts(xDivsCount);
+                yDivs = getInts(yDivsCount);
+                colors = getUInts(numColors);
+                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+                getFloat();
+                getFloat();
+                getFloat();
+                getFloat();
+                getPaint();
+            }
+            break;
+            case DrawColor: {
+                int color = getInt();
+                int xferMode = getInt();
+                LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
+            }
+            break;
+            case DrawRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawRoundRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+            }
+            break;
+            case DrawCircle: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+            }
+            break;
+            case DrawOval: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawArc: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                int i1 = getInt();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+            }
+            break;
+            case DrawPath: {
+                SkPath* path = getPath();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
+            }
+            break;
+            case DrawLines: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPoints: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawText: {
+                getText(&text);
+                int count = getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    text.text(), text.length(), count, x, y, paint);
+            }
+            break;
+            case ResetShader: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShader: {
+                SkiaShader* shader = getShader();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
+            }
+            break;
+            case ResetColorFilter: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupColorFilter: {
+                SkiaColorFilter *colorFilter = getColorFilter();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
+            }
+            break;
+            case ResetShadow: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShadow: {
+                float radius = getFloat();
+                float dx = getFloat();
+                float dy = getFloat();
+                int color = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
+                    radius, dx, dy, color);
+            }
+            break;
+            default:
+                LOGD("Display List error: op not handled: %s%s",
+                    (char*) indent, OP_NAMES[op]);
+                break;
+        }
+    }
+
+    LOGD("%sDone", (char*) indent + 2);
+}
+
+/**
+ * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
+ * in the output() function, since that function processes the same list of opcodes for the
+ * purposes of logging display list info for a given view.
+ */
 bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b782103..dcf2cf2 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -107,6 +107,8 @@
 
     bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
+    void output(OpenGLRenderer& renderer, uint32_t level = 0);
+
     static void outputLogBuffer(int fd);
 
 private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6f751e8..f6a21d4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1185,6 +1185,12 @@
     return false;
 }
 
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+    if (displayList) {
+        displayList->output(*this, level);
+    }
+}
+
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b5c37c2..271e4b1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,6 +98,7 @@
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
             Rect& dirty, uint32_t level = 0);
+    virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 44f5df2..d931350 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.content.pm.PackageManager;
+import android.net.NetworkStats;
 import android.net.Uri;
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
@@ -32,6 +33,8 @@
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.INetworkManagementService;
 import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Log;
@@ -44,13 +47,21 @@
 import android.database.ContentObserver;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.io.Reader;
 import java.lang.IllegalStateException;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.concurrent.CountDownLatch;
 
+import libcore.io.IoUtils;
+
 /**
  * @hide
  */
@@ -716,12 +727,47 @@
         return -1;
     }
 
-    public long getInterfaceRxCounter(String iface) {
-        return getInterfaceCounter(iface, true);
+    /** {@inheritDoc} */
+    public NetworkStats getNetworkStatsSummary() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        final String[] ifaces = listInterfaces();
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), ifaces.length);
+
+        for (String iface : ifaces) {
+            final long rx = getInterfaceCounter(iface, true);
+            final long tx = getInterfaceCounter(iface, false);
+            stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
+        }
+
+        return stats.build();
     }
 
-    public long getInterfaceTxCounter(String iface) {
-        return getInterfaceCounter(iface, false);
+    /** {@inheritDoc} */
+    public NetworkStats getNetworkStatsDetail() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        final File procPath = new File("/proc/uid_stat");
+        final String[] knownUids = procPath.list();
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), knownUids.length);
+
+        // TODO: kernel module will provide interface-level stats in future
+        // TODO: migrate these stats to come across netd in bulk, instead of all
+        // these individual file reads.
+        for (String uid : knownUids) {
+            final File uidPath = new File(procPath, uid);
+            final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
+            final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
+
+            final int uidInt = Integer.parseInt(uid);
+            stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+        }
+
+        return stats.build();
     }
 
     public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
@@ -782,4 +828,24 @@
     public int getInterfaceTxThrottle(String iface) {
         return getInterfaceThrottle(iface, false);
     }
+
+    /**
+     * Utility method to read a single plain-text {@link Integer} from the given
+     * {@link File}, usually from a {@code /proc/} filesystem.
+     */
+    private static int readSingleIntFromFile(File file) {
+        RandomAccessFile f = null;
+        try {
+            f = new RandomAccessFile(file, "r");
+            byte[] buffer = new byte[(int) f.length()];
+            f.readFully(buffer);
+            return Integer.parseInt(new String(buffer).trim());
+        } catch (NumberFormatException e) {
+            return -1;
+        } catch (IOException e) {
+            return -1;
+        } finally {
+            IoUtils.closeQuietly(f);
+        }
+    }
 }
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 02332b7..510ff62 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -33,6 +33,7 @@
 import android.database.ContentObserver;
 import android.net.INetworkManagementEventObserver;
 import android.net.IThrottleManager;
+import android.net.NetworkStats;
 import android.net.ThrottleManager;
 import android.os.Binder;
 import android.os.Environment;
@@ -531,8 +532,17 @@
             long incRead = 0;
             long incWrite = 0;
             try {
-                incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
-                incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
+                final NetworkStats stats = mNMService.getNetworkStatsSummary();
+                final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);
+
+                if (index != -1) {
+                    incRead = stats.rx[index] - mLastRead;
+                    incWrite = stats.tx[index] - mLastWrite;
+                } else {
+                    // missing iface, assume stats are 0
+                    Slog.w(TAG, "unable to find stats for iface " + mIface);
+                }
+
                 // handle iface resets - on some device the 3g iface comes and goes and gets
                 // totals reset to 0.  Deal with it
                 if ((incRead < 0) || (incWrite < 0)) {
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index bf1b6e6..6ef6963 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -28,6 +28,7 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -508,6 +509,7 @@
             // This access point does not require a watchdog, so queue idle on the main thread
             mHandler.idle();
         }
+        mHandler.checkWalledGarden(ssid);
     }
     
     /**
@@ -1002,6 +1004,8 @@
          * The object will be an {@link AccessPoint}.
          */
         static final int ACTION_BACKGROUND_CHECK_AP = 3;
+        /** Check whether the connection is a walled garden */
+        static final int ACTION_CHECK_WALLED_GARDEN = 4;
 
         /**
          * Go to sleep for the current network. We are conservative with making
@@ -1022,7 +1026,16 @@
         static final int MESSAGE_DISCONNECTED = 104;
         /** Performs a hard-reset on the watchdog state. */
         static final int MESSAGE_RESET = 105;
-        
+
+        /* Walled garden detection */
+        private String mLastSsid;
+        private long mLastTime;
+        private final long MIN_WALLED_GARDEN_TEST_INTERVAL = 15 * 60 * 1000; //15 minutes
+
+        void checkWalledGarden(String ssid) {
+            sendMessage(obtainMessage(ACTION_CHECK_WALLED_GARDEN, ssid));
+        }
+
         void checkAp(AccessPoint ap) {
             removeAllActions();
             sendMessage(obtainMessage(ACTION_CHECK_AP, ap));
@@ -1084,6 +1097,9 @@
                 case ACTION_BACKGROUND_CHECK_AP:
                     handleBackgroundCheckAp((AccessPoint) msg.obj);
                     break;
+                case ACTION_CHECK_WALLED_GARDEN:
+                    handleWalledGardenCheck((String) msg.obj);
+                    break;
                 case MESSAGE_SLEEP:
                     handleSleep((String) msg.obj);
                     break;
@@ -1101,6 +1117,43 @@
                     break;
             }
         }
+
+        private boolean isWalledGardenConnection() {
+            //One way to detect a walled garden is to see if multiple DNS queries
+            //resolve to the same IP address
+            try {
+                String host1 = "www.google.com";
+                String host2 = "www.android.com";
+                String address1 = InetAddress.getByName(host1).getHostAddress();
+                String address2 = InetAddress.getByName(host2).getHostAddress();
+                if (address1.equals(address2)) return true;
+            } catch (UnknownHostException e) {
+                return false;
+            }
+            return false;
+        }
+
+        private void handleWalledGardenCheck(String ssid) {
+            long currentTime = System.currentTimeMillis();
+            //Avoid a walled garden test on the same network if one was already done
+            //within MIN_WALLED_GARDEN_TEST_INTERVAL. This will handle scenarios where
+            //there are frequent network disconnections
+            if (ssid.equals(mLastSsid) &&
+                    (currentTime - mLastTime) < MIN_WALLED_GARDEN_TEST_INTERVAL) {
+                return;
+            }
+
+            mLastTime = currentTime;
+            mLastSsid = ssid;
+
+            if (isWalledGardenConnection()) {
+                Uri uri = Uri.parse("http://www.google.com");
+                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+                        Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+            }
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index cebd5e7..9fb35b9 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -49,7 +49,7 @@
     // Debug facility
     private static final String LOG_TAG = "ViewServer";
 
-    private static final String VALUE_PROTOCOL_VERSION = "3";
+    private static final String VALUE_PROTOCOL_VERSION = "4";
     private static final String VALUE_SERVER_VERSION = "4";
 
     // Protocol commands
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 6f55f46..f20d5e5 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -34,11 +34,17 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
 import android.net.ThrottleManager;
+import android.os.IBinder;
 import android.os.INetworkManagementService;
+import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
 import android.text.format.DateUtils;
+import android.util.Log;
 import android.util.TrustedTime;
 
 import java.util.Iterator;
@@ -222,6 +228,16 @@
         verify(mMockTime, mMockNMService);
     }
 
+    @Suppress
+    public void testReturnStats() throws Exception {
+        final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
+
+        // test is currently no-op, just exercises stats apis
+        Log.d(TAG, nmService.getNetworkStatsSummary().toString());
+        Log.d(TAG, nmService.getNetworkStatsDetail().toString());
+    }
+
     /**
      * Persist the given {@link ThrottleService} policy into {@link Settings}.
      */
@@ -272,12 +288,16 @@
     }
 
     /**
-     * Expect {@link NetworkManagementService#getInterfaceRxCounter} mock calls,
-     * responding with the given counter values.
+     * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
+     * calls, responding with the given counter values.
      */
     public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
-        expect(mMockNMService.getInterfaceRxCounter(isA(String.class))).andReturn(rx).atLeastOnce();
-        expect(mMockNMService.getInterfaceTxCounter(isA(String.class))).andReturn(tx).atLeastOnce();
+        // TODO: provide elapsedRealtime mock to match TimeAuthority
+        final NetworkStats.Builder stats = new NetworkStats.Builder(
+                SystemClock.elapsedRealtime(), 1);
+        stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
+
+        expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index ad4e796..ad39b27 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -38,6 +38,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.telephony.DataConnection.FailCause;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -202,6 +203,19 @@
     //       getActionIntentReconnectAlarm.
     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
 
+    // Used for debugging. Send the INTENT with an optional counter value with the number
+    // of times the setup is to fail before succeeding. If the counter isn't passed the
+    // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
+    // adb shell am broadcast \
+    //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
+    //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
+    protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
+        "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
+    protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
+    protected int mFailDataSetupCounter = 0;
+    protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
+    protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
+
     // member variables
     protected PhoneBase mPhone;
     protected Activity mActivity = Activity.NONE;
@@ -275,6 +289,7 @@
         public void onReceive(Context context, Intent intent)
         {
             String action = intent.getAction();
+            if (DBG) log("onReceive: action=" + action);
             if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 mIsScreenOn = true;
                 stopNetStatPoll();
@@ -300,10 +315,36 @@
                     // quit and won't report disconnected until next enabling.
                     mIsWifiConnected = false;
                 }
+            } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
+                mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
+                mFailDataSetupFailCause = FailCause.fromInt(
+                        intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
+                                                    FailCause.ERROR_UNSPECIFIED.getErrorCode()));
+                if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
+                        " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
             }
         }
     };
 
+    protected boolean isDataSetupCompleteOk(AsyncResult ar) {
+        if (ar.exception != null) {
+            if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
+            return false;
+        }
+        if (mFailDataSetupCounter <= 0) {
+            if (DBG) log("isDataSetupCompleteOk return true");
+            return true;
+        }
+        ar.result = mFailDataSetupFailCause;
+        if (DBG) {
+            log("isDataSetupCompleteOk return false" +
+                    " mFailDataSetupCounter=" + mFailDataSetupCounter +
+                    " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
+        }
+        mFailDataSetupCounter -= 1;
+        return false;
+    }
+
     protected void onActionIntentReconnectAlarm(Intent intent) {
         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
         if (mState == State.FAILED) {
@@ -329,6 +370,7 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
 
         mDataEnabled = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
                 Settings.Secure.MOBILE_DATA, 1) == 1;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 4b185a0..2f783e8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -54,9 +54,6 @@
 
     private CDMAPhone mCdmaPhone;
 
-    //useful for debugging
-    boolean mFailNextConnect = false;
-
     /** The DataConnection being setup */
     private CdmaDataConnection mPendingDataConnection;
 
@@ -660,7 +657,7 @@
             reason = (String) ar.userObj;
         }
 
-        if (ar.exception == null) {
+        if (isDataSetupCompleteOk(ar)) {
             // Everything is setup
             notifyDefaultData(reason);
         } else {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index a1b4376..69a8153 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -104,9 +104,6 @@
     /** Delay between APN attempts */
     protected static final int APN_DELAY_MILLIS = 5000;
 
-    //useful for debugging
-    boolean mFailNextConnect = false;
-
     //***** Constants
 
     private static final int POLL_PDP_MILLIS = 5 * 1000;
@@ -1574,13 +1571,14 @@
         } else {
             throw new RuntimeException("onDataSetupComplete: No apnContext");
         }
-        DataConnectionAc dcac = apnContext.getDataConnectionAc();
-        if (dcac == null) {
-            throw new RuntimeException("onDataSetupCompete: No dcac");
-        }
-        DataConnection dc = apnContext.getDataConnection();
 
-        if (ar.exception == null) {
+        if (isDataSetupCompleteOk(ar)) {
+            DataConnectionAc dcac = apnContext.getDataConnectionAc();
+            if (dcac == null) {
+                throw new RuntimeException("onDataSetupCompete: No dcac");
+            }
+            DataConnection dc = apnContext.getDataConnection();
+
             if (DBG) {
                 log(String.format("onDataSetupComplete: success apn=%s",
                     apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
@@ -1612,16 +1610,11 @@
             }
             notifyDefaultData(apnContext);
         } else {
-            int refCount = releaseApnContext(apnContext, false);
-            if (DBG) {
-                log(String.format("onDataSetupComplete: error apn=%s",
-                    apnContext.getWaitingApns().get(0).apn) + " refCount=" + refCount);
-            }
+            String apnString;
+            DataConnection.FailCause cause;
 
-            GsmDataConnection.FailCause cause;
-            cause = (GsmDataConnection.FailCause) (ar.result);
+            cause = (DataConnection.FailCause) (ar.result);
             if (DBG) {
-                String apnString;
                 try {
                     apnString = apnContext.getWaitingApns().get(0).apn;
                 } catch (Exception e) {
@@ -1667,6 +1660,11 @@
                 sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
                         APN_DELAY_MILLIS);
             }
+
+            int refCount = releaseApnContext(apnContext, false);
+            if (DBG) {
+                log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+            }
         }
     }