Merge "making slide unlock on tablet have a larger radius" into ics-mr1
diff --git a/api/current.txt b/api/current.txt
index fe0699c..b180f7d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14399,6 +14399,7 @@
     field public static final int HONEYCOMB_MR1 = 12; // 0xc
     field public static final int HONEYCOMB_MR2 = 13; // 0xd
     field public static final int ICE_CREAM_SANDWICH = 14; // 0xe
+    field public static final int ICE_CREAM_SANDWICH_MR1 = 15; // 0xf
   }
 
   public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -22849,6 +22850,7 @@
     method public void buildDrawingCache();
     method public void buildDrawingCache(boolean);
     method public void buildLayer();
+    method public boolean callOnClick();
     method public boolean canScrollHorizontally(int);
     method public boolean canScrollVertically(int);
     method public void cancelLongPress();
@@ -23000,6 +23002,7 @@
     method public float getY();
     method public boolean hasFocus();
     method public boolean hasFocusable();
+    method public boolean hasOnClickListeners();
     method public boolean hasWindowFocus();
     method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
     method protected void initializeFadingEdge(android.content.res.TypedArray);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8afe9bf..00fe953 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2769,7 +2769,9 @@
             if (info != null) {
                 try {
                     // First create a thumbnail for the activity...
-                    info.thumbnail = createThumbnailBitmap(r);
+                    // For now, don't create the thumbnail here; we are
+                    // doing that by doing a screen snapshot.
+                    info.thumbnail = null; //createThumbnailBitmap(r);
                     info.description = r.activity.onCreateDescription();
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 7a69419..f1ce2bb 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ContextMenu;
@@ -77,6 +78,7 @@
  */
 public class Dialog implements DialogInterface, Window.Callback,
         KeyEvent.Callback, OnCreateContextMenuListener {
+    private static final String TAG = "Dialog";
     private Activity mOwnerActivity;
     
     final Context mContext;
@@ -110,6 +112,8 @@
 
     private Handler mListenersHandler;
 
+    private ActionMode mActionMode;
+
     private final Runnable mDismissAction = new Runnable() {
         public void run() {
             dismissDialog();
@@ -298,18 +302,27 @@
         if (Thread.currentThread() != mUiThread) {
             mHandler.post(mDismissAction);
         } else {
+            mHandler.removeCallbacks(mDismissAction);
             mDismissAction.run();
         }
     }
 
-    private void dismissDialog() {
+    void dismissDialog() {
         if (mDecor == null || !mShowing) {
             return;
         }
 
+        if (mWindow.isDestroyed()) {
+            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
+            return;
+        }
+
         try {
             mWindowManager.removeView(mDecor);
         } finally {
+            if (mActionMode != null) {
+                mActionMode.finish();
+            }
             mDecor = null;
             mWindow.closeAllPanels();
             onStop();
@@ -952,10 +965,26 @@
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * Note that if you override this method you should always call through
+     * to the superclass implementation by calling super.onActionModeStarted(mode).
+     */
     public void onActionModeStarted(ActionMode mode) {
+        mActionMode = mode;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * Note that if you override this method you should always call through
+     * to the superclass implementation by calling super.onActionModeFinished(mode).
+     */
     public void onActionModeFinished(ActionMode mode) {
+        if (mode == mActionMode) {
+            mActionMode = null;
+        }
     }
 
     /**
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 17a882d..7d034940 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -277,7 +277,7 @@
         public static final int HONEYCOMB_MR2 = 13;
 
         /**
-         * Android 4.0.
+         * October 2011: Android 4.0.
          *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -309,6 +309,11 @@
          * </ul>
          */
         public static final int ICE_CREAM_SANDWICH = 14;
+
+        /**
+         * Android 4.1.
+         */
+        public static final int ICE_CREAM_SANDWICH_MR1 = 15;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fea79d5..62e6ebd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1548,7 +1548,7 @@
     int mID = NO_ID;
 
     /**
-     * The stable ID of this view for accessibility porposes.
+     * The stable ID of this view for accessibility purposes.
      */
     int mAccessibilityViewId = NO_ID;
 
@@ -2317,55 +2317,59 @@
     private int mBackgroundResource;
     private boolean mBackgroundSizeChanged;
 
-    /**
-     * Listener used to dispatch focus change events.
-     * This field should be made private, so it is hidden from the SDK.
-     * {@hide}
-     */
-    protected OnFocusChangeListener mOnFocusChangeListener;
+    static class ListenerInfo {
+        /**
+         * Listener used to dispatch focus change events.
+         * This field should be made private, so it is hidden from the SDK.
+         * {@hide}
+         */
+        protected OnFocusChangeListener mOnFocusChangeListener;
 
-    /**
-     * Listeners for layout change events.
-     */
-    private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
+        /**
+         * Listeners for layout change events.
+         */
+        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
 
-    /**
-     * Listeners for attach events.
-     */
-    private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
+        /**
+         * Listeners for attach events.
+         */
+        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
 
-    /**
-     * Listener used to dispatch click events.
-     * This field should be made private, so it is hidden from the SDK.
-     * {@hide}
-     */
-    protected OnClickListener mOnClickListener;
+        /**
+         * Listener used to dispatch click events.
+         * This field should be made private, so it is hidden from the SDK.
+         * {@hide}
+         */
+        public OnClickListener mOnClickListener;
 
-    /**
-     * Listener used to dispatch long click events.
-     * This field should be made private, so it is hidden from the SDK.
-     * {@hide}
-     */
-    protected OnLongClickListener mOnLongClickListener;
+        /**
+         * Listener used to dispatch long click events.
+         * This field should be made private, so it is hidden from the SDK.
+         * {@hide}
+         */
+        protected OnLongClickListener mOnLongClickListener;
 
-    /**
-     * Listener used to build the context menu.
-     * This field should be made private, so it is hidden from the SDK.
-     * {@hide}
-     */
-    protected OnCreateContextMenuListener mOnCreateContextMenuListener;
+        /**
+         * Listener used to build the context menu.
+         * This field should be made private, so it is hidden from the SDK.
+         * {@hide}
+         */
+        protected OnCreateContextMenuListener mOnCreateContextMenuListener;
 
-    private OnKeyListener mOnKeyListener;
+        private OnKeyListener mOnKeyListener;
 
-    private OnTouchListener mOnTouchListener;
+        private OnTouchListener mOnTouchListener;
 
-    private OnHoverListener mOnHoverListener;
+        private OnHoverListener mOnHoverListener;
 
-    private OnGenericMotionListener mOnGenericMotionListener;
+        private OnGenericMotionListener mOnGenericMotionListener;
 
-    private OnDragListener mOnDragListener;
+        private OnDragListener mOnDragListener;
 
-    private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+    }
+
+    ListenerInfo mListenerInfo;
 
     /**
      * The application environment this view lives in.
@@ -3346,13 +3350,21 @@
         return mVerticalScrollbarPosition;
     }
 
+    ListenerInfo getListenerInfo() {
+        if (mListenerInfo != null) {
+            return mListenerInfo;
+        }
+        mListenerInfo = new ListenerInfo();
+        return mListenerInfo;
+    }
+
     /**
      * Register a callback to be invoked when focus of this view changed.
      *
      * @param l The callback that will run.
      */
     public void setOnFocusChangeListener(OnFocusChangeListener l) {
-        mOnFocusChangeListener = l;
+        getListenerInfo().mOnFocusChangeListener = l;
     }
 
     /**
@@ -3362,11 +3374,12 @@
      * @param listener The listener that will be called when layout bounds change.
      */
     public void addOnLayoutChangeListener(OnLayoutChangeListener listener) {
-        if (mOnLayoutChangeListeners == null) {
-            mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>();
+        ListenerInfo li = getListenerInfo();
+        if (li.mOnLayoutChangeListeners == null) {
+            li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>();
         }
-        if (!mOnLayoutChangeListeners.contains(listener)) {
-            mOnLayoutChangeListeners.add(listener);
+        if (!li.mOnLayoutChangeListeners.contains(listener)) {
+            li.mOnLayoutChangeListeners.add(listener);
         }
     }
 
@@ -3376,10 +3389,11 @@
      * @param listener The listener for layout bounds change.
      */
     public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) {
-        if (mOnLayoutChangeListeners == null) {
+        ListenerInfo li = mListenerInfo;
+        if (li == null || li.mOnLayoutChangeListeners == null) {
             return;
         }
-        mOnLayoutChangeListeners.remove(listener);
+        li.mOnLayoutChangeListeners.remove(listener);
     }
 
     /**
@@ -3393,10 +3407,12 @@
      * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener)
      */
     public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
-        if (mOnAttachStateChangeListeners == null) {
-            mOnAttachStateChangeListeners = new CopyOnWriteArrayList<OnAttachStateChangeListener>();
+        ListenerInfo li = getListenerInfo();
+        if (li.mOnAttachStateChangeListeners == null) {
+            li.mOnAttachStateChangeListeners
+                    = new CopyOnWriteArrayList<OnAttachStateChangeListener>();
         }
-        mOnAttachStateChangeListeners.add(listener);
+        li.mOnAttachStateChangeListeners.add(listener);
     }
 
     /**
@@ -3407,10 +3423,11 @@
      * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener)
      */
     public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
-        if (mOnAttachStateChangeListeners == null) {
+        ListenerInfo li = mListenerInfo;
+        if (li == null || li.mOnAttachStateChangeListeners == null) {
             return;
         }
-        mOnAttachStateChangeListeners.remove(listener);
+        li.mOnAttachStateChangeListeners.remove(listener);
     }
 
     /**
@@ -3419,7 +3436,8 @@
      * @return The callback, or null if one is not registered.
      */
     public OnFocusChangeListener getOnFocusChangeListener() {
-        return mOnFocusChangeListener;
+        ListenerInfo li = mListenerInfo;
+        return li != null ? li.mOnFocusChangeListener : null;
     }
 
     /**
@@ -3434,7 +3452,16 @@
         if (!isClickable()) {
             setClickable(true);
         }
-        mOnClickListener = l;
+        getListenerInfo().mOnClickListener = l;
+    }
+
+    /**
+     * Return whether this view has an attached OnClickListener.  Returns
+     * true if there is a listener, false if there is none.
+     */
+    public boolean hasOnClickListeners() {
+        ListenerInfo li = mListenerInfo;
+        return (li != null && li.mOnClickListener != null);
     }
 
     /**
@@ -3449,7 +3476,7 @@
         if (!isLongClickable()) {
             setLongClickable(true);
         }
-        mOnLongClickListener = l;
+        getListenerInfo().mOnLongClickListener = l;
     }
 
     /**
@@ -3463,11 +3490,13 @@
         if (!isLongClickable()) {
             setLongClickable(true);
         }
-        mOnCreateContextMenuListener = l;
+        getListenerInfo().mOnCreateContextMenuListener = l;
     }
 
     /**
-     * Call this view's OnClickListener, if it is defined.
+     * Call this view's OnClickListener, if it is defined.  Performs all normal
+     * actions associated with clicking: reporting accessibility event, playing
+     * a sound, etc.
      *
      * @return True there was an assigned OnClickListener that was called, false
      *         otherwise is returned.
@@ -3475,9 +3504,10 @@
     public boolean performClick() {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
 
-        if (mOnClickListener != null) {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnClickListener != null) {
             playSoundEffect(SoundEffectConstants.CLICK);
-            mOnClickListener.onClick(this);
+            li.mOnClickListener.onClick(this);
             return true;
         }
 
@@ -3485,6 +3515,23 @@
     }
 
     /**
+     * Directly call any attached OnClickListener.  Unlike {@link #performClick()},
+     * this only calls the listener, and does not do any associated clicking
+     * actions like reporting an accessibility event.
+     *
+     * @return True there was an assigned OnClickListener that was called, false
+     *         otherwise is returned.
+     */
+    public boolean callOnClick() {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnClickListener != null) {
+            li.mOnClickListener.onClick(this);
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Call this view's OnLongClickListener, if it is defined. Invokes the context menu if the
      * OnLongClickListener did not consume the event.
      *
@@ -3494,8 +3541,9 @@
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
 
         boolean handled = false;
-        if (mOnLongClickListener != null) {
-            handled = mOnLongClickListener.onLongClick(View.this);
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnLongClickListener != null) {
+            handled = li.mOnLongClickListener.onLongClick(View.this);
         }
         if (!handled) {
             handled = showContextMenu();
@@ -3563,7 +3611,7 @@
      * @param l the key listener to attach to this view
      */
     public void setOnKeyListener(OnKeyListener l) {
-        mOnKeyListener = l;
+        getListenerInfo().mOnKeyListener = l;
     }
 
     /**
@@ -3571,7 +3619,7 @@
      * @param l the touch listener to attach to this view
      */
     public void setOnTouchListener(OnTouchListener l) {
-        mOnTouchListener = l;
+        getListenerInfo().mOnTouchListener = l;
     }
 
     /**
@@ -3579,7 +3627,7 @@
      * @param l the generic motion listener to attach to this view
      */
     public void setOnGenericMotionListener(OnGenericMotionListener l) {
-        mOnGenericMotionListener = l;
+        getListenerInfo().mOnGenericMotionListener = l;
     }
 
     /**
@@ -3587,7 +3635,7 @@
      * @param l the hover listener to attach to this view
      */
     public void setOnHoverListener(OnHoverListener l) {
-        mOnHoverListener = l;
+        getListenerInfo().mOnHoverListener = l;
     }
 
     /**
@@ -3598,7 +3646,7 @@
      * @param l An implementation of {@link android.view.View.OnDragListener}.
      */
     public void setOnDragListener(OnDragListener l) {
-        mOnDragListener = l;
+        getListenerInfo().mOnDragListener = l;
     }
 
     /**
@@ -3804,8 +3852,9 @@
         }
 
         invalidate(true);
-        if (mOnFocusChangeListener != null) {
-            mOnFocusChangeListener.onFocusChange(this, gainFocus);
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnFocusChangeListener != null) {
+            li.mOnFocusChangeListener.onFocusChange(this, gainFocus);
         }
 
         if (mAttachInfo != null) {
@@ -4122,10 +4171,12 @@
         bounds.offset(locationOnScreen[0], locationOnScreen[1]);
         info.setBoundsInScreen(bounds);
 
-        ViewParent parent = getParent();
-        if (parent instanceof View) {
-            View parentView = (View) parent;
-            info.setParent(parentView);
+        if ((mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+            ViewParent parent = getParent();
+            if (parent instanceof View) {
+                View parentView = (View) parent;
+                info.setParent(parentView);
+            }
         }
 
         info.setPackageName(mContext.getPackageName());
@@ -5439,8 +5490,9 @@
 
         // Give any attached key listener a first crack at the event.
         //noinspection SimplifiableIfStatement
-        if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
-                && mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+                && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
             return true;
         }
 
@@ -5479,8 +5531,9 @@
 
         if (onFilterTouchEventForSecurity(event)) {
             //noinspection SimplifiableIfStatement
-            if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
-                    mOnTouchListener.onTouch(this, event)) {
+            ListenerInfo li = mListenerInfo;
+            if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+                    && li.mOnTouchListener.onTouch(this, event)) {
                 return true;
             }
 
@@ -5572,8 +5625,10 @@
 
     private boolean dispatchGenericMotionEventInternal(MotionEvent event) {
         //noinspection SimplifiableIfStatement
-        if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
-                && mOnGenericMotionListener.onGenericMotion(this, event)) {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnGenericMotionListener != null
+                && (mViewFlags & ENABLED_MASK) == ENABLED
+                && li.mOnGenericMotionListener.onGenericMotion(this, event)) {
             return true;
         }
 
@@ -5599,8 +5654,10 @@
      */
     protected boolean dispatchHoverEvent(MotionEvent event) {
         //noinspection SimplifiableIfStatement
-        if (mOnHoverListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
-                && mOnHoverListener.onHover(this, event)) {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnHoverListener != null
+                && (mViewFlags & ENABLED_MASK) == ENABLED
+                && li.mOnHoverListener.onHover(this, event)) {
             return true;
         }
 
@@ -5884,7 +5941,8 @@
                 mAttachInfo.mKeepScreenOn = true;
             }
             mAttachInfo.mSystemUiVisibility |= mSystemUiVisibility;
-            if (mOnSystemUiVisibilityChangeListener != null) {
+            ListenerInfo li = mListenerInfo;
+            if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
                 mAttachInfo.mHasSystemUiListeners = true;
             }
         }
@@ -6118,8 +6176,9 @@
         ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo);
 
         onCreateContextMenu(menu);
-        if (mOnCreateContextMenuListener != null) {
-            mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnCreateContextMenuListener != null) {
+            li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
         }
 
         // Clear the extra information so subsequent items that aren't mine don't
@@ -9723,8 +9782,9 @@
         performCollectViewAttributes(visibility);
         onAttachedToWindow();
 
+        ListenerInfo li = mListenerInfo;
         final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
-                mOnAttachStateChangeListeners;
+                li != null ? li.mOnAttachStateChangeListeners : null;
         if (listeners != null && listeners.size() > 0) {
             // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
             // perform the dispatching. The iterator is a safe guard against listeners that
@@ -9756,8 +9816,9 @@
 
         onDetachedFromWindow();
 
+        ListenerInfo li = mListenerInfo;
         final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
-                mOnAttachStateChangeListeners;
+                li != null ? li.mOnAttachStateChangeListeners : null;
         if (listeners != null && listeners.size() > 0) {
             // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
             // perform the dispatching. The iterator is a safe guard against listeners that
@@ -11193,9 +11254,10 @@
             onLayout(changed, l, t, r, b);
             mPrivateFlags &= ~LAYOUT_REQUIRED;
 
-            if (mOnLayoutChangeListeners != null) {
+            ListenerInfo li = mListenerInfo;
+            if (li != null && li.mOnLayoutChangeListeners != null) {
                 ArrayList<OnLayoutChangeListener> listenersCopy =
-                        (ArrayList<OnLayoutChangeListener>) mOnLayoutChangeListeners.clone();
+                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                 int numListeners = listenersCopy.size();
                 for (int i = 0; i < numListeners; ++i) {
                     listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
@@ -13065,7 +13127,7 @@
      * @param l  The {@link OnSystemUiVisibilityChangeListener} to receive callbacks.
      */
     public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {
-        mOnSystemUiVisibilityChangeListener = l;
+        getListenerInfo().mOnSystemUiVisibilityChangeListener = l;
         if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
             mParent.recomputeViewAttributes(this);
         }
@@ -13076,8 +13138,9 @@
      * the view hierarchy.
      */
     public void dispatchSystemUiVisibilityChanged(int visibility) {
-        if (mOnSystemUiVisibilityChangeListener != null) {
-            mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
+            li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(
                     visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK);
         }
     }
@@ -13349,8 +13412,9 @@
      */
     public boolean dispatchDragEvent(DragEvent event) {
         //noinspection SimplifiableIfStatement
-        if (mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
-                && mOnDragListener.onDrag(this, event)) {
+        ListenerInfo li = mListenerInfo;
+        if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+                && li.mOnDragListener.onDrag(this, event)) {
             return true;
         }
         return onDragEvent(event);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 62b20b3..e366e72 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -352,7 +352,7 @@
     private static final int ARRAY_CAPACITY_INCREMENT = 12;
 
     // Used to draw cached views
-    private final Paint mCachePaint = new Paint();
+    private Paint mCachePaint;
 
     // Used to animate add/remove changes in layout
     private LayoutTransition mTransition;
@@ -405,8 +405,6 @@
         mChildren = new View[ARRAY_INITIAL_CAPACITY];
         mChildrenCount = 0;
 
-        mCachePaint.setDither(false);
-
         mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
     }
 
@@ -2231,14 +2229,10 @@
     @Override
     void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        // If the view is not the topmost one in the view hierarchy and it is
-        // marked as the logical root of a view hierarchy, do not go any deeper.
-        if ((!(getParent() instanceof ViewRootImpl)) && (mPrivateFlags & IS_ROOT_NAMESPACE) != 0) {
-            return;
-        }
         for (int i = 0, count = mChildrenCount; i < count; i++) {
             View child = mChildren[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
+                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
                 info.addChild(child);
             }
         }
@@ -2909,6 +2903,11 @@
 
             if (layerType == LAYER_TYPE_NONE) {
                 cachePaint = mCachePaint;
+                if (cachePaint == null) {
+                    cachePaint = new Paint();
+                    cachePaint.setDither(false);
+                    mCachePaint = cachePaint;
+                }
                 if (alpha < 1.0f) {
                     cachePaint.setAlpha((int) (alpha * 255));
                     mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 9cbe8db4..e0403ff 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,8 +16,6 @@
 
 package android.widget;
 
-import com.android.internal.R;
-
 import android.annotation.Widget;
 import android.app.Service;
 import android.content.Context;
@@ -31,7 +29,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
-import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -44,6 +41,8 @@
 import android.view.ViewGroup;
 import android.widget.AbsListView.OnScrollListener;
 
+import com.android.internal.R;
+
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -121,11 +120,6 @@
     private static final int SCROLL_CHANGE_DELAY = 40;
 
     /**
-     * String for formatting the month name in the title text view.
-     */
-    private static final String FORMAT_MONTH_NAME = "MMMM, yyyy";
-
-    /**
      * String for parsing dates.
      */
     private static final String DATE_FORMAT = "MM/dd/yyyy";
@@ -940,11 +934,17 @@
      * @param calendar A day in the new focus month.
      */
     private void setMonthDisplayed(Calendar calendar) {
-        mMonthName.setText(DateFormat.format(FORMAT_MONTH_NAME, calendar));
-        mMonthName.invalidate();
-        mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
-        mAdapter.setFocusMonth(mCurrentMonthDisplayed);
-        // TODO Send Accessibility Event
+        final int newMonthDisplayed = calendar.get(Calendar.MONTH);
+        if (mCurrentMonthDisplayed != newMonthDisplayed) {
+            mCurrentMonthDisplayed = newMonthDisplayed;
+            mAdapter.setFocusMonth(mCurrentMonthDisplayed);
+            final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY
+                    | DateUtils.FORMAT_SHOW_YEAR;
+            final long millis = calendar.getTimeInMillis();
+            String newMonthName = DateUtils.formatDateRange(mContext, millis, millis, flags);
+            mMonthName.setText(newMonthName);
+            mMonthName.invalidate();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 320c650..5ab99dc 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -203,6 +203,11 @@
     private final EditText mInputText;
 
     /**
+     * The min height of this widget.
+     */
+    private final int mMinHeight;
+
+    /**
      * The max height of this widget.
      */
     private final int mMaxHeight;
@@ -210,7 +215,17 @@
     /**
      * The max width of this widget.
      */
-    private final int mMaxWidth;
+    private final int mMinWidth;
+
+    /**
+     * The max width of this widget.
+     */
+    private int mMaxWidth;
+
+    /**
+     * Flag whether to compute the max width.
+     */
+    private final boolean mComputeMaxWidth;
 
     /**
      * The height of the text.
@@ -527,8 +542,19 @@
                 getResources().getDisplayMetrics());
         mSelectionDividerHeight = attributesArray.getDimensionPixelSize(
                 R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight);
-        mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight, 0);
-        mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth, 0);
+        mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, 0);
+        mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight,
+                Integer.MAX_VALUE);
+        if (mMinHeight > mMaxHeight) {
+            throw new IllegalArgumentException("minHeight > maxHeight");
+        }
+        mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, 0);
+        mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth,
+                Integer.MAX_VALUE);
+        if (mMinWidth > mMaxWidth) {
+            throw new IllegalArgumentException("minWidth > maxWidth");
+        }
+        mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
         attributesArray.recycle();
 
         mShowInputControlsAnimimationDuration = getResources().getInteger(
@@ -677,37 +703,33 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mMaxHeight <= 0 && mMaxWidth <= 0) {
-            super.onLayout(changed, left, top, right, bottom);
-        } else {
-            final int msrdWdth = getMeasuredWidth();
-            final int msrdHght = getMeasuredHeight();
+        final int msrdWdth = getMeasuredWidth();
+        final int msrdHght = getMeasuredHeight();
 
-            // Increment button at the top.
-            final int inctBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
-            final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth) / 2;
-            final int incrBtnTop = 0;
-            final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth;
-            final int incrBtnBottom = incrBtnTop + mIncrementButton.getMeasuredHeight();
-            mIncrementButton.layout(incrBtnLeft, incrBtnTop, incrBtnRight, incrBtnBottom);
+        // Increment button at the top.
+        final int inctBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
+        final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth) / 2;
+        final int incrBtnTop = 0;
+        final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth;
+        final int incrBtnBottom = incrBtnTop + mIncrementButton.getMeasuredHeight();
+        mIncrementButton.layout(incrBtnLeft, incrBtnTop, incrBtnRight, incrBtnBottom);
 
-            // Input text centered horizontally.
-            final int inptTxtMsrdWdth = mInputText.getMeasuredWidth();
-            final int inptTxtMsrdHght = mInputText.getMeasuredHeight();
-            final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2;
-            final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2;
-            final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth;
-            final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght;
-            mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom);
+        // Input text centered horizontally.
+        final int inptTxtMsrdWdth = mInputText.getMeasuredWidth();
+        final int inptTxtMsrdHght = mInputText.getMeasuredHeight();
+        final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2;
+        final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2;
+        final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth;
+        final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght;
+        mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom);
 
-            // Decrement button at the top.
-            final int decrBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
-            final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth) / 2;
-            final int decrBtnTop = msrdHght - mDecrementButton.getMeasuredHeight();
-            final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth;
-            final int decrBtnBottom = msrdHght;
-            mDecrementButton.layout(decrBtnLeft, decrBtnTop, decrBtnRight, decrBtnBottom);
-        }
+        // Decrement button at the top.
+        final int decrBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
+        final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth) / 2;
+        final int decrBtnTop = msrdHght - mDecrementButton.getMeasuredHeight();
+        final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth;
+        final int decrBtnBottom = msrdHght;
+        mDecrementButton.layout(decrBtnLeft, decrBtnTop, decrBtnRight, decrBtnBottom);
 
         if (!mScrollWheelAndFadingEdgesInitialized) {
             mScrollWheelAndFadingEdgesInitialized = true;
@@ -719,20 +741,9 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        final int measuredWidth;
-        if (mMaxWidth > 0) {
-            measuredWidth = getMaxSize(widthMeasureSpec, mMaxWidth);
-        } else {
-            measuredWidth = getMeasuredWidth();
-        }
-        final int measuredHeight;
-        if (mMaxHeight > 0) {
-            measuredHeight = getMaxSize(heightMeasureSpec, mMaxHeight);
-        } else {
-            measuredHeight = getMeasuredHeight();
-        }
-        setMeasuredDimension(measuredWidth, measuredHeight);
+        final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMinWidth, mMaxWidth);
+        final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMinHeight, mMaxHeight);
+        super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
     }
 
     @Override
@@ -1034,6 +1045,49 @@
     }
 
     /**
+     * Computes the max width if no such specified as an attribute.
+     */
+    private void tryComputeMaxWidth() {
+        if (!mComputeMaxWidth) {
+            return;
+        }
+        int maxTextWidth = 0;
+        if (mDisplayedValues == null) {
+            float maxDigitWidth = 0;
+            for (int i = 0; i <= 9; i++) {
+                final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i));
+                if (digitWidth > maxDigitWidth) {
+                    maxDigitWidth = digitWidth;
+                }
+            }
+            int numberOfDigits = 0;
+            int current = mMaxValue;
+            while (current > 0) {
+                numberOfDigits++;
+                current = current / 10;
+            }
+            maxTextWidth = (int) (numberOfDigits * maxDigitWidth);
+        } else {
+            final int valueCount = mDisplayedValues.length;
+            for (int i = 0; i < valueCount; i++) {
+                final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]);
+                if (textWidth > maxTextWidth) {
+                    maxTextWidth = (int) textWidth;
+                }
+            }
+        }
+        maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight();
+        if (mMaxWidth != maxTextWidth) {
+            if (maxTextWidth > mMinWidth) {
+                mMaxWidth = maxTextWidth;
+            } else {
+                mMaxWidth = mMinWidth;
+            }
+            invalidate();
+        }
+    }
+
+    /**
      * Gets whether the selector wheel wraps when reaching the min/max value.
      *
      * @return True if the selector wheel wraps.
@@ -1119,6 +1173,7 @@
         setWrapSelectorWheel(wrapSelectorWheel);
         initializeSelectorWheelIndices();
         updateInputTextView();
+        tryComputeMaxWidth();
     }
 
     /**
@@ -1150,6 +1205,7 @@
         setWrapSelectorWheel(wrapSelectorWheel);
         initializeSelectorWheelIndices();
         updateInputTextView();
+        tryComputeMaxWidth();
     }
 
     /**
@@ -1298,24 +1354,28 @@
     }
 
     /**
-     * Gets the max value for a size based on the measure spec passed by
-     * the parent and the max value for that size.
+     * Makes a measure spec that tries greedily to use the max value.
      *
      * @param measureSpec The measure spec.
      * @param maxValue The max value for the size.
-     * @return The max size.
+     * @return A measure spec greedily imposing the max size.
      */
-    private int getMaxSize(int measureSpec, int maxValue) {
+    private int makeMeasureSpec(int measureSpec, int minValue, int maxValue) {
+        final int size = MeasureSpec.getSize(measureSpec);
+        if (size < minValue) {
+            throw new IllegalArgumentException("Available space is less than min size: "
+                    +  size + " < " + minValue);
+        }
         final int mode = MeasureSpec.getMode(measureSpec);
         switch (mode) {
             case MeasureSpec.EXACTLY:
-                return MeasureSpec.getSize(measureSpec);
+                return measureSpec;
             case MeasureSpec.AT_MOST:
-                return Math.min(MeasureSpec.getSize(measureSpec), maxValue);
+                return MeasureSpec.makeMeasureSpec(Math.min(size, maxValue), MeasureSpec.EXACTLY);
             case MeasureSpec.UNSPECIFIED:
-                return maxValue;
+                return MeasureSpec.makeMeasureSpec(maxValue, MeasureSpec.EXACTLY);
             default:
-                throw new IllegalArgumentException();
+                throw new IllegalArgumentException("Unknown measure mode: " + mode);
         }
     }
 
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 6df80e4..399d217 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1187,6 +1187,8 @@
      */
     @Override
     public void onActionViewExpanded() {
+        if (mExpandedInActionView) return;
+
         mExpandedInActionView = true;
         mCollapsedImeOptions = mQueryTextView.getImeOptions();
         mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9257534..a8680d4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -271,7 +271,7 @@
     private static final int SIGNED = 2;
     private static final int DECIMAL = 4;
 
-    class Drawables {
+    static class Drawables {
         final Rect mCompoundRect = new Rect();
         Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
                 mDrawableStart, mDrawableEnd;
@@ -304,7 +304,7 @@
 
     private int mMarqueeRepeatLimit = 3;
 
-    class InputContentType {
+    static class InputContentType {
         int imeOptions = EditorInfo.IME_NULL;
         String privateImeOptions;
         CharSequence imeActionLabel;
@@ -315,7 +315,7 @@
     }
     InputContentType mInputContentType;
 
-    class InputMethodState {
+    static class InputMethodState {
         Rect mCursorRectInWindow = new Rect();
         RectF mTmpRectF = new RectF();
         float[] mTmpOffset = new float[2];
@@ -5363,7 +5363,7 @@
                     // don't let it be inserted into the text.
                     if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0
                             || shouldAdvanceFocusOnEnter()) {
-                        if (mOnClickListener != null) {
+                        if (hasOnClickListeners()) {
                             return 0;
                         }
                         return -1;
@@ -5497,7 +5497,7 @@
                      * call performClick(), but that won't do anything in
                      * this case.)
                      */
-                    if (mOnClickListener == null) {
+                    if (hasOnClickListeners()) {
                         if (mMovement != null && mText instanceof Editable
                                 && mLayout != null && onCheckIsTextEditor()) {
                             InputMethodManager imm = InputMethodManager.peekInstance();
@@ -5535,7 +5535,7 @@
                          * call performClick(), but that won't do anything in
                          * this case.)
                          */
-                        if (mOnClickListener == null) {
+                        if (hasOnClickListeners()) {
                             View v = focusSearch(FOCUS_DOWN);
 
                             if (v != null) {
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index c5fa18c..eb372ca 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -29,8 +29,8 @@
     private final Handler mHandler;
     private final Runnable mRunnable = new Runnable() {
         public void run() {
-            if ((mOnClickListener != null) && mIsInLongpress && isEnabled()) {
-                mOnClickListener.onClick(ZoomButton.this);
+            if (hasOnClickListeners() && mIsInLongpress && isEnabled()) {
+                callOnClick();
                 mHandler.postDelayed(this, mZoomSpeed);
             }
         }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 8ee1d8b..79aa43b 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -444,7 +444,11 @@
                     LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d",
                             dirFlags, rc, paraDir);
 #endif
-                    if (!U_SUCCESS(status) || rc <= 1) {
+                    if (U_SUCCESS(status) && rc == 1) {
+                        // Normal case: one run, status is ok
+                        isRTL = (paraDir == 1);
+                        useSingleRun = true;
+                    } else if (!U_SUCCESS(status) || rc < 1) {
                         LOGW("computeValuesWithHarfbuzz -- need to force to single run");
                         isRTL = (paraDir == 1);
                         useSingleRun = true;
diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
index 004d52a..f9b247f 100644
--- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
@@ -22,4 +22,6 @@
     android:layout_gravity="center_horizontal"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:spinnersShown="true"
+    android:calendarViewShown="true"
     />
diff --git a/core/res/res/layout-sw600dp/number_picker.xml b/core/res/res/layout-sw600dp/number_picker.xml
deleted file mode 100644
index 807daf2..0000000
--- a/core/res/res/layout-sw600dp/number_picker.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <ImageButton android:id="@+id/increment"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/numberPickerUpButtonStyle"
-        android:contentDescription="@string/number_picker_increment_button" />
-
-    <EditText android:id="@+id/numberpicker_input"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/numberPickerInputTextStyle" />
-
-    <ImageButton android:id="@+id/decrement"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/numberPickerDownButtonStyle"
-        android:contentDescription="@string/number_picker_decrement_button" />
-
-</merge>
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index 1649466..6f0517d 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -40,7 +40,7 @@
         <!-- Month -->
         <NumberPicker
             android:id="@+id/month"
-            android:layout_width="80dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginLeft="1dip"
             android:layout_marginRight="1dip"
@@ -51,7 +51,7 @@
         <!-- Day -->
         <NumberPicker
             android:id="@+id/day"
-            android:layout_width="80dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginLeft="1dip"
             android:layout_marginRight="1dip"
@@ -62,7 +62,7 @@
         <!-- Year -->
         <NumberPicker
             android:id="@+id/year"
-            android:layout_width="95dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginLeft="1dip"
             android:layout_marginRight="1dip"
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
index 8627637..57b5614 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -23,8 +23,8 @@
      depending on the date format selected by the user.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:orientation="horizontal"
     android:gravity="center">
@@ -32,7 +32,6 @@
     <LinearLayout android:id="@+id/pickers"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginRight="22dip"
         android:layout_weight="1"
         android:orientation="horizontal"
         android:gravity="center">
@@ -40,10 +39,10 @@
         <!-- Month -->
         <NumberPicker
             android:id="@+id/month"
-            android:layout_width="48dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -51,10 +50,10 @@
         <!-- Day -->
         <NumberPicker
             android:id="@+id/day"
-            android:layout_width="48dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
@@ -62,10 +61,10 @@
         <!-- Year -->
         <NumberPicker
             android:id="@+id/year"
-            android:layout_width="48dip"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="22dip"
-            android:layout_marginRight="22dip"
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index ca6fe2d..29c97b7 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -28,10 +28,10 @@
     <!-- hour -->
     <NumberPicker
         android:id="@+id/hour"
-        android:layout_width="48dip"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="22dip"
-        android:layout_marginRight="20dip"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="14dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
@@ -47,10 +47,10 @@
     <!-- minute -->
     <NumberPicker
         android:id="@+id/minute"
-        android:layout_width="48dip"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="20dip"
-        android:layout_marginRight="22dip"
+        android:layout_marginLeft="14dip"
+        android:layout_marginRight="16dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
@@ -58,10 +58,10 @@
     <!-- AM / PM -->
     <NumberPicker
         android:id="@+id/amPm"
-        android:layout_width="48dip"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="22dip"
-        android:layout_marginRight="22dip"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
         android:focusable="true"
         android:focusableInTouchMode="true"
         />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 936482df..a40e24c 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3576,8 +3576,14 @@
         <attr name="selectionDivider" format="reference" />
         <!-- @hide The height of the selection divider. -->
         <attr name="selectionDividerHeight" format="dimension" />
+        <!-- @hide The min height of the NumberPicker. -->
+        <attr name="minHeight" />
         <!-- @hide The max height of the NumberPicker. -->
         <attr name="maxHeight" />
+        <!-- @hide The min width of the NumberPicker. -->
+        <attr name="minWidth" />
+        <!-- @hide The max width of the NumberPicker. -->
+        <attr name="maxWidth" />
         <!-- @hide The max width of the NumberPicker. -->
         <attr name="maxWidth" />
     </declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bde2c72..48e8f1e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -182,12 +182,14 @@
     <!-- Regex of wired ethernet ifaces -->
     <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
 
-    <!-- If the mobile hotspot feature requires provisioning, an intent string can be provided
-        to the launch a supported application that provisions the devices.
+    <!-- If the mobile hotspot feature requires provisioning, a package name and class name
+        can be provided to launch a supported application that provisions the devices.
 
         Example Usage:
 
-        Intent intent = new Intent(R.string.config_mobile_hotspot_provision_intent);
+        String[] appDetails = getStringArray(R.array.config_mobile_hotspot_provision_app);
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(appDetails[0], appDetails[1]);
         startActivityForResult(intent, 0);
 
         public void onActivityResult(int requestCode, int resultCode, Intent intent) {
@@ -202,7 +204,14 @@
 
         See src/com/android/settings/TetherSettings.java for more details.
         -->
-    <string translatable="false" name="config_mobile_hotspot_provision_intent"></string>
+    <!-- The first element is the package name and the second element is the class name
+         of the provisioning app -->
+    <string-array translatable="false" name="config_mobile_hotspot_provision_app">
+    <!--
+        <item>com.example.provisioning</item>
+        <item>com.example.provisioning.Activity</item>
+    -->
+    </string-array>
 
     <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
     <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 8356985..8d95d86e5 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1654,8 +1654,8 @@
         <item name="android:flingable">true</item>
         <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item>
         <item name="android:selectionDividerHeight">2dip</item>
-        <item name="android:maxHeight">180dip</item>
-        <item name="android:maxWidth">56dip</item>
+        <item name="android:minWidth">48dip</item>
+        <item name="android:maxHeight">200dip</item>
     </style>
 
     <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
@@ -1684,6 +1684,8 @@
     <style name="Widget.Holo.EditText.NumberPickerInputText">
         <item name="android:paddingTop">13sp</item>
         <item name="android:paddingBottom">13sp</item>
+        <item name="android:paddingLeft">2sp</item>
+        <item name="android:paddingRight">2sp</item>
         <item name="android:gravity">center</item>
         <item name="android:singleLine">true</item>
         <item name="android:textSize">18sp</item>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 20ce701..61337b7 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -321,6 +321,10 @@
   <li>{@link android.widget.ProgressBar}</li>
   <li>{@link android.widget.TextView}</li>
   <li>{@link android.widget.ViewFlipper}</li>
+  <li>{@link android.widget.ListView}</li>
+  <li>{@link android.widget.GridView}</li>
+  <li>{@link android.widget.StackView}</li>
+  <li>{@link android.widget.AdapterViewFlipper}</li>
 </ul>
 
 <p>Descendants of these classes are not supported.</p>
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f8a7d6a..310ace0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -408,6 +408,12 @@
     ProcessRecord mHomeProcess;
     
     /**
+     * This is the process holding the activity the user last visited that
+     * is in a different process from the one they are currently in.
+     */
+    ProcessRecord mPreviousProcess;
+    
+    /**
      * Packages that the user has asked to have run in screen size
      * compatibility mode instead of filling the screen.
      */
@@ -8114,6 +8120,7 @@
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
+        pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (mHeavyWeightProcess != null) {
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
@@ -8212,6 +8219,7 @@
             pw.print("    BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
             pw.print("    SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ);
             pw.print("    HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
+            pw.print("    PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ);
             pw.print("    SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ);
             pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ);
             pw.print("    HIDDEN_APP_MAX_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MAX_ADJ);
@@ -8228,6 +8236,7 @@
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
+        pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (mHeavyWeightProcess != null) {
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
@@ -9009,6 +9018,8 @@
                 oomAdj = buildOomTag("bak", "  ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ);
             } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
                 oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
+            } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+                oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
             } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
                 oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
             } else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
@@ -9287,12 +9298,13 @@
             ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
             ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
             ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
-            ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
+            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
         };
         final String[] oomLabel = new String[] {
                 "System", "Persistent", "Foreground",
                 "Visible", "Perceptible", "Heavy Weight",
-                "Backup", "A Services", "Home", "B Services", "Background"
+                "Backup", "A Services", "Home", "Previous",
+                "B Services", "Background"
         };
         long oomPss[] = new long[oomLabel.length];
         ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])new ArrayList[oomLabel.length];
@@ -9714,7 +9726,10 @@
         if (app == mHomeProcess) {
             mHomeProcess = null;
         }
-        
+        if (app == mPreviousProcess) {
+            mPreviousProcess = null;
+        }
+
         if (restart) {
             // We have components that still need to be running in the
             // process, so re-launch it.
@@ -13112,6 +13127,17 @@
             app.adjType = "home";
         }
 
+        if (adj > ProcessList.PREVIOUS_APP_ADJ && app == mPreviousProcess
+                && app.activities.size() > 0) {
+            // This was the previous process that showed UI to the user.
+            // We want to try to keep it around more aggressively, to give
+            // a good experience around switching between two apps.
+            adj = ProcessList.PREVIOUS_APP_ADJ;
+            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.hidden = false;
+            app.adjType = "previous";
+        }
+
         if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
                 + " reason=" + app.adjType);
 
@@ -13841,7 +13867,8 @@
                     } else {
                         numBg++;
                     }
-                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
+                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ
+                        && app.curAdj != ProcessList.SERVICE_B_ADJ) {
                     numBg++;
                 }
             }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 28c3bae..a47502e 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1363,6 +1363,13 @@
                         + ", nowVisible=" + next.nowVisible);
                 }
             }
+
+            if (!prev.finishing && prev.app != null && prev.app != next.app) {
+                // We are switching to a new activity that is in a different
+                // process than the previous one.  Note the previous process,
+                // so we can try to keep it around.
+                mService.mPreviousProcess = prev.app;
+            }
         }
 
         // Launching this app's activity, make sure the app is no longer
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index f368a70..af7b314 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -38,11 +38,19 @@
     // This is a process only hosting activities that are not visible,
     // so it can be killed without any disruption.
     static final int HIDDEN_APP_MAX_ADJ = 15;
-    static int HIDDEN_APP_MIN_ADJ = 8;
+    static int HIDDEN_APP_MIN_ADJ = 9;
 
     // The B list of SERVICE_ADJ -- these are the old and decrepit
     // services that aren't as shiny and interesting as the ones in the A list.
-    static final int SERVICE_B_ADJ = 7;
+    static final int SERVICE_B_ADJ = 8;
+
+    // This is the process of the previous application that the user was in.
+    // This process is kept above other things, because it is very common to
+    // switch back to the previous app.  This is important both for recent
+    // task switch (toggling between the two top recent apps) as well as normal
+    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
+    // and then pressing back to return to e-mail.
+    static final int PREVIOUS_APP_ADJ = 7;
 
     // This is a process holding the home application -- we want to try
     // avoiding killing it, even if it would normally be in the background,
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index e610782..bdad82a 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -186,8 +186,10 @@
 
     private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
 
-    private static final int MSG_RULES_CHANGED = 0x1;
-    private static final int MSG_METERED_IFACES_CHANGED = 0x2;
+    private static final int MSG_RULES_CHANGED = 1;
+    private static final int MSG_METERED_IFACES_CHANGED = 2;
+    private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3;
+    private static final int MSG_PROCESS_DIED = 4;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -335,37 +337,13 @@
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
         @Override
         public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
-            // only someone like AMS should only be calling us
-            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
-
-            synchronized (mRulesLock) {
-                // because a uid can have multiple pids running inside, we need to
-                // remember all pid states and summarize foreground at uid level.
-
-                // record foreground for this specific pid
-                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
-                if (pidForeground == null) {
-                    pidForeground = new SparseBooleanArray(2);
-                    mUidPidForeground.put(uid, pidForeground);
-                }
-                pidForeground.put(pid, foregroundActivities);
-                computeUidForegroundLocked(uid);
-            }
+            mHandler.obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED,
+                    pid, uid, foregroundActivities).sendToTarget();
         }
 
         @Override
         public void onProcessDied(int pid, int uid) {
-            // only someone like AMS should only be calling us
-            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
-
-            synchronized (mRulesLock) {
-                // clear records and recompute, when they exist
-                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
-                if (pidForeground != null) {
-                    pidForeground.delete(pid);
-                    computeUidForegroundLocked(uid);
-                }
-            }
+            mHandler.obtainMessage(MSG_PROCESS_DIED, pid, uid).sendToTarget();
         }
     };
 
@@ -1469,6 +1447,40 @@
                     mListeners.finishBroadcast();
                     return true;
                 }
+                case MSG_FOREGROUND_ACTIVITIES_CHANGED: {
+                    final int pid = msg.arg1;
+                    final int uid = msg.arg2;
+                    final boolean foregroundActivities = (Boolean) msg.obj;
+
+                    synchronized (mRulesLock) {
+                        // because a uid can have multiple pids running inside, we need to
+                        // remember all pid states and summarize foreground at uid level.
+
+                        // record foreground for this specific pid
+                        SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+                        if (pidForeground == null) {
+                            pidForeground = new SparseBooleanArray(2);
+                            mUidPidForeground.put(uid, pidForeground);
+                        }
+                        pidForeground.put(pid, foregroundActivities);
+                        computeUidForegroundLocked(uid);
+                    }
+                    return true;
+                }
+                case MSG_PROCESS_DIED: {
+                    final int pid = msg.arg1;
+                    final int uid = msg.arg2;
+
+                    synchronized (mRulesLock) {
+                        // clear records and recompute, when they exist
+                        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+                        if (pidForeground != null) {
+                            pidForeground.delete(pid);
+                            computeUidForegroundLocked(uid);
+                        }
+                    }
+                    return true;
+                }
                 default: {
                     return false;
                 }
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index c3fc837..aa663f3 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -3,7 +3,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-sdk android:minSdkVersion="5" />
 
-    <application>
+    <application android:hardwareAccelerated="false">
         <activity android:name="FrameworkPerfActivity" android:label="Framework Perf">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/tests/FrameworkPerf/res/layout/main.xml b/tests/FrameworkPerf/res/layout/main.xml
index 8b54118..62b1a7a 100644
--- a/tests/FrameworkPerf/res/layout/main.xml
+++ b/tests/FrameworkPerf/res/layout/main.xml
@@ -64,6 +64,23 @@
         android:orientation="horizontal"
         android:layout_marginTop="10dp"
         >
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:text="Test time (ms): "
+            />
+        <EditText android:id="@+id/testtime"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="number"
+            android:text="5000"
+        />
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_marginTop="10dp"
+        >
         <Button android:id="@+id/start"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
index 66e788c..5e15224 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
@@ -58,6 +58,7 @@
     Spinner mFgSpinner;
     Spinner mBgSpinner;
     TextView mLog;
+    TextView mTestTime;
     PowerManager.WakeLock mPartialWakeLock;
 
     long mMaxRunTime = 5000;
@@ -110,6 +111,7 @@
     };
 
     final Op[] mAvailOps = new Op[] {
+            null,
             new NoOp(),
             new CpuOp(),
             new SchedulerOp(),
@@ -122,6 +124,8 @@
             new ReadFileOp(),
             new ParseXmlResOp(),
             new ParseLargeXmlResOp(),
+            new LayoutInflaterOp(),
+            new LayoutInflaterLargeOp(),
             new LoadSmallBitmapOp(),
             new LoadLargeBitmapOp(),
             new LoadSmallScaledBitmapOp(),
@@ -170,11 +174,14 @@
         mAvailOpDescriptions = new String[mAvailOps.length];
         for (int i=0; i<mAvailOps.length; i++) {
             Op op = mAvailOps[i];
-            if (op.getClass() == NoOp.class) {
+            if (op == null) {
                 mAvailOpLabels[i] = "All";
                 mAvailOpDescriptions[i] = "All tests";
             } else {
                 mAvailOpLabels[i] = op.getName();
+                if (mAvailOpLabels[i] == null) {
+                    mAvailOpLabels[i] = "Nothing";
+                }
                 mAvailOpDescriptions[i] = op.getLongName();
             }
         }
@@ -211,6 +218,7 @@
                 stopRunning();
             }
         });
+        mTestTime = (TextView)findViewById(R.id.testtime);
         mLog = (TextView)findViewById(R.id.log);
 
         PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
@@ -221,11 +229,7 @@
     @Override
     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         if (parent == mFgSpinner || parent == mBgSpinner) {
-            Spinner spinner = (Spinner)parent;
             Op op = mAvailOps[position];
-            if (op.getClass() == NoOp.class) {
-                op = null;
-            }
             if (parent == mFgSpinner) {
                 mFgTest = op;
                 ((TextView)findViewById(R.id.fgtext)).setText(mAvailOpDescriptions[position]);
@@ -238,8 +242,6 @@
 
     @Override
     public void onNothingSelected(AdapterView<?> parent) {
-        // TODO Auto-generated method stub
-        
     }
 
     @Override
@@ -314,6 +316,7 @@
             updateWakeLock();
             startService(new Intent(this, SchedulerService.class));
             mCurOpIndex = 0;
+            mMaxRunTime = Integer.parseInt(mTestTime.getText().toString());
             mResults.clear();
             startCurOp();
         }