Merge "Fix issue 381905: BassBoostTest CTS tests fail..." into ics-mr0
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4225393..7d683a5 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -990,8 +990,8 @@
                 mBound = false;
                 mContext.unbindService(this);
             }
-            mSyncWakeLock.setWorkSource(null);
             mSyncWakeLock.release();
+            mSyncWakeLock.setWorkSource(null);
         }
 
         @Override
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e344197..438c536 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1095,6 +1095,16 @@
         }
     }
 
+    private static long computeWakeLock(Timer timer, long batteryRealtime, int which) {
+        if (timer != null) {
+            // Convert from microseconds to milliseconds with rounding
+            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
+            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+            return totalTimeMillis;
+        }
+        return 0;
+    }
+
     /**
      *
      * @param sb a StringBuilder object.
@@ -1109,9 +1119,7 @@
             long batteryRealtime, String name, int which, String linePrefix) {
         
         if (timer != null) {
-            // Convert from microseconds to milliseconds with rounding
-            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
-            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+            long totalTimeMillis = computeWakeLock(timer, batteryRealtime, which);
             
             int count = timer.getCountLocked(which);
             if (totalTimeMillis != 0) {
@@ -1735,6 +1743,8 @@
 
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
+                long totalFull = 0, totalPartial = 0, totalWindow = 0;
+                int count = 0;
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
                     : wakelocks.entrySet()) {
                     Uid.Wakelock wl = ent.getValue();
@@ -1754,6 +1764,44 @@
                         // Only print out wake locks that were held
                         pw.println(sb.toString());
                         uidActivity = true;
+                        count++;
+                    }
+                    totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
+                            batteryRealtime, which);
+                    totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
+                            batteryRealtime, which);
+                    totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
+                            batteryRealtime, which);
+                }
+                if (count > 1) {
+                    if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
+                        sb.setLength(0);
+                        sb.append(prefix);
+                        sb.append("    TOTAL wake: ");
+                        boolean needComma = false;
+                        if (totalFull != 0) {
+                            needComma = true;
+                            formatTimeMs(sb, totalFull);
+                            sb.append("full");
+                        }
+                        if (totalPartial != 0) {
+                            if (needComma) {
+                                sb.append(", ");
+                            }
+                            needComma = true;
+                            formatTimeMs(sb, totalPartial);
+                            sb.append("partial");
+                        }
+                        if (totalWindow != 0) {
+                            if (needComma) {
+                                sb.append(", ");
+                            }
+                            needComma = true;
+                            formatTimeMs(sb, totalWindow);
+                            sb.append("window");
+                        }
+                        sb.append(" realtime");
+                        pw.println(sb.toString());
                     }
                 }
             }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e2a2566..3e96c81 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -98,6 +98,10 @@
     // in to one common name.
     private static final int MAX_WAKELOCKS_PER_UID = 30;
 
+    // The system process gets more.  It is special.  Oh so special.
+    // With, you know, special needs.  Like this.
+    private static final int MAX_WAKELOCKS_PER_UID_IN_SYSTEM = 50;
+
     private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
 
     private static int sNumSpeedSteps;
@@ -2895,12 +2899,10 @@
                 String wakelockName = in.readString();
                 Uid.Wakelock wakelock = new Wakelock();
                 wakelock.readFromParcelLocked(unpluggables, in);
-                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
-                    // We will just drop some random set of wakelocks if
-                    // the previous run of the system was an older version
-                    // that didn't impose a limit.
-                    mWakelockStats.put(wakelockName, wakelock);
-                }
+                // We will just drop some random set of wakelocks if
+                // the previous run of the system was an older version
+                // that didn't impose a limit.
+                mWakelockStats.put(wakelockName, wakelock);
             }
 
             int numSensors = in.readInt();
@@ -3904,7 +3906,9 @@
         public StopwatchTimer getWakeTimerLocked(String name, int type) {
             Wakelock wl = mWakelockStats.get(name);
             if (wl == null) {
-                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
+                final int N = mWakelockStats.size();
+                if (N > MAX_WAKELOCKS_PER_UID && (mUid != Process.SYSTEM_UID
+                        || N > MAX_WAKELOCKS_PER_UID_IN_SYSTEM)) {
                     name = BATCHED_WAKELOCK_NAME;
                     wl = mWakelockStats.get(name);
                 }
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 2b94b28..9089937 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.4,90.6" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.2,90.8" />
 
 <table>
 <tr>
@@ -66,14 +66,14 @@
 </tr>
 <tr>
 <td>1.1</th>
-<td>9.4%</td>
+<td>9.2%</td>
 </tr>
 <tr>
 <td>2.0</th>
-<td>90.6%</td>
+<td>90.8%</td>
 </tr>
 </table>
 
-<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on October 3, 2011</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 51cbae3..135c6f2 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="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.0,1.8,13.3,51.2,0.6,30.7,0.2,0.7,0.5&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.1,1.4,11.7,45.3,0.5,38.2,0.2,0.9,0.7&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -61,21 +61,21 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>1.0%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.8%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>13.3%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>51.2%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>1.1%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>11.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>45.3%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
-                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.6%</td></tr>
+                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.5%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
-      Android 2.3.4</a></td><!-- Gingerbread -->                                       <td>10</td><td>30.7%</td></tr>
+      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>38.2%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
                                                    <td rowspan="3">Honeycomb</td>      <td>11</td><td>0.2%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>0.7%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>0.5%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>0.9%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>0.7%</td></tr> 
 </table>
 
-<p><em>Data collected during a 14-day period ending on September 2, 2011</em></p>
+<p><em>Data collected during a 14-day period ending on October 3, 2011</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -104,9 +104,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%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C1%3A%7C2011%7C%7C%7C%7C%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.8,99.7,99.6,99.6,99.5,99.4,99.3,99.2,99.0,98.8,98.7,98.6|96.7,96.8,97.0,97.1,97.3,97.5,97.5,97.5,97.7,97.6,97.5,97.5,97.5|91.5,92.0,93.5,93.9,94.3,94.8,95.0,95.2,95.5,95.5,95.5,95.6,95.8|61.5,63.0,66.4,68.0,69.8,71.5,73.9,75.4,77.6,79.0,80.2,81.1,82.4|1.1,1.7,2.5,3.1,4.0,6.1,9.5,13.6,17.8,20.6,24.3,27.5,31.1|0.0,1.0,1.7,2.2,3.0,5.1,8.4,12.6,16.8,20.0,23.7,26.9,30.5&chm=b,c3df9b,0,1,0|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|tAndroid 2.3.3,131d02,5,7,15,,t::-5|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%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C1%3A%7C2011%7C%7C%7C%7C%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:99.7,99.6,99.6,99.5,99.4,99.3,99.2,99.0,98.8,98.7,98.5,98.5,98.2|97.0,97.1,97.3,97.5,97.5,97.5,97.7,97.6,97.5,97.5,97.5,97.5,97.1|93.5,93.9,94.3,94.8,95.0,95.2,95.5,95.5,95.5,95.6,95.7,95.8,95.6|66.4,68.0,69.8,71.5,73.9,75.4,77.6,79.0,80.2,81.1,82.4,83.3,83.8|2.5,3.1,4.0,6.1,9.5,13.6,17.8,20.6,24.3,27.5,31.2,34.7,38.3|1.7,2.2,3.0,5.1,8.4,12.6,16.8,20.0,23.7,26.9,30.6,34.1,37.8&chm=b,c3df9b,0,1,0|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|tAndroid 2.3.3,131d02,5,5,15,,t::-5|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 a 14-day period ending on September 2, 2011</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on October 3, 2011</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index 77fd2d2..67b47d0 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -59,7 +59,8 @@
 
 <div class="dashboard-panel">
 
-<img alt="" width="400" height="250" src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi| Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi&chd=t%3A1.5, 3.2,74,0.9,16.9,3.5" />
+<img alt="" width="400" height="250"
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A2.6,0.1,3.0,71.9,0.9,17.6,2.7,1.2" />
 
 <table>
 <tr>
@@ -70,31 +71,31 @@
 <th scope="col">xhdpi</th>
 </tr>
 <tr><th scope="row">small</th> 
-<td></td>     <!-- small/ldpi -->
+<td>1.2%</td>     <!-- small/ldpi -->
 <td></td>     <!-- small/mdpi -->
-<td>3.5%</td> <!-- small/hdpi -->
+<td>2.7%</td> <!-- small/hdpi -->
 <td></td>     <!-- small/xhdpi -->
 </tr> 
 <tr><th scope="row">normal</th> 
 <td>0.9%</td>  <!-- normal/ldpi -->
-<td>16.9%</td> <!-- normal/mdpi -->
-<td>74%</td> <!-- normal/hdpi -->
+<td>17.6%</td> <!-- normal/mdpi -->
+<td>71.9%</td> <!-- normal/hdpi -->
 <td></td>      <!-- normal/xhdpi -->
 </tr> 
 <tr><th scope="row">large</th> 
-<td></td>     <!-- large/ldpi -->
-<td>3.2%</td> <!-- large/mdpi -->
+<td>0.1%</td>     <!-- large/ldpi -->
+<td>3.0%</td> <!-- large/mdpi -->
 <td></td>     <!-- large/hdpi -->
 <td></td>     <!-- large/xhdpi -->
 </tr> 
 <tr><th scope="row">xlarge</th> 
 <td></td>     <!-- xlarge/ldpi -->
-<td>1.5%</td> <!-- xlarge/mdpi -->
+<td>2.6%</td> <!-- xlarge/mdpi -->
 <td></td>     <!-- xlarge/hdpi -->
 <td></td>     <!-- xlarge/xhdpi -->
 </tr> 
 </table>
 
-<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on October 3, 2011</em></p>
 </div>
 
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index da40d52..9031987 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -158,7 +158,7 @@
 <p>Adding a new raw contact for the profile requires the {@link
 android.Manifest.permission#WRITE_PROFILE} permission. Likewise, in order to read from the profile
 table, you must request the {@link android.Manifest.permission#READ_PROFILE} permission. However,
-most apps should need to read the user profile, even when contributing data to the
+most apps should not need to read the user profile, even when contributing data to the
 profile. Reading the user profile is a sensitive permission and you should expect users to be
 skeptical of apps that request it.</p>
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 0bee0f1..98fa171 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -409,9 +409,9 @@
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
     int err = mSurfaceTexture->disconnect(api);
     if (!err) {
-        freeAllBuffers();
         mReqFormat = 0;
         mReqWidth = 0;
         mReqHeight = 0;
diff --git a/packages/SystemUI/res/anim/recent_appear.xml b/packages/SystemUI/res/anim/recent_appear.xml
index 20fe052..4400d9d 100644
--- a/packages/SystemUI/res/anim/recent_appear.xml
+++ b/packages/SystemUI/res/anim/recent_appear.xml
@@ -16,5 +16,5 @@
 
 <alpha xmlns:android="http://schemas.android.com/apk/res/android"
     android:fromAlpha="0.0" android:toAlpha="1.0"
-    android:duration="@android:integer/config_mediumAnimTime"
+    android:duration="@android:integer/config_shortAnimTime"
     />
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 83c4faf..2d76455 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -39,11 +39,11 @@
             android:layout_marginTop="@dimen/status_bar_recents_thumbnail_top_margin"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
             android:background="@drawable/recents_thumbnail_bg"
-            android:foreground="@drawable/recents_thumbnail_fg">
+            android:foreground="@drawable/recents_thumbnail_fg"
+            android:visibility="invisible">
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="@dimen/status_bar_recents_thumbnail_width"
                 android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-                android:visibility="invisible"
             />
         </FrameLayout>
 
@@ -58,7 +58,6 @@
             android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
             android:scaleType="centerInside"
             android:adjustViewBounds="true"
-            android:visibility="invisible"
         />
 
         <TextView android:id="@+id/app_label"
@@ -74,7 +73,6 @@
             android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
-            android:visibility="invisible"
             android:textColor="@color/status_bar_recents_app_label_color"
         />
 
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index 3d8b9d6..b653fcd 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -52,11 +52,11 @@
             android:layout_toRightOf="@id/app_label"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
             android:background="@drawable/recents_thumbnail_bg"
-            android:foreground="@drawable/recents_thumbnail_fg">
+            android:foreground="@drawable/recents_thumbnail_fg"
+            android:visibility="invisible">
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="@dimen/status_bar_recents_thumbnail_width"
                 android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-                android:visibility="invisible"
             />
         </FrameLayout>
         <View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index e633671..18a31f7 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -31,11 +31,11 @@
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
         android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_fg">
+        android:foreground="@drawable/recents_thumbnail_fg"
+        android:visibility="invisible">
         <ImageView android:id="@+id/app_thumbnail_image"
             android:layout_width="@dimen/status_bar_recents_thumbnail_width"
             android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-            android:visibility="invisible"
         />
         <ImageView android:id="@+id/app_icon"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 47aa849..dcda9c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -86,8 +86,8 @@
         mIconDpi = isTablet ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
 
         // Render the default thumbnail background
-        int width = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_width);
-        int height = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_height);
+        int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+        int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
         int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
 
         mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@@ -106,6 +106,10 @@
         mRecentsPanel = recentsPanel;
     }
 
+    public Bitmap getDefaultThumbnail() {
+        return mDefaultThumbnailBackground;
+    }
+
     // Create an TaskDescription, returning null if the title or icon is null, or if it's the
     // home activity
     TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -278,7 +282,7 @@
                             TaskDescription td = descriptions.get(i);
                             loadThumbnail(td);
                             long now = SystemClock.uptimeMillis();
-                            nextTime += 150;
+                            nextTime += 0;
                             if (nextTime > now) {
                                 try {
                                     Thread.sleep(nextTime-now);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index bd1fcfc..343b33514 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -37,6 +37,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
@@ -57,8 +58,8 @@
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
-public class RecentsPanelView extends RelativeLayout
-        implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
+public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
+        StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
     static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
     private Context mContext;
@@ -74,6 +75,7 @@
 
     private RecentTasksLoader mRecentTasksLoader;
     private ArrayList<TaskDescription> mRecentTaskDescriptions;
+    private boolean mRecentTasksDirty = true;
     private TaskDescriptionAdapter mListAdapter;
     private int mThumbnailWidth;
 
@@ -94,6 +96,7 @@
     /* package */ final static class ViewHolder {
         View thumbnailView;
         ImageView thumbnailViewImage;
+        Bitmap thumbnailViewImageBitmap;
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
@@ -127,6 +130,10 @@
                 holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
                 holder.thumbnailViewImage = (ImageView) convertView.findViewById(
                         R.id.app_thumbnail_image);
+                // If we set the default thumbnail now, we avoid an onLayout when we update
+                // the thumbnail later (if they both have the same dimensions)
+                updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
+
                 holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
                 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
                 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -139,12 +146,15 @@
             // index is reverse since most recent appears at the bottom...
             final int index = mRecentTaskDescriptions.size() - position - 1;
 
-            final TaskDescription taskDescription = mRecentTaskDescriptions.get(index);
-            applyTaskDescription(holder, taskDescription, false);
+            final TaskDescription td = mRecentTaskDescriptions.get(index);
+            holder.iconView.setImageDrawable(td.getIcon());
+            holder.labelView.setText(td.getLabel());
+            holder.thumbnailView.setContentDescription(td.getLabel());
+            updateThumbnail(holder, td.getThumbnail(), true, false);
 
-            holder.thumbnailView.setTag(taskDescription);
+            holder.thumbnailView.setTag(td);
             holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
-            holder.taskDescription = taskDescription;
+            holder.taskDescription = td;
 
             return convertView;
         }
