Merge "Fix a NPE in Recents"
diff --git a/api/current.txt b/api/current.txt
index 52b28f5..f380cf9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16775,7 +16775,7 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public final class LiveFolders implements android.provider.BaseColumns {
+  public final deprecated class LiveFolders implements android.provider.BaseColumns {
     field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
     field public static final java.lang.String DESCRIPTION = "description";
     field public static final int DISPLAY_MODE_GRID = 1; // 0x1
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 3cc6820..da878d4 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -20,7 +20,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.util.HashMap;
+import java.util.WeakHashMap;
 
 /**
  * Manages NFC API's that are coupled to the life-cycle of an Activity.
@@ -38,7 +38,7 @@
     static final Boolean DBG = false;
 
     final NfcAdapter mAdapter;
-    final HashMap<Activity, NfcActivityState> mNfcState;  // contents protected by this
+    final WeakHashMap<Activity, NfcActivityState> mNfcState;  // contents protected by this
     final NfcEvent mDefaultEvent;  // can re-use one NfcEvent because it just contains adapter
 
     /**
@@ -60,7 +60,7 @@
 
     public NfcActivityManager(NfcAdapter adapter) {
         mAdapter = adapter;
-        mNfcState = new HashMap<Activity, NfcActivityState>();
+        mNfcState = new WeakHashMap<Activity, NfcActivityState>();
         mDefaultEvent = new NfcEvent(mAdapter);
     }
 
@@ -88,6 +88,13 @@
         }
     }
 
+    /**
+     * onDestroy hook from fragment attached to activity
+     */
+    public void onDestroy(Activity activity) {
+        mNfcState.remove(activity);
+    }
+
     public synchronized void setNdefPushMessage(Activity activity, NdefMessage message) {
         NfcActivityState state = getOrCreateState(activity, message != null);
         if (state == null || state.ndefMessage == message) {
@@ -214,4 +221,5 @@
             callback.onNdefPushComplete(mDefaultEvent);
         }
     }
+
 }
diff --git a/core/java/android/nfc/NfcFragment.java b/core/java/android/nfc/NfcFragment.java
index c48859b..17278dc 100644
--- a/core/java/android/nfc/NfcFragment.java
+++ b/core/java/android/nfc/NfcFragment.java
@@ -80,4 +80,14 @@
             sNfcActivityManager.onPause(getActivity());
         }
     }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (sNfcActivityManager != null) {
+            sNfcActivityManager.onDestroy(getActivity());
+        }
+    }
+
+
 }
diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java
index 7856bab..cf8ad46 100644
--- a/core/java/android/provider/LiveFolders.java
+++ b/core/java/android/provider/LiveFolders.java
@@ -162,7 +162,17 @@
  *     </tr>
  *     </tbody>
  * </table>
+ * 
+ * @deprecated Live folders are no longer supported by Android.  These have been
+ * replaced by the new
+ * <a href="{@docRoot}guide/topics/appwidgets/index.html#collections">AppWidget Collection</a>
+ * APIs introduced in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.  These provide
+ * all of the features of live folders plus many more.  The use of live folders is greatly
+ * discouraged because of security issues they introduce -- publishing a live folder requires
+ * making all data show for the live folder available to all applications with no
+ * permissions protecting it.
  */
