Merge "Fix bug 5201420 - Appease the monkeys"
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 31c5f8d..d2d66b6 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -351,7 +351,7 @@
     @Override
     public void start() {
         if (DBG) {
-            Log.d("ObjectAnimator", "Anim target, duration" + mTarget + ", " + getDuration());
+            Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
             for (int i = 0; i < mValues.length; ++i) {
                 PropertyValuesHolder pvh = mValues[i];
                 ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 316c474..48d0203 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -127,7 +127,7 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-            if (!device.equals(mDevice)) return;
+            if (device == null || !device.equals(mDevice)) return;
 
             if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 98afdb8..b0c0a0b 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -59,7 +59,9 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
+            if (device == null) {
+                return;
+            }
             if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
                 if (mProfile == HFP && (newState == BluetoothProfile.STATE_CONNECTED ||
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7db1b32..7ca8174 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1599,6 +1599,11 @@
                 }
             }
         } else {
+            // If we're not drawing, then we don't need to draw the transitions, either
+            if (mPendingTransitions != null) {
+                mPendingTransitions.clear();
+            }
+
             // We were supposed to report when we are done drawing. Since we canceled the
             // draw, remember it here.
             if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b2c3051..e033d2d 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -933,9 +933,32 @@
         // onDraw will translate the canvas so we draw starting at 0,0
         int right = w - mPaddingRight - mPaddingLeft;
         int bottom = h - mPaddingBottom - mPaddingTop;
+        int top = 0;
+        int left = 0;
 
         if (mIndeterminateDrawable != null) {
-            mIndeterminateDrawable.setBounds(0, 0, right, bottom);
+            if (mOnlyIndeterminate) {
+                // Maintain aspect ratio. Certain kinds of animated drawables
+                // get very confused otherwise.
+                final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
+                final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
+                final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
+                final float boundAspect = (float) w / h;
+                if (intrinsicAspect != boundAspect) {
+                    if (boundAspect > intrinsicAspect) {
+                        // New width is larger. Make it smaller to match height.
+                        final int width = (int) (h * intrinsicAspect);
+                        left = (w - width) / 2;
+                        right = left + width;
+                    } else {
+                        // New height is larger. Make it smaller to match width.
+                        final int height = (int) (w * (1 / intrinsicAspect));
+                        top = (h - height) / 2;
+                        bottom = top + height;
+                    }
+                }
+            }
+            mIndeterminateDrawable.setBounds(left, top, right, bottom);
         }
         
         if (mProgressDrawable != null) {
diff --git a/core/java/com/android/internal/widget/LockScreenWidgetInterface.java b/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
index 6dfcc75..8f80cfc 100644
--- a/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
+++ b/core/java/com/android/internal/widget/LockScreenWidgetInterface.java
@@ -20,4 +20,6 @@
 
     public void setCallback(LockScreenWidgetCallback callback);
 
+    public boolean providesClock();
+
 }
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index 1c47ca88a..29ad15b 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -381,4 +381,8 @@
         mWidgetCallbacks = callback;
     }
 
+    public boolean providesClock() {
+        return false;
+    }
+
 }
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 362ee16..2b94b28 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%3A8.9,91" />
+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" />
 
 <table>
 <tr>
@@ -66,14 +66,14 @@
 </tr>
 <tr>
 <td>1.1</th>
-<td>9%</td>
+<td>9.4%</td>
 </tr>
 <tr>
 <td>2.0</th>
-<td>91%</td>
+<td>90.6%</td>
 </tr>
 </table>
 
-<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index d9adb36..51cbae3 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,27 +52,30 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.4,2.2,17.5,59.4,1.0,17.6,0.4,0.5&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3%20-%202.3.2|Android%202.3.3%20-%202.3.4|Android%203.0|Android%203.1&chco=c4df9b,6fad0c" />
+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" />
 
 <table>
 <tr>
   <th>Platform</th>
+  <th>Codename</th>
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>1.4%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>2.2%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>17.5%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>59.4%</td></tr>
-<tr><td>Android 2.3 -<br/>
-        Android 2.3.2</td><td>9</td><td>1%</td></tr>
-<tr><td>Android 2.3.3 -<br/>
-        Android 2.3.4</td><td>10</td><td>17.6%</td></tr>
-<tr><td>Android 3.0</td><td>11</td><td>0.4%</td></tr>
-<tr><td>Android 3.1</td><td>12</td><td>0.5%</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.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-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>
+<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>
+<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> 
 </table>
 
-<p><em>Data collected during a 14-day period ending on July 5, 2011</em></p>
+<p><em>Data collected during a 14-day period ending on September 2, 2011</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -101,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%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/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.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6,99.5,99.4,99.3,99.2|95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3,97.5,97.5,97.5,97.7|87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3,94.8,95.0,95.2,95.5|51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8,71.5,73.9,75.4,77.6|0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0,6.1,9.5,13.6,17.8|0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0,5.1,8.4,12.6,16.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|tAndroid2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|tAndroid2.3.3,131d02,5,11,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android2.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%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" />
 
-<p><em>Last historical dataset collected during a 14-day period ending on July 5, 2011</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on September 2, 2011</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index e61e799..77fd2d2 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -59,8 +59,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=Xlarge%20/%20mdpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi&chd=t%3A0.9,2.8,75,1.0,17,3.3" />
+<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" />
 
 <table>
 <tr>
@@ -73,29 +72,29 @@
 <tr><th scope="row">small</th> 
 <td></td>     <!-- small/ldpi -->
 <td></td>     <!-- small/mdpi -->
-<td>3.3%</td> <!-- small/hdpi -->
+<td>3.5%</td> <!-- small/hdpi -->
 <td></td>     <!-- small/xhdpi -->
 </tr> 
 <tr><th scope="row">normal</th> 
-<td>1%</td>  <!-- normal/ldpi -->
-<td>17%</td> <!-- normal/mdpi -->
-<td>75%</td> <!-- normal/hdpi -->
+<td>0.9%</td>  <!-- normal/ldpi -->
+<td>16.9%</td> <!-- normal/mdpi -->
+<td>74%</td> <!-- normal/hdpi -->
 <td></td>      <!-- normal/xhdpi -->
 </tr> 
 <tr><th scope="row">large</th> 
 <td></td>     <!-- large/ldpi -->
-<td>2.8%</td> <!-- large/mdpi -->
+<td>3.2%</td> <!-- large/mdpi -->
 <td></td>     <!-- large/hdpi -->
 <td></td>     <!-- large/xhdpi -->
 </tr> 
 <tr><th scope="row">xlarge</th> 
 <td></td>     <!-- xlarge/ldpi -->
-<td>0.9%</td> <!-- xlarge/mdpi -->
+<td>1.5%</td> <!-- xlarge/mdpi -->
 <td></td>     <!-- xlarge/hdpi -->
 <td></td>     <!-- xlarge/xhdpi -->
 </tr> 
 </table>
 
-<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on September 2, 2011</em></p>
 </div>
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 4f74b37..e987679 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -83,7 +83,7 @@
         float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
         float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
-        canvas.rotate(st.mCurrentDegrees, px, py);
+        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
 
         st.mDrawable.draw(canvas);
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index cd15718..d233f92 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2295,7 +2295,13 @@
                 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                                BluetoothProfile.STATE_DISCONNECTED);
                 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (btDevice == null) {
+                    return;
+                }
                 String address = btDevice.getAddress();