@@ -193,6 +203,7 @@
             }
         } else {
             mRecentTasksLoader.cancelLoadingThumbnails();
+            mRecentTasksDirty = true;
         }
         if (animate) {
             if (mShowing != show) {
@@ -250,9 +261,7 @@
             createCustomAnimations(transitioner);
         } else {
             ((ViewGroup)mRecentsContainer).setLayoutTransition(null);
-            // Clear memory used by screenshots
-            mRecentTaskDescriptions.clear();
-            mListAdapter.notifyDataSetInvalidated();
+            clearRecentTasksList();
         }
     }
 
@@ -374,47 +383,33 @@
         }
     }
 
-
-    void applyTaskDescription(ViewHolder h, TaskDescription td, boolean anim) {
-        h.iconView.setImageDrawable(td.getIcon());
-        if (h.iconView.getVisibility() != View.VISIBLE) {
-            if (anim) {
-                h.iconView.setAnimation(AnimationUtils.loadAnimation(
-                        mContext, R.anim.recent_appear));
-            }
-            h.iconView.setVisibility(View.VISIBLE);
-        }
-        h.labelView.setText(td.getLabel());
-        h.thumbnailView.setContentDescription(td.getLabel());
-        if (h.labelView.getVisibility() != View.VISIBLE) {
-            if (anim) {
-                h.labelView.setAnimation(AnimationUtils.loadAnimation(
-                        mContext, R.anim.recent_appear));
-            }
-            h.labelView.setVisibility(View.VISIBLE);
-        }
-        Bitmap thumbnail = td.getThumbnail();
+    private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
         if (thumbnail != null) {
             // Should remove the default image in the frame
             // that this now covers, to improve scrolling speed.
             // That can't be done until the anim is complete though.
             h.thumbnailViewImage.setImageBitmap(thumbnail);
-            // scale to fill up the full width
-            Matrix scaleMatrix = new Matrix();
-            float scale = mThumbnailWidth / (float) thumbnail.getWidth();
-            scaleMatrix.setScale(scale, scale);
-            h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
-            h.thumbnailViewImage.setImageMatrix(scaleMatrix);
-            if (h.thumbnailViewImage.getVisibility() != View.VISIBLE) {
-                if (anim) {
-                    h.thumbnailViewImage.setAnimation(
-                            AnimationUtils.loadAnimation(
-                                    mContext, R.anim.recent_appear));
-                }
-                h.thumbnailViewImage.setVisibility(View.VISIBLE);
+
+            // scale the image to fill the full width of the ImageView. do this only if
+            // we haven't set a bitmap before, or if the bitmap size has changed
+            if (h.thumbnailViewImageBitmap == null ||
+                h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
+                h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+                Matrix scaleMatrix = new Matrix();
+                float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+                scaleMatrix.setScale(scale, scale);
+                h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
+                h.thumbnailViewImage.setImageMatrix(scaleMatrix);
             }
+            if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
+                if (anim) {
+                    h.thumbnailView.setAnimation(
+                            AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
+                }
+                h.thumbnailView.setVisibility(View.VISIBLE);
+            }
+            h.thumbnailViewImageBitmap = thumbnail;
         }
-        //h.descriptionView.setText(ad.description);
     }
 
     void onTaskThumbnailLoaded(TaskDescription ad) {
@@ -432,7 +427,11 @@
                     if (v.getTag() instanceof ViewHolder) {
                         ViewHolder h = (ViewHolder)v.getTag();
                         if (h.taskDescription == ad) {
-                            applyTaskDescription(h, ad, true);
+                            // only fade in the thumbnail if recents is already visible-- we
+                            // show it immediately otherwise
+                            boolean animateShow = mShowing &&
+                                mRecentsGlowView.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
+                            updateThumbnail(h, ad.getThumbnail(), true, animateShow);
                         }
                     }
                 }
@@ -440,14 +439,55 @@
         }
     }
 