+@Deprecated
 public final class LiveFolders implements BaseColumns {
     /**
      * <p>Content provider column.</p>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index efdb79e..bc5994e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -42,6 +42,7 @@
 import android.text.TextUtils;
 import android.util.AndroidException;
 import android.util.Log;
+import android.view.WindowOrientationListener;
 
 import java.net.URISyntaxException;
 import java.util.HashMap;
@@ -59,7 +60,7 @@
      * <p>
      * Input: Nothing.
      * <p>
-     * Output: nothing.
+     * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -69,7 +70,7 @@
      * <p>
      * Input: Nothing.
      * <p>
-     * Output: nothing.
+     * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
@@ -328,6 +329,23 @@
             "android.settings.USER_DICTIONARY_SETTINGS";
 
     /**
+     * Activity Action: Adds a word to the user dictionary.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: An extra with key <code>word</code> that contains the word
+     * that should be added to the dictionary.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_USER_DICTIONARY_INSERT =
+            "com.android.settings.USER_DICTIONARY_INSERT";
+
+    /**
      * Activity Action: Show settings to allow configuration of application-related settings.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -1462,6 +1480,7 @@
          * @hide
          * @deprecated
          */
+        @Deprecated
         public static final String NOTIFICATIONS_USE_RING_VOLUME =
             "notifications_use_ring_volume";
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 355d467..894afbd 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -750,7 +750,7 @@
                 case SUGGESTION_RANGE_SPAN:
                     readSpan(p, sp, new SuggestionRangeSpan(p));
                     break;
-                    
+
                 case EASY_EDIT_SPAN:
                     readSpan(p, sp, new EasyEditSpan());
                     break;
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index fe96565..b8728ee 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -232,8 +232,7 @@
 
         if (widget.isFocused() && !widget.didTouchFocusSelect()) {
             if (action == MotionEvent.ACTION_DOWN) {
-              boolean cap = isSelecting(buffer);
-              if (cap) {
+              if (isSelecting(buffer)) {
                   int offset = widget.getOffsetForPosition(event.getX(), event.getY());
 
                   buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
@@ -245,9 +244,7 @@
                   widget.getParent().requestDisallowInterceptTouchEvent(true);
               }
             } else if (action == MotionEvent.ACTION_MOVE) {
-                boolean cap = isSelecting(buffer);
-
-                if (cap && handled) {
+                if (isSelecting(buffer) && handled) {
                     // Before selecting, make sure we've moved out of the "slop".
                     // handled will be true, if we're in select mode AND we're
                     // OUT of the slop
@@ -279,7 +276,7 @@
                 if (isSelecting(buffer)) {
                     buffer.removeSpan(LAST_TAP_DOWN);
                     Selection.extendSelection(buffer, offset);
-                } else {
+                } else if (!widget.shouldIgnoreActionUpEvent()) {
                     Selection.setSelection(buffer, offset);
                 }
 
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index a528044..3f9b945 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -147,12 +147,10 @@
                     int nx = widget.getScrollX() + (int) dx;
                     int ny = widget.getScrollY() + (int) dy;
 
-                    int padding = widget.getTotalPaddingTop() +
-                                  widget.getTotalPaddingBottom();
+                    int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
                     Layout layout = widget.getLayout();
 
-                    ny = Math.min(ny, layout.getHeight() - (widget.getHeight() -
-                                                            padding));
+                    ny = Math.min(ny, layout.getHeight() - (widget.getHeight() - padding));
                     ny = Math.max(ny, 0);
         
                     int oldX = widget.getScrollX();
@@ -161,8 +159,7 @@
                     scrollTo(widget, layout, nx, ny);
 
                     // If we actually scrolled, then cancel the up action.
-                    if (oldX != widget.getScrollX()
-                            || oldY != widget.getScrollY()) {
+                    if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) {
                         widget.cancelLongPress();
                     }
 
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 8625257..693a7a9 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -76,8 +76,11 @@
     private final String mNotificationTargetClassName;
     private final int mHashCode;
 
-    private float mUnderlineThickness;
-    private int mUnderlineColor;
+    private float mEasyCorrectUnderlineThickness;
+    private int mEasyCorrectUnderlineColor;
+
+    private float mMisspelledUnderlineThickness;
+    private int mMisspelledUnderlineColor;
 
     /*
      * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
@@ -132,25 +135,22 @@
     }
 
     private void initStyle(Context context) {
-        int defStyle = 0;
-        if ((getFlags() & FLAG_MISSPELLED) != 0) {
-            defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
-        } else if ((getFlags() & FLAG_EASY_CORRECT) != 0) {
-            defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
-        } else {
-            // No style is applied.
-            mUnderlineThickness = 0;
-            mUnderlineColor = 0;
-            return;
-        }
-
-        TypedArray typedArray = context.obtainStyledAttributes(null,
-                com.android.internal.R.styleable.SuggestionSpan,
-                defStyle, 0);
-
-        mUnderlineThickness = typedArray.getDimension(
+        int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
+        TypedArray typedArray = context.obtainStyledAttributes(
+                null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
+        mMisspelledUnderlineThickness = typedArray.getDimension(
                 com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
-        mUnderlineColor = typedArray.getColor(
+        mMisspelledUnderlineColor = typedArray.getColor(
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
+        defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
+
+        typedArray = context.obtainStyledAttributes(
+                null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
+
+        mEasyCorrectUnderlineThickness = typedArray.getDimension(
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
+        mEasyCorrectUnderlineColor = typedArray.getColor(
                 com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
     }
 
@@ -160,8 +160,10 @@
         mLocaleString = src.readString();
         mNotificationTargetClassName = src.readString();
         mHashCode = src.readInt();
-        mUnderlineColor = src.readInt();
-        mUnderlineThickness = src.readFloat();
+        mEasyCorrectUnderlineColor = src.readInt();
+        mEasyCorrectUnderlineThickness = src.readFloat();
+        mMisspelledUnderlineColor = src.readInt();
+        mMisspelledUnderlineThickness = src.readFloat();
     }
 
     /**
@@ -211,8 +213,10 @@
         dest.writeString(mLocaleString);
         dest.writeString(mNotificationTargetClassName);
         dest.writeInt(mHashCode);
-        dest.writeInt(mUnderlineColor);
-        dest.writeFloat(mUnderlineThickness);
+        dest.writeInt(mEasyCorrectUnderlineColor);
+        dest.writeFloat(mEasyCorrectUnderlineThickness);
+        dest.writeInt(mMisspelledUnderlineColor);
+        dest.writeFloat(mMisspelledUnderlineThickness);
     }
 
     @Override
@@ -254,6 +258,10 @@
 
     @Override
     public void updateDrawState(TextPaint tp) {
-        tp.setUnderlineText(mUnderlineColor, mUnderlineThickness);
+        if ((mFlags & FLAG_MISSPELLED) != 0) {
+            tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+        } else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
+            tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+        }
     }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2e7f923..64fbae6f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2346,6 +2346,14 @@
     }
 
     /**
+     * Return the reading level scale of the WebView
+     * @return The reading level scale.
+     */
+    /*package*/ float getReadingLevelScale() {
+        return mZoomManager.getReadingLevelScale();
+    }
+
+    /**
      * Set the initial scale for the WebView. 0 means default. If
      * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
      * way. Otherwise it starts with 100%. If initial scale is greater than 0,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c895b84..c61bd48 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2460,7 +2460,7 @@
                     if (mSettings.isNarrowColumnLayout()) {
                         // In case of automatic text reflow in fixed view port mode.
                         mInitialViewState.mTextWrapScale =
-                                ZoomManager.computeReadingLevelScale(data.mScale);
+                                mWebView.getReadingLevelScale();
                     }
                 } else {
                     // Scale is given such as when page is restored, use it.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 2bcb020..0bfb668 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -58,13 +58,6 @@
     private ZoomControlExternal mExternalZoomControl;
 
     /*
-     * For large screen devices, the defaultScale usually set to 1.0 and
-     * equal to the overview scale, to differentiate the zoom level for double tapping,
-     * a default reading level scale is used.
-     */
-    private static final float DEFAULT_READING_LEVEL_SCALE = 1.5f;
-
-    /*
      * The scale factors that determine the upper and lower bounds for the
      * default zoom scale.
      */
@@ -151,6 +144,19 @@
     private float mDefaultScale;
     private float mInvDefaultScale;
 
+    /*
+     * The scale factor that is used to determine the zoom level for reading text.
+     * The value is initially set to equal the display density.
+     * TODO: Support changing this in WebSettings
+     */
+    private float mReadingLevelScale;
+
+    /*
+     * The scale factor that is used as the minimum increment when going from
+     * overview to reading level on a double tap.
+     */
+    private static float MIN_DOUBLE_TAP_SCALE_INCREMENT = 0.5f;
+
     // the current computed zoom scale and its inverse.
     private float mActualScale;
     private float mInvActualScale;
@@ -230,6 +236,7 @@
         setDefaultZoomScale(density);
         mActualScale = density;
         mInvActualScale = 1 / density;
+        mReadingLevelScale = density;
         mTextWrapScale = density;
     }
 
@@ -304,13 +311,7 @@
     }
 
     public final float getReadingLevelScale() {
-        return computeScaleWithLimits(computeReadingLevelScale(getZoomOverviewScale()));
-    }
-
-    /* package */ final static float computeReadingLevelScale(float scale) {
-        // The reading scale is at least 0.5f apart from the input scale.
-        final float MIN_SCALE_DIFF = 0.5f;
-        return Math.max(scale + MIN_SCALE_DIFF, DEFAULT_READING_LEVEL_SCALE);
+        return mReadingLevelScale;
     }
 
     public final float getInvDefaultScale() {
@@ -652,7 +653,7 @@
         } else if (!mInZoomOverview && willScaleTriggerZoom(getZoomOverviewScale())) {
             zoomToOverview();
         } else {
-            zoomToReadingLevel();
+            zoomToReadingLevelOrMore();
         }
     }
 
@@ -683,8 +684,10 @@
             !mWebView.getSettings().getUseFixedViewport());
     }
 
-    private void zoomToReadingLevel() {
-        final float readingScale = getReadingLevelScale();
+    private void zoomToReadingLevelOrMore() {
+        final float zoomScale = Math.max(getReadingLevelScale(),
+                mActualScale + MIN_DOUBLE_TAP_SCALE_INCREMENT);
+
         int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
         if (left != WebView.NO_LEFTEDGE) {
             // add a 5pt padding to the left edge.
@@ -693,13 +696,13 @@
             // Re-calculate the zoom center so that the new scroll x will be
             // on the left edge.
             if (viewLeft > 0) {
-                mZoomCenterX = viewLeft * readingScale / (readingScale - mActualScale);
+                mZoomCenterX = viewLeft * zoomScale / (zoomScale - mActualScale);
             } else {
                 mWebView.scrollBy(viewLeft, 0);
                 mZoomCenterX = 0;
             }
         }
-        startZoomAnimation(readingScale,
+        startZoomAnimation(zoomScale,
             !mWebView.getSettings().getUseFixedViewport());
     }
 
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 4fcb358..02c9d03 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -161,6 +161,7 @@
         mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
 
         // Refresh display with current params
+        refreshDrawableState();
         setChecked(isChecked());
     }
 
@@ -632,8 +633,9 @@
         int[] myDrawableState = getDrawableState();
 
         // Set the state of the Drawable
-        mThumbDrawable.setState(myDrawableState);
-        mTrackDrawable.setState(myDrawableState);
+        // Drawable may be null when checked state is set from XML, from super constructor
+        if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
+        if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
 
         invalidate();
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1aa009b..abf1281 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -21,6 +21,7 @@
 import android.content.ClipData.Item;
 import android.content.ClipboardManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -42,6 +43,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
 import android.text.Editable;
@@ -8119,6 +8121,7 @@
                 Selection.setSelection((Spannable) mText, selStart, selEnd);
             } else {
                 hideControllers();
+                downgradeEasyCorrectionSpans();
             }
 
             // No need to create the controller
@@ -8243,10 +8246,10 @@
             return superResult;
         }
 