+                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+                    address = "";
+                }
                 boolean isConnected =
                     (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
                      mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
@@ -2331,24 +2337,30 @@
                 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                                BluetoothProfile.STATE_DISCONNECTED);
                 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                 String address = null;
-                if (btDevice != null) {
-                    address = btDevice.getAddress();
-                    BluetoothClass btClass = btDevice.getBluetoothClass();
-                    if (btClass != null) {
-                        switch (btClass.getDeviceClass()) {
-                        case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
-                        case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-                            break;
-                        case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
-                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                            break;
-                        }
+
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (btDevice == null) {
+                    return;
+                }
+
+                address = btDevice.getAddress();
+                BluetoothClass btClass = btDevice.getBluetoothClass();
+                if (btClass != null) {
+                    switch (btClass.getDeviceClass()) {
+                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+                        break;
+                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                        break;
                     }
                 }
 
+                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+                    address = "";
+                }
                 boolean isConnected = (mConnectedDevices.containsKey(device) &&
                                        mConnectedDevices.get(device).equals(address));
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 853a5f6..7b14c18 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -511,9 +511,15 @@
                                                const char *device_address)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    const char *address = "";
+
     if (aps == 0) return PERMISSION_DENIED;
 
-    return aps->setDeviceConnectionState(device, state, device_address);
+    if (device_address != NULL) {
+        address = device_address;
+    }
+
+    return aps->setDeviceConnectionState(device, state, address);
 }
 
 audio_policy_dev_state_t AudioSystem::getDeviceConnectionState(audio_devices_t device,
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 1ebdfa1..0354fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -165,11 +165,13 @@
             case MotionEvent.ACTION_DOWN:
                 mDragging = false;
                 mCurrView = mCallback.getChildAtPosition(ev);
-                mCurrAnimView = mCallback.getChildContentView(mCurrView);
-                mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
                 mVelocityTracker.clear();
-                mVelocityTracker.addMovement(ev);
-                mInitialTouchPos = getPos(ev);
+                if (mCurrView != null) {
+                    mCurrAnimView = mCallback.getChildContentView(mCurrView);
+                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
+                    mVelocityTracker.addMovement(ev);
+                    mInitialTouchPos = getPos(ev);
+                }
                 break;
             case MotionEvent.ACTION_MOVE:
                 if (mCurrView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 85cde7c..5c1bbf0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -26,6 +26,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.View.OnClickListener;
 import android.widget.HorizontalScrollView;
 import android.widget.LinearLayout;
 
@@ -75,13 +76,23 @@
                 mPerformanceHelper.addViewCallback(view);
             }
 
-            final View thumbnail = view.findViewById(R.id.app_thumbnail);
-            // thumbnail is set to clickable in the layout file
-            thumbnail.setOnClickListener(new OnClickListener() {
+            view.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.dismiss();
+                }
+            });
+
+            OnClickListener launchAppListener = new OnClickListener() {
                 public void onClick(View v) {
                     mCallback.handleOnClick(view);
                 }
-            });
+            };
+            final View thumbnail = view.findViewById(R.id.app_thumbnail);
+            thumbnail.setClickable(true);
+            thumbnail.setOnClickListener(launchAppListener);
+            final View appTitle = view.findViewById(R.id.app_label);
+            appTitle.setClickable(true);
+            appTitle.setOnClickListener(launchAppListener);
             mLinearLayout.addView(view);
         }
         // Scroll to end after layout.
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index d7bb3c4..fc33931 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -84,7 +84,7 @@
     private View mRecentsScrim;
     private View mRecentsGlowView;
     private ViewGroup mRecentsContainer;