-    private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
-        if (recentTasksList != null) {
-            mRecentTaskDescriptions = recentTasksList;
-        } else {
-            mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
+    // additional optimization when we have sofware system buttons - start loading the recent
+    // tasks on touch down
+    @Override
+    public boolean onTouch(View v, MotionEvent ev) {
+        if (!mShowing) {
+            int action = ev.getAction() & MotionEvent.ACTION_MASK;
+            if (action == MotionEvent.ACTION_DOWN) {
+                // If we set our visibility to INVISIBLE here, we avoid an extra call to onLayout
+                // later when we become visible
+                setVisibility(INVISIBLE);
+                refreshRecentTasksList();
+            } else if (action == MotionEvent.ACTION_CANCEL) {
+                setVisibility(GONE);
+                clearRecentTasksList();
+            } else if (action == MotionEvent.ACTION_UP) {
+                if (!v.isPressed()) {
+                    setVisibility(GONE);
+                    clearRecentTasksList();
+                }
+            }
         }
-        mListAdapter.notifyDataSetInvalidated();
-        updateUiElements(getResources().getConfiguration());
+        return false;
+    }
+
+    public void clearRecentTasksList() {
+        // Clear memory used by screenshots
+        if (mRecentTaskDescriptions != null) {
+            mRecentTasksLoader.cancelLoadingThumbnails();
+            mRecentTaskDescriptions.clear();
+            mListAdapter.notifyDataSetInvalidated();
+            mRecentTasksDirty = true;
+        }
+    }
+
+    public void refreshRecentTasksList() {
+        refreshRecentTasksList(null);
+    }
+
+    private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
+        if (mRecentTasksDirty) {
+            if (recentTasksList != null) {
+                mRecentTaskDescriptions = recentTasksList;
+            } else {
+                mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
+            }
+            mListAdapter.notifyDataSetInvalidated();
+            updateUiElements(getResources().getConfiguration());
+            mRecentTasksDirty = false;
+        }
     }
 
     public ArrayList<TaskDescription> getRecentTasksList() {
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 b724552..352d4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -113,6 +113,8 @@
     // will likely move to a resource or other tunable param at some point
     private static final int INTRUDER_ALERT_DECAY_MS = 10000;
 
+    private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
+
     // fling gesture tuning parameters, scaled to display density
     private float mSelfExpandVelocityPx; // classic value: 2000px/s
     private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -435,13 +437,18 @@
         }
     };
 