-        final boolean touchIsFinished = action == MotionEvent.ACTION_UP && !mIgnoreActionUpEvent &&
-                isFocused();
+        final boolean touchIsFinished = (action == MotionEvent.ACTION_UP) &&
+                !shouldIgnoreActionUpEvent() && isFocused();
 
-        if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
+         if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
                 && mText instanceof Spannable && mLayout != null) {
             boolean handled = false;
 
@@ -8254,9 +8257,10 @@
                 handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
             }
 
-            if (mLinksClickable && mAutoLinkMask != 0 && mTextIsSelectable && touchIsFinished) {
+            if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && mTextIsSelectable) {
                 // The LinkMovementMethod which should handle taps on links has not been installed
-                // to support text selection. We reproduce its behavior here to open links.
+                // on non editable text that support text selection.
+                // We reproduce its behavior here to open links for these.
                 ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
                         getSelectionEnd(), ClickableSpan.class);
 
@@ -8266,7 +8270,7 @@
                 }
             }
 
-            if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) {
+            if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
                 // Show the IME, except when selecting in read-only text.
                 final InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
@@ -8277,16 +8281,12 @@
                 }
 
                 boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
-                if (!selectAllGotFocus && hasSelection()) {
-                    startSelectionActionMode();
-                } else {
-                    hideControllers();
-                    if (!selectAllGotFocus && mText.length() > 0) {
-                        if (isCursorInsideEasyCorrectionSpan()) {
-                            showSuggestions();
-                        } else if (hasInsertionController()) {
-                            getInsertionController().show();
-                        }
+                hideControllers();
+                if (!selectAllGotFocus && mText.length() > 0) {
+                    if (isCursorInsideEasyCorrectionSpan()) {
+                        showSuggestions();
+                    } else if (hasInsertionController()) {
+                        getInsertionController().show();
                     }
                 }
 
@@ -8328,6 +8328,26 @@
         return false;
     }
 
+    /**
+     * Downgrades to simple suggestions all the easy correction spans that are not a spell check
+     * span.
+     */
+    private void downgradeEasyCorrectionSpans() {
+        if (mText instanceof Spannable) {
+            Spannable spannable = (Spannable) mText;
+            SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
+                    spannable.length(), SuggestionSpan.class);
+            for (int i = 0; i < suggestionSpans.length; i++) {
+                int flags = suggestionSpans[i].getFlags();
+                if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+                        && (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) {
+                    flags = flags & ~SuggestionSpan.FLAG_EASY_CORRECT;
+                    suggestionSpans[i].setFlags(flags);
+                }
+            }
+        }
+    }
+
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (mMovement != null && mText instanceof Spannable && mLayout != null) {
@@ -8398,7 +8418,18 @@
         super.cancelLongPress();
         mIgnoreActionUpEvent = true;
     }
-    
+
+    /**
+     * This method is only valid during a touch event.
+     *
+     * @return true when the ACTION_UP event should be ignored, false otherwise.
+     *
+     * @hide
+     */
+    public boolean shouldIgnoreActionUpEvent() {
+        return mIgnoreActionUpEvent;
+    }
+
     @Override
     public boolean onTrackballEvent(MotionEvent event) {
         if (mMovement != null && mText instanceof Spannable &&
@@ -9152,6 +9183,7 @@
                 startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
                 stopSelectionActionMode();
             } else {
+                getSelectionController().hide();
                 selectCurrentWord();
                 getSelectionController().show();
             }
@@ -9199,7 +9231,8 @@
     }
 
     private interface TextViewPositionListener {
-        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified);
+        public void updatePosition(int parentPositionX, int parentPositionY,
+                boolean parentPositionChanged, boolean parentScrolled);
     }
 
     private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
@@ -9212,6 +9245,7 @@
         // Absolute position of the TextView with respect to its parent window
         private int mPositionX, mPositionY;
         private int mNumberOfListeners;
+        private boolean mScrollHasChanged;
 
         public void addSubscriber(TextViewPositionListener positionListener, boolean canMove) {
             if (mNumberOfListeners == 0) {
@@ -9263,15 +9297,16 @@
             updatePosition();
 
             for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
-                if (mPositionHasChanged || mCanMove[i]) {
+                if (mPositionHasChanged || mScrollHasChanged || mCanMove[i]) {
                     TextViewPositionListener positionListener = mPositionListeners[i];
                     if (positionListener != null) {
                         positionListener.updatePosition(mPositionX, mPositionY,
-                                mPositionHasChanged);
+                                mPositionHasChanged, mScrollHasChanged);
                     }
                 }
             }
 
+            mScrollHasChanged = false;
             return true;
         }
 
@@ -9313,6 +9348,18 @@
             final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
             return isVisible(primaryHorizontal, lineBottom);
         }
+
+        public void onScrollChanged() {
+            mScrollHasChanged = true;
+        }
+    }
+
+    @Override
+    protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
+        super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
+        if (mPositionListener != null) {
+            mPositionListener.onScrollChanged();
+        }
     }
 
     private abstract class PinnedPopupWindow implements TextViewPositionListener {
@@ -9343,7 +9390,7 @@
         }
 
         public void show() {
-            TextView.this.getPositionListener().addSubscriber(this, false);
+            TextView.this.getPositionListener().addSubscriber(this, false /* offset is fixed */);
 
             computeLocalPosition();
 
@@ -9402,8 +9449,11 @@
         }
 
         @Override
-        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+        public void updatePosition(int parentPositionX, int parentPositionY,
+                boolean parentPositionChanged, boolean parentScrolled) {
+            // Either parentPositionChanged or parentScrolled is true, check if still visible
             if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+                if (parentScrolled) computeLocalPosition();
                 updatePosition(parentPositionX, parentPositionY);
             } else {
                 hide();
@@ -9417,7 +9467,6 @@
 
     private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
-        private static final int NO_SUGGESTIONS = -1;
         private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
         private WordIterator mSuggestionWordIterator;
         private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
@@ -9472,9 +9521,9 @@
             listView.setOnItemClickListener(this);
             mContentView = listView;
 
-            // Inflate the suggestion items once and for all.
-            mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
-            for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
+            // Inflate the suggestion items once and for all. +1 for add to dictionary
+            mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 1];
+            for (int i = 0; i < MAX_NUMBER_SUGGESTIONS + 1; i++) {
                 mSuggestionInfos[i] = new SuggestionInfo();
             }
         }
@@ -9485,6 +9534,15 @@
             SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
             int suggestionIndex; // the index of the suggestion inside suggestionSpan
             SpannableStringBuilder text = new SpannableStringBuilder();
+
+            void removeMisspelledFlag() {
+                int suggestionSpanFlags = suggestionSpan.getFlags();
+                if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
+                    suggestionSpanFlags &= ~(SuggestionSpan.FLAG_MISSPELLED);
+                    suggestionSpanFlags &= ~(SuggestionSpan.FLAG_EASY_CORRECT);
+                    suggestionSpan.setFlags(suggestionSpanFlags);
+                }
+            }
         }
 
         private class SuggestionAdapter extends BaseAdapter {
@@ -9623,6 +9681,8 @@
             int spanUnionStart = mText.length();
             int spanUnionEnd = 0;
 
+            SuggestionSpan misspelledSpan = null;
+
             for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
                 SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
                 final int spanStart = spannable.getSpanStart(suggestionSpan);
@@ -9630,6 +9690,10 @@
                 spanUnionStart = Math.min(spanStart, spanUnionStart);
                 spanUnionEnd = Math.max(spanEnd, spanUnionEnd);
 
+                if ((suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+                    misspelledSpan = suggestionSpan;
+                }
+
                 String[] suggestions = suggestionSpan.getSuggestions();
                 int nbSuggestions = suggestions.length;
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
@@ -9638,7 +9702,8 @@
                     suggestionInfo.spanEnd = spanEnd;
                     suggestionInfo.suggestionSpan = suggestionSpan;
                     suggestionInfo.suggestionIndex = suggestionIndex;
-                    suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]);
+                    suggestionInfo.text.replace(0, suggestionInfo.text.length(),
+                            suggestions[suggestionIndex]);
 
                     mNumberOfSuggestions++;
                     if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
@@ -9649,41 +9714,38 @@
                 }
             }
 
+            for (int i = 0; i < mNumberOfSuggestions; i++) {
+                highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
+            }
+
+            if (misspelledSpan != null) {
+                final int misspelledStart = spannable.getSpanStart(misspelledSpan);
+                final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
+                if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
+                    SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
+                    suggestionInfo.spanStart = misspelledStart;
+                    suggestionInfo.spanEnd = misspelledEnd;
+                    suggestionInfo.suggestionSpan = misspelledSpan;
+                    suggestionInfo.suggestionIndex = -1;
+                    suggestionInfo.text.replace(0, suggestionInfo.text.length(),
+                            getContext().getString(com.android.internal.R.string.addToDictionary));
+
+                    mNumberOfSuggestions++;
+                }
+            }
+
             if (mNumberOfSuggestions == 0) return false;
 
             if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
                     new SuggestionRangeSpan(mHighlightColor);
-
             ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
-            for (int i = 0; i < mNumberOfSuggestions; i++) {
-                highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
-            }
             mSuggestionsAdapter.notifyDataSetChanged();
 
             return true;
         }
 
-        private void onDictionarySuggestionsReceived(String[] suggestions) {
-            if (suggestions.length == 0) {
-                // TODO Actual implementation of this feature
-                suggestions = new String[] {"Add to dictionary"};
-            }
-
-            WordIterator wordIterator = getWordIterator();
-            wordIterator.setCharSequence(mText);
-
-            final int pos = getSelectionStart();
-            int wordStart = wordIterator.getBeginning(pos);
-            int wordEnd = wordIterator.getEnd(pos);
-
-            SuggestionSpan suggestionSpan = new SuggestionSpan(getContext(), suggestions, 0);
-            ((Editable) mText).setSpan(suggestionSpan, wordStart, wordEnd,
-                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-            show();
-        }
-
         private long[] getWordLimits(CharSequence text) {
             // TODO locale for mSuggestionWordIterator
             if (mSuggestionWordIterator == null) mSuggestionWordIterator = new WordIterator();
@@ -9836,10 +9898,19 @@
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             if (view instanceof TextView) {
                 TextView textView = (TextView) view;
+
                 SuggestionInfo suggestionInfo = mSuggestionInfos[position];
                 final int spanStart = suggestionInfo.spanStart;
                 final int spanEnd = suggestionInfo.spanEnd;
-                if (spanStart != NO_SUGGESTIONS) {
+                final String originalText = mText.subSequence(spanStart, spanEnd).toString();
+
+                if (suggestionInfo.suggestionIndex < 0) {
+                    Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
+                    intent.putExtra("word", originalText);
+                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+                    getContext().startActivity(intent);
+                    suggestionInfo.removeMisspelledFlag();
+                } else {
                     // SuggestionSpans are removed by replace: save them before
                     Editable editable = (Editable) mText;
                     SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
@@ -9859,17 +9930,9 @@
                     final int suggestionEnd = suggestionInfo.suggestionEnd;
                     final String suggestion = textView.getText().subSequence(
                             suggestionStart, suggestionEnd).toString();
-                    final String originalText = mText.subSequence(spanStart, spanEnd).toString();
                     editable.replace(spanStart, spanEnd, suggestion);
 
-                    // A replacement on a misspelled text removes the misspelled flag.
-                    // TODO restore the flag if the misspelled word is selected back?
-                    int suggestionSpanFlags = suggestionInfo.suggestionSpan.getFlags();
-                    if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
-                        suggestionSpanFlags &= ~(SuggestionSpan.FLAG_MISSPELLED);
-                        suggestionSpanFlags &= ~(SuggestionSpan.FLAG_EASY_CORRECT);
-                        suggestionInfo.suggestionSpan.setFlags(suggestionSpanFlags);
-                    }
+                    suggestionInfo.removeMisspelledFlag();
 
                     // Notify source IME of the suggestion pick. Do this before swaping texts.
                     if (!TextUtils.isEmpty(
@@ -9916,12 +9979,6 @@
         return mSuggestionsPopupWindow != null && mSuggestionsPopupWindow.isShowing();
     }
 
-    void onDictionarySuggestionsReceived(String[] suggestions) {
-        if (mSuggestionsPopupWindow != null) {
-            mSuggestionsPopupWindow.onDictionarySuggestionsReceived(suggestions);
-        }
-    }
-
     /**
      * Return whether or not suggestions are enabled on this TextView. The suggestions are generated
      * by the IME or by the spell checker as the user types. This is done by adding
@@ -10349,7 +10406,7 @@
 
             if (i > 0 && i < iMax &&
                     (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
-                positionAtCursorOffset(mPreviousOffsets[index]);
+                positionAtCursorOffset(mPreviousOffsets[index], false);
             }
         }
 
@@ -10365,11 +10422,11 @@
         public void show() {
             if (isShowing()) return;
 
-            getPositionListener().addSubscriber(this, true);
+            getPositionListener().addSubscriber(this, true /* local position may change */);
 
             // Make sure the offset is always considered new, even when focusing at same position
             mPreviousOffset = -1;
-            positionAtCursorOffset(getCurrentCursorOffset());
+            positionAtCursorOffset(getCurrentCursorOffset(), false);
 
             hideActionPopupWindow();
         }
@@ -10434,7 +10491,7 @@
 
         public abstract void updatePosition(float x, float y);
 
-        protected void positionAtCursorOffset(int offset) {
+        protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
             // A HandleView relies on the layout, which may be nulled by external methods
             if (mLayout == null) {
                 // Will update controllers' state, hiding them and stopping selection mode if needed
@@ -10442,7 +10499,7 @@
                 return;
             }
 
-            if (offset != mPreviousOffset) {
+            if (offset != mPreviousOffset || parentScrolled) {
                 updateSelection(offset);
                 addPositionToTouchUpFilter(offset);
                 final int line = mLayout.getLineForOffset(offset);
@@ -10459,9 +10516,10 @@
             }
         }
 
-        public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
-            positionAtCursorOffset(getCurrentCursorOffset());
-            if (modified || mPositionHasChanged) {
+        public void updatePosition(int parentPositionX, int parentPositionY,
+                boolean parentPositionChanged, boolean parentScrolled) {
+            positionAtCursorOffset(getCurrentCursorOffset(), parentScrolled);
+            if (parentPositionChanged || mPositionHasChanged) {
                 if (mIsDragging) {
                     // Update touchToWindow offset in case of parent scrolling while dragging
                     if (parentPositionX != mLastParentX || parentPositionY != mLastParentY) {
@@ -10666,7 +10724,7 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            positionAtCursorOffset(getOffsetForPosition(x, y));
+            positionAtCursorOffset(getOffsetForPosition(x, y), false);
         }
 
         @Override
@@ -10705,17 +10763,13 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            final int selectionStart = getSelectionStart();
-            final int selectionEnd = getSelectionEnd();
-
             int offset = getOffsetForPosition(x, y);
 
-            // No need to redraw when the offset is unchanged
-            if (offset == selectionStart) return;
             // Handles can not cross and selection is at least one character
+            final int selectionEnd = getSelectionEnd();
             if (offset >= selectionEnd) offset = selectionEnd - 1;
 
-            positionAtCursorOffset(offset);
+            positionAtCursorOffset(offset, false);
         }
 
         public ActionPopupWindow getActionPopupWindow() {
@@ -10746,17 +10800,13 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            final int selectionStart = getSelectionStart();
-            final int selectionEnd = getSelectionEnd();
-
             int offset = getOffsetForPosition(x, y);
 
-            // No need to redraw when the offset is unchanged
-            if (offset == selectionEnd) return;
             // Handles can not cross and selection is at least one character
+            final int selectionStart = getSelectionStart();
             if (offset <= selectionStart) offset = selectionStart + 1;
 
-            positionAtCursorOffset(offset);
+            positionAtCursorOffset(offset, false);
         }
 
         public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
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/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 685ebb7..5e010fe 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2484,6 +2484,9 @@
     <!-- Text selection contextual mode title, displayed in the CAB. [CHAR LIMIT=20] -->
     <string name="textSelectionCABTitle">Text selection</string>
 
+    <!-- Option to add the current misspelled word to the user dictionary. [CHAR LIMIT=25] -->
+    <string name="addToDictionary">+ add to dictionary</string>
+
     <!-- EditText context menu -->
     <string name="inputMethod">Input method</string>
 
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 1bee47a..e468558 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -46,6 +46,16 @@
     </family>
     <family>
         <fileset>
+            <file>DroidSansArmenian.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansGeorgian.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>Lohit_Hindi.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 56bd2ce..5bac8f0 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -31,6 +31,8 @@
     frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \
     frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
     frameworks/base/data/fonts/Lohit_Hindi.ttf:system/fonts/Lohit_Hindi.ttf \
+    frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \
+    frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \
     frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
     frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
     frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
diff --git a/data/sounds/alarms/wav/Copernicium.wav b/data/sounds/alarms/wav/Copernicium.wav
new file mode 100644
index 0000000..935ea75
--- /dev/null
+++ b/data/sounds/alarms/wav/Copernicium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Curium.wav b/data/sounds/alarms/wav/Curium.wav
new file mode 100644
index 0000000..a9942d3
--- /dev/null
+++ b/data/sounds/alarms/wav/Curium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Fermium.wav b/data/sounds/alarms/wav/Fermium.wav
new file mode 100644
index 0000000..0174884
--- /dev/null
+++ b/data/sounds/alarms/wav/Fermium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Hassium.wav b/data/sounds/alarms/wav/Hassium.wav
new file mode 100644
index 0000000..e3992cf
--- /dev/null
+++ b/data/sounds/alarms/wav/Hassium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Neptunium.wav b/data/sounds/alarms/wav/Neptunium.wav
new file mode 100644
index 0000000..cf3684a
--- /dev/null
+++ b/data/sounds/alarms/wav/Neptunium.wav
Binary files differ
diff --git a/data/sounds/alarms/wav/Nobelium.wav b/data/sounds/alarms/wav/Nobelium.wav
new file mode 100644
index 0000000..0e9101a
--- /dev/null
+++ b/data/sounds/alarms/wav/Nobelium.wav
Binary files differ
diff --git a/data/sounds/effects/wav/CameraClick.wav b/data/sounds/effects/wav/CameraClick.wav
new file mode 100644
index 0000000..9fe75f2
--- /dev/null
+++ b/data/sounds/effects/wav/CameraClick.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Dock.wav b/data/sounds/effects/wav/Dock.wav
index 7fa6a7e..7ec64a8 100644
--- a/data/sounds/effects/wav/Dock.wav
+++ b/data/sounds/effects/wav/Dock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressDelete_14.wav b/data/sounds/effects/wav/KeypressDelete_14.wav
new file mode 100644
index 0000000..1d3498e
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressDelete_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressDelete_49.wav b/data/sounds/effects/wav/KeypressDelete_49.wav
new file mode 100644
index 0000000..2404759
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressDelete_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressReturn_14.wav b/data/sounds/effects/wav/KeypressReturn_14.wav
new file mode 100644
index 0000000..01573ff
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressReturn_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressReturn_49.wav b/data/sounds/effects/wav/KeypressReturn_49.wav
new file mode 100644
index 0000000..6bf216f
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressReturn_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressSpacebar_14.wav b/data/sounds/effects/wav/KeypressSpacebar_14.wav
new file mode 100644
index 0000000..77269a6
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressSpacebar_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressSpacebar_49.wav b/data/sounds/effects/wav/KeypressSpacebar_49.wav
new file mode 100644
index 0000000..8504a25
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressSpacebar_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressStandard_14.wav b/data/sounds/effects/wav/KeypressStandard_14.wav
new file mode 100644
index 0000000..93389ac
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressStandard_14.wav
Binary files differ
diff --git a/data/sounds/effects/wav/KeypressStandard_49.wav b/data/sounds/effects/wav/KeypressStandard_49.wav
new file mode 100644
index 0000000..9a660a1
--- /dev/null
+++ b/data/sounds/effects/wav/KeypressStandard_49.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Lock.wav b/data/sounds/effects/wav/Lock.wav
index 88be052..fead37f 100644
--- a/data/sounds/effects/wav/Lock.wav
+++ b/data/sounds/effects/wav/Lock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/LowBattery.wav b/data/sounds/effects/wav/LowBattery.wav
index 8905534..5d8b48d 100644
--- a/data/sounds/effects/wav/LowBattery.wav
+++ b/data/sounds/effects/wav/LowBattery.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Undock.wav b/data/sounds/effects/wav/Undock.wav
index 358eb18..79abb4e 100644
--- a/data/sounds/effects/wav/Undock.wav
+++ b/data/sounds/effects/wav/Undock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/Unlock.wav b/data/sounds/effects/wav/Unlock.wav
index 4b39c5c..33b80ff 100644
--- a/data/sounds/effects/wav/Unlock.wav
+++ b/data/sounds/effects/wav/Unlock.wav
Binary files differ
diff --git a/data/sounds/effects/wav/VideoRecord.wav b/data/sounds/effects/wav/VideoRecord.wav
index 6880b29..f431023 100644
--- a/data/sounds/effects/wav/VideoRecord.wav
+++ b/data/sounds/effects/wav/VideoRecord.wav
Binary files differ
diff --git a/data/sounds/effects/wav/camera_click.wav b/data/sounds/effects/wav/camera_click.wav
deleted file mode 100644
index 420da7c..0000000
--- a/data/sounds/effects/wav/camera_click.wav
+++ /dev/null
Binary files differ
diff --git a/data/sounds/notifications/wav/Altair.wav b/data/sounds/notifications/wav/Altair.wav
new file mode 100644
index 0000000..0fb9788
--- /dev/null
+++ b/data/sounds/notifications/wav/Altair.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Antares.wav b/data/sounds/notifications/wav/Antares.wav
new file mode 100644
index 0000000..7c2dd23
--- /dev/null
+++ b/data/sounds/notifications/wav/Antares.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Betelgeuse.wav b/data/sounds/notifications/wav/Betelgeuse.wav
new file mode 100644
index 0000000..9ad799f
--- /dev/null
+++ b/data/sounds/notifications/wav/Betelgeuse.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Deneb.wav b/data/sounds/notifications/wav/Deneb.wav
new file mode 100644
index 0000000..ffe7c31
--- /dev/null
+++ b/data/sounds/notifications/wav/Deneb.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Hojus.wav b/data/sounds/notifications/wav/Hojus.wav
new file mode 100644
index 0000000..076a0c7
--- /dev/null
+++ b/data/sounds/notifications/wav/Hojus.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Lalande.wav b/data/sounds/notifications/wav/Lalande.wav
new file mode 100644
index 0000000..14c9fec
--- /dev/null
+++ b/data/sounds/notifications/wav/Lalande.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Mira.wav b/data/sounds/notifications/wav/Mira.wav
new file mode 100644
index 0000000..71be516
--- /dev/null
+++ b/data/sounds/notifications/wav/Mira.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Proxima.wav b/data/sounds/notifications/wav/Proxima.wav
new file mode 100644
index 0000000..109bfdd
--- /dev/null
+++ b/data/sounds/notifications/wav/Proxima.wav
Binary files differ
diff --git a/data/sounds/notifications/wav/Upsilon.wav b/data/sounds/notifications/wav/Upsilon.wav
new file mode 100644
index 0000000..ffc959b
--- /dev/null
+++ b/data/sounds/notifications/wav/Upsilon.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Cassiopeia.wav b/data/sounds/ringtones/wav/Cassiopeia.wav
new file mode 100644
index 0000000..5c5c6e0
--- /dev/null
+++ b/data/sounds/ringtones/wav/Cassiopeia.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Lyra.wav b/data/sounds/ringtones/wav/Lyra.wav
new file mode 100644
index 0000000..2943cf5
--- /dev/null
+++ b/data/sounds/ringtones/wav/Lyra.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Sceptrum.wav b/data/sounds/ringtones/wav/Sceptrum.wav
new file mode 100644
index 0000000..3694373
--- /dev/null
+++ b/data/sounds/ringtones/wav/Sceptrum.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Solarium.wav b/data/sounds/ringtones/wav/Solarium.wav
new file mode 100644
index 0000000..93f1e01
--- /dev/null
+++ b/data/sounds/ringtones/wav/Solarium.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/UrsaMinor.wav b/data/sounds/ringtones/wav/UrsaMinor.wav
new file mode 100644
index 0000000..5e16c94
--- /dev/null
+++ b/data/sounds/ringtones/wav/UrsaMinor.wav
Binary files differ
diff --git a/data/sounds/ringtones/wav/Vespa.wav b/data/sounds/ringtones/wav/Vespa.wav
new file mode 100644
index 0000000..7d696f8
--- /dev/null
+++ b/data/sounds/ringtones/wav/Vespa.wav
Binary files differ
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/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 4418e02a..88c9155 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -111,8 +111,11 @@
         alpha += alpha >> 7;   // make it 0..256
         int baseAlpha = mState.mBaseColor >>> 24;
         int useAlpha = baseAlpha * alpha >> 8;
+        int oldUseColor = mState.mUseColor;
         mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
-        invalidateSelf();
+        if (oldUseColor != mState.mUseColor) {
+            invalidateSelf();
+        }
     }
 
     /**
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 e99888c..0d17b55 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -37,7 +37,6 @@
             android:layout_alignParentTop="true"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
             android:scaleType="center"
-            android:clickable="true"
             android:background="@drawable/recents_thumbnail_overlay">
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="match_parent"
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 73ca335..84c89f7 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -33,7 +33,6 @@
             android:layout_height="wrap_content"
             android:layout_alignParentLeft="true"
             android:layout_alignParentTop="true"
-            android:clickable="true"
             android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
             android:scaleType="center"
             android:background="@drawable/recents_thumbnail_overlay">
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index dd25cf9..ed9ea7a 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -38,6 +38,7 @@
             android:orientation="horizontal"
             android:clipChildren="false"
             android:layout_marginTop="@*android:dimen/status_bar_height">
+
             <com.android.systemui.recent.RecentsVerticalScrollView
                 android:id="@+id/recents_container"
                 android:layout_width="match_parent"
@@ -62,7 +63,6 @@
 
             </com.android.systemui.recent.RecentsVerticalScrollView>
 
-
         </LinearLayout>
 
     </FrameLayout>
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 cab90fd..9dc6378 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -29,7 +29,6 @@
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:clickable="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
         android:background="@drawable/recents_thumbnail_overlay">
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 09d38d8..0354fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -198,7 +198,11 @@
         final View animView = mCallback.getChildContentView(view);
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
         float newPos;
-        if (velocity < 0 || (velocity == 0 && getTranslation(animView) < 0)) {
+
+        if (velocity < 0
+                || (velocity == 0 && getTranslation(animView) < 0)
+                // if we use the Menu to dismiss an item in landscape, animate up
+                || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) {
             newPos = -getSize(animView);
         } else {
             newPos = getSize(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 2de4185..e3c4eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -28,6 +28,7 @@
     void handleSwipe(View selectedView);
     void handleLongPress(View selectedView, View anchorView);
     void handleShowBackground(boolean show);
+    void dismiss();
 
     // TODO: find another way to get this info from RecentsPanelView
     boolean isRecentsVisible();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index e59c109..d7bb3c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -243,8 +243,11 @@
         }
     }
 
+    public void dismiss() {
+        hide(true);
+    }
+
     public void hide(boolean animate) {
-        mShowing = false;
         if (!animate) {
             setVisibility(View.GONE);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 3acef08..1978d69 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -84,15 +84,26 @@
             if (old == null) {
                 view.setClickable(true);
                 view.setOnLongClickListener(mOnLongClick);
-
-                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.handleOnClick(view);
+                        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);
+                final View calloutLine = view.findViewById(R.id.recents_callout_line);
+                calloutLine.setClickable(true);
+                calloutLine.setOnClickListener(launchAppListener);
                 mLinearLayout.addView(view);
             }
         }
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 d9cb4e8..4a1cafd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -28,6 +28,10 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
 import android.widget.RelativeLayout;
 
 import com.android.systemui.R;
@@ -52,6 +56,8 @@
     ViewGroup mContentParent;
     TabletStatusBar mBar;
     View mClearButton;
+    static Interpolator sAccelerateInterpolator = new AccelerateInterpolator();
+    static Interpolator sDecelerateInterpolator = new DecelerateInterpolator();
 
     // amount to slide mContentParent down by when mContentFrame is missing
     float mContentFrameMissingTranslation;
@@ -117,8 +123,13 @@
                 mShowing = show;
                 if (show) {
                     setVisibility(View.VISIBLE);
+                    // Don't start the animation until we've created the layer, which is done
+                    // right before we are drawn
+                    mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                    getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+                } else {
+                    mChoreo.startAnimation(show);
                 }
-                mChoreo.startAnimation(show);
             }
         } else {
             mShowing = show;
@@ -127,6 +138,20 @@
     }
 
     /**
+     * This is used only when we've created a hardware layer and are waiting until it's
+     * been created in order to start the appearing animation.
+     */
+    private ViewTreeObserver.OnPreDrawListener mPreDrawListener =
+            new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            mChoreo.startAnimation(true);
+            return true;
+        }
+    };
+
+    /**
      * Whether the panel is showing, or, if it's animating, whether it will be
      * when the animation is done.
      */
@@ -330,8 +355,8 @@
         AnimatorSet mContentAnim;
 
         // should group this into a multi-property animation
-        final static int OPEN_DURATION = 300;
-        final static int CLOSE_DURATION = 300;
+        final static int OPEN_DURATION = 250;
+        final static int CLOSE_DURATION = 250;
 
         // the panel will start to appear this many px from the end
         final int HYPERSPACE_OFFRAMP = 200;
@@ -362,19 +387,15 @@
 
             Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY",
                     start, end);
-            posAnim.setInterpolator(appearing
-                    ? new android.view.animation.DecelerateInterpolator(1.0f)
-                    : new android.view.animation.AccelerateInterpolator(1.0f));
+            posAnim.setInterpolator(appearing ? sDecelerateInterpolator : sAccelerateInterpolator);
 
             if (mContentAnim != null && mContentAnim.isRunning()) {
                 mContentAnim.cancel();
             }
 
             Animator fadeAnim = ObjectAnimator.ofFloat(mContentParent, "alpha",
-                                mContentParent.getAlpha(), appearing ? 1.0f : 0.0f);
-            fadeAnim.setInterpolator(appearing
-                    ? new android.view.animation.AccelerateInterpolator(2.0f)
-                    : new android.view.animation.DecelerateInterpolator(2.0f));
+                    appearing ? 1.0f : 0.0f);
+            fadeAnim.setInterpolator(appearing ? sAccelerateInterpolator : sDecelerateInterpolator);
 
             mContentAnim = new AnimatorSet();
             mContentAnim
@@ -389,8 +410,6 @@
             if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
 
             createAnimation(appearing);
-
-            mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
             mContentAnim.start();
 
             mVisible = appearing;
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();
     }