-    private Bitmap mAppThumbnailBackground;
+    private Bitmap mDefaultThumbnailBackground;
 
     private boolean mShowing;
     private Choreographer mChoreo;
@@ -125,7 +125,7 @@
         }
 
         public void setThumbnail(Bitmap thumbnail) {
-            mThumbnail = compositeBitmap(mAppThumbnailBackground, thumbnail);
+            mThumbnail = compositeBitmap(mDefaultThumbnailBackground, thumbnail);
         }
 
         public Bitmap getThumbnail() {
@@ -339,8 +339,8 @@
         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 color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
-        mAppThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas(mAppThumbnailBackground);
+        mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(mDefaultThumbnailBackground);
         c.drawColor(color);
     }
 
@@ -517,7 +517,7 @@
         synchronized (ad) {
             ad.mLabel = label;
             ad.mIcon = icon;
-            ad.setThumbnail(thumbs != null ? thumbs.mainThumbnail : null);
+            ad.setThumbnail(thumbs != null ? thumbs.mainThumbnail : mDefaultThumbnailBackground);
         }
     }
 
@@ -577,7 +577,7 @@
         }
         mActivityDescriptions = getRecentTasks();
         for (ActivityDescription ad : mActivityDescriptions) {
-            ad.setThumbnail(mAppThumbnailBackground);
+            ad.setThumbnail(mDefaultThumbnailBackground);
         }
         mListAdapter.notifyDataSetInvalidated();
         if (mActivityDescriptions.size() > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 4a1cafd..510fd3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -147,7 +147,7 @@
         public boolean onPreDraw() {
             getViewTreeObserver().removeOnPreDrawListener(this);
             mChoreo.startAnimation(true);
-            return true;
+            return false;
         }
     };
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 40cc7d8..8654a25 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -589,6 +589,11 @@
         public void onPhoneStateChanged(String newState) {
             updateEmergencyCallButtonState();
         }