+    private void prepareNavigationBarView() {
+        mNavigationBarView.reorient();
+
+        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
+        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+    }
+
     // For small-screen devices (read: phones) that lack hardware navigation buttons
     private void addNavigationBar() {
         if (mNavigationBarView == null) return;
 
-        mNavigationBarView.reorient();
-
-        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
+        prepareNavigationBarView();
 
         WindowManagerImpl.getDefault().addView(
                 mNavigationBarView, getNavigationBarLayoutParams());
@@ -450,9 +457,7 @@
     private void repositionNavigationBar() {
         if (mNavigationBarView == null) return;
 
-        mNavigationBarView.reorient();
-
-        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
+        prepareNavigationBarView();
 
         WindowManagerImpl.getDefault().updateViewLayout(
                 mNavigationBarView, getNavigationBarLayoutParams());
@@ -695,6 +700,10 @@
 
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+
+            if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 && !mAnimating) {
+                animateCollapse();
+            }
         }
 
         setAreThereNotifications();
@@ -2007,8 +2016,8 @@
     }
 
     public void toggleRecentApps() {
-        int msg = (mRecentsPanel.getVisibility() == View.GONE)
-                ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+        int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
+                ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
         mHandler.removeMessages(msg);
         mHandler.sendEmptyMessage(msg);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index f0a10f3..de8226b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -587,6 +587,7 @@
 
         // Add the windows
         addPanelWindows();
+        mRecentButton.setOnTouchListener(mRecentsPanel);
 
         mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
         mPile.removeAllViews();
@@ -1805,8 +1806,8 @@
     }
 
     public void toggleRecentApps() {
-        int msg = (mRecentsPanel.getVisibility() == View.GONE)
-                ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+        int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
+                ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
         mHandler.removeMessages(msg);
         mHandler.sendEmptyMessage(msg);
     }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index f1b8bae..47644de 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -44,6 +44,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPowerManager;
@@ -1656,8 +1657,18 @@
         }
     }
 
+    private boolean isExtStorageEncrypted() {
+        String state = SystemProperties.get("vold.decrypt");
+        return !"".equals(state);
+    }
+
     void wipeDataLocked(int flags) {
-        if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
+        // If the SD card is encrypted and non-removable, we have to force a wipe.
+        boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
+        boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
+
+        // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
+        if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
             Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
             intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
             mWakeLock.acquire(10000);