+
+        /** {@inheritDoc} */
+        public void onClockVisibilityChanged() {
+            // ignored
+        }
     };
 
     private SimStateCallback mSimStateCallback = new SimStateCallback() {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 2955de3..958f555 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -81,6 +81,8 @@
 
     private int mFailedAttempts = 0;
 
+    private boolean mClockVisible;
+
     private Handler mHandler;
 
     private ArrayList<InfoCallback> mInfoCallbacks = Lists.newArrayList();
@@ -94,6 +96,7 @@
     private static final int MSG_SIM_STATE_CHANGE = 304;
     private static final int MSG_RINGER_MODE_CHANGED = 305;
     private static final int MSG_PHONE_STATE_CHANGED = 306;
+    private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
 
     /**
      * When we receive a
@@ -170,6 +173,9 @@
                     case MSG_PHONE_STATE_CHANGED:
                         handlePhoneStateChanged((String)msg.obj);
                         break;
+                    case MSG_CLOCK_VISIBILITY_CHANGED:
+                        handleClockVisibilityChanged();
+                        break;
                 }
             }
         };
@@ -334,6 +340,13 @@
         }
     }
 
+    private void handleClockVisibilityChanged() {
+        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
+        for (int i = 0; i < mInfoCallbacks.size(); i++) {
+            mInfoCallbacks.get(i).onClockVisibilityChanged();
+        }
+    }
+
     /**
      * @param status One of the statuses of {@link android.os.BatteryManager}
      * @return Whether the status maps to a status for being plugged in.
@@ -448,6 +461,12 @@
          */
         void onPhoneStateChanged(String newState);
 
+        /**
+         * Called when visibility of lockscreen clock changes, such as when
+         * obscured by a widget.
+         */
+        void onClockVisibilityChanged();
+
     }
 
     /**
@@ -484,6 +503,11 @@
         }
     }
 
+    public void reportClockVisible(boolean visible) {
+        mClockVisible = visible;
+        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
+    }
+
     public IccCard.State getSimState() {
         return mSimState;
     }
@@ -546,4 +570,8 @@
         mFailedAttempts++;
     }
 
+    public boolean isClockVisible() {
+        return mClockVisible;
+    }
+
 }
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index a544167..2a34f18 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -92,7 +92,7 @@
  * thread of the keyguard.
  */
 public class KeyguardViewMediator implements KeyguardViewCallback,
-        KeyguardUpdateMonitor.SimStateCallback {
+        KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     private final static boolean DEBUG = false;
     private final static boolean DBG_WAKE = false;
@@ -284,6 +284,7 @@
 
         mUpdateMonitor = new KeyguardUpdateMonitor(context);
 
+        mUpdateMonitor.registerInfoCallback(this);
         mUpdateMonitor.registerSimStateCallback(this);
 
         mLockPatternUtils = new LockPatternUtils(mContext);
@@ -1190,9 +1191,12 @@
                 flags |= StatusBarManager.DISABLE_NAVIGATION;
                 if (!mHidden) {
                     // showing lockscreen exclusively (no activities in front of it)
-                    // disable clock and back button too
+                    // disable back button too
                     flags |= StatusBarManager.DISABLE_BACK;
-                    flags |= StatusBarManager.DISABLE_CLOCK;
+                    if (mUpdateMonitor.isClockVisible()) {
+                        // lockscreen showing a clock, so hide statusbar clock
+                        flags |= StatusBarManager.DISABLE_CLOCK;
+                    }
                 }
                 if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
                     // showing secure lockscreen; disable expanding.
@@ -1283,4 +1287,34 @@
             mKeyguardViewManager.onScreenTurnedOn();
         }
     }
+
+    /** {@inheritDoc} */
+    public void onClockVisibilityChanged() {
+        adjustStatusBarLocked();
+    }
+
+    /** {@inheritDoc} */
+    public void onPhoneStateChanged(String newState) {
+        // ignored
+    }
+
+    /** {@inheritDoc} */
+    public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
+        // ignored
+    }
+
+    /** {@inheritDoc} */
+    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+        // ignored
+    }
+
+    /** {@inheritDoc} */
+    public void onRingerModeChanged(int state) {
+        // ignored
+    }
+
+    /** {@inheritDoc} */
+    public void onTimeChanged() {
+        // ignored
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 9c14734..62abf20 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -21,6 +21,7 @@
 import com.android.internal.telephony.IccCard;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockScreenWidgetCallback;
+import com.android.internal.widget.LockScreenWidgetInterface;
 import com.android.internal.widget.TransportControlView;
 
 import android.accounts.Account;
@@ -191,11 +192,17 @@
         public void requestShow(View view) {
             if (DEBUG) Log.v(TAG, "View " + view + " requested show transports");
             view.setVisibility(View.VISIBLE);
+
+            // TODO: examine all widgets to derive clock status
+            mUpdateMonitor.reportClockVisible(false);
         }
 
         public void requestHide(View view) {
             if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports");
             view.setVisibility(View.GONE);
+
+            // TODO: examine all widgets to derive clock status
+            mUpdateMonitor.reportClockVisible(true);
         }
     };
 
@@ -743,6 +750,7 @@
         if (tcv == null) {
             if (DEBUG) Log.w(TAG, "Couldn't find transport control widget");
         } else {
+            mUpdateMonitor.reportClockVisible(true);
             tcv.setVisibility(View.GONE); // hide tcv until we get the callback below to show it.
             tcv.setCallback(mWidgetCallback);
         }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7d1bdf0..0ff1cce 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -108,8 +108,21 @@
 }
 
 status_t HWComposer::release() const {
-    int err = mHwc->set(mHwc, NULL, NULL, NULL);
-    return (status_t)err;
+    if (mHwc) {
+        int err = mHwc->set(mHwc, NULL, NULL, NULL);
+        return (status_t)err;
+    }
+    return NO_ERROR;
+}
+
+status_t HWComposer::disable() {
+    if (mHwc) {
+        free(mList);
+        mList = NULL;
+        int err = mHwc->prepare(mHwc, NULL);
+        return (status_t)err;
+    }
+    return NO_ERROR;
 }
 
 size_t HWComposer::getNumLayers() const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 983898a..77c1a4b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -50,6 +50,9 @@
     // Asks the HAL what it can do
     status_t prepare() const;
 
+    // disable hwc until next createWorkList
+    status_t disable();
+
     // commits the list
     status_t commit() const;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b4c5dec..4a3a8ea 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2113,6 +2113,12 @@
         // we're already off
         return NO_ERROR;
     }
+
+    // turn off hwc while we're doing the animation
+    hw.getHwComposer().disable();
+    // and make sure to turn it back on (if needed) next time we compose
+    invalidateHwcGeometry();
+
     if (mode & ISurfaceComposer::eElectronBeamAnimationOff) {
         electronBeamOffAnimationImplLocked();
     }