Merge "Factor viewport scaling into coverage calculation"
diff --git a/api/current.txt b/api/current.txt
index 541ce51..665b054 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2864,6 +2864,12 @@
     field public android.content.ComponentName topActivity;
   }
 
+  public class ActivityOptions {
+    method public void join(android.app.ActivityOptions);
+    method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
+    method public android.os.Bundle toBundle();
+  }
+
   public class AlarmManager {
     method public void cancel(android.app.PendingIntent);
     method public void set(int, long, android.app.PendingIntent);
@@ -3728,7 +3734,9 @@
     method public void cancel();
     method public int describeContents();
     method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent[], int);
+    method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent[], int, android.os.Bundle);
     method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int);
+    method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle);
     method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int);
     method public android.content.IntentSender getIntentSender();
     method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
@@ -23592,10 +23600,10 @@
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
     field public static final int LAYER_TYPE_NONE = 0; // 0x0
     field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
-    field public static final int LAYOUT_DIRECTION_INHERIT = -2147483648; // 0x80000000
-    field public static final int LAYOUT_DIRECTION_LOCALE = -1073741824; // 0xc0000000
-    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
-    field public static final int LAYOUT_DIRECTION_RTL = 1073741824; // 0x40000000
+    field public static final int LAYOUT_DIRECTION_INHERIT = 4; // 0x4
+    field public static final int LAYOUT_DIRECTION_LOCALE = 8; // 0x8
+    field public static final int LAYOUT_DIRECTION_LTR = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_RTL = 2; // 0x2
     field public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
     field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
     field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
@@ -26950,7 +26958,6 @@
     method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
     method public void setValue(int);
     method public void setWrapSelectorWheel(boolean);
-    field public static final int SELECTOR_WHEEL_ITEM_COUNT = 5; // 0x5
   }
 
   public static abstract interface NumberPicker.Formatter {
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 28b7dd3..cf1e8f3 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1780,7 +1780,7 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
             }
-            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE, mAccounts.userId)) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
                 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index dc12acd..ea32745 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -32,7 +32,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.content.res.Resources.Theme;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -55,7 +54,6 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -3208,7 +3206,8 @@
      * @param requestCode If >= 0, this code will be returned in
      *                    onActivityResult() when the activity exits.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      *
      * @throws android.content.ActivityNotFoundException
      *
@@ -3288,7 +3287,10 @@
      * <var>flagsMask</var>
      * @param extraFlags Always set to 0.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.  If options
+     * have also been supplied by the IntentSender, options given here will
+     * override any that conflict with those given by the IntentSender.
      */
     public void startIntentSenderForResult(IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
@@ -3369,7 +3371,8 @@
      * 
      * @param intent The intent to start. 
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      * 
      * @throws android.content.ActivityNotFoundException
      *
@@ -3417,7 +3420,8 @@
      *
      * @param intents The intents to start.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      *
      * @throws android.content.ActivityNotFoundException
      *
@@ -3465,7 +3469,10 @@
      * <var>flagsMask</var>
      * @param extraFlags Always set to 0.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.  If options
+     * have also been supplied by the IntentSender, options given here will
+     * override any that conflict with those given by the IntentSender.
      */
     public void startIntentSender(IntentSender intent,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
@@ -3521,7 +3528,8 @@
      *         onActivityResult() when the activity exits, as described in
      *         {@link #startActivityForResult}.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      * 
      * @return If a new activity was launched then true is returned; otherwise
      *         false is returned and you must handle the Intent yourself.
@@ -3592,7 +3600,8 @@
      * your own activity; the only changes you can make are to the extras
      * inside of it.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      * 
      * @return Returns a boolean indicating whether there was another Activity
      * to start: true if there was a next activity to start, false if there
@@ -3644,7 +3653,8 @@
      * @param intent The intent to start.
      * @param requestCode Reply request code.  < 0 if reply is not requested.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      * 
      * @throws android.content.ActivityNotFoundException
      * 
@@ -3694,7 +3704,8 @@
      * @param intent The intent to start.
      * @param requestCode Reply request code.  < 0 if reply is not requested. 
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      * 
      * @throws android.content.ActivityNotFoundException
      * 
@@ -3744,6 +3755,14 @@
      * Call immediately after one of the flavors of {@link #startActivity(Intent)}
      * or {@link #finish} to specify an explicit transition animation to
      * perform next.
+     *
+     * <p>As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN} an alternative
+     * to using this with starting activities is to supply the desired animation
+     * information through a {@link ActivityOptions} bundle to
+     * {@link #startActivity(Intent, Bundle) or a related function.  This allows
+     * you to specify a custom animation even when starting an activity from
+     * outside the context of the current top activity.
+     *
      * @param enterAnim A resource ID of the animation resource to use for
      * the incoming activity.  Use 0 for no animation.
      * @param exitAnim A resource ID of the animation resource to use for
@@ -4065,7 +4084,7 @@
                 ActivityManagerNative.getDefault().getIntentSender(
                         ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
                         mParent == null ? mToken : mParent.mToken,
-                        mEmbeddedID, requestCode, new Intent[] { data }, null, flags);
+                        mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null);
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
             // Empty
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 732d211..a3cc352 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -835,9 +835,11 @@
                 requestResolvedTypes = null;
             }
             int fl = data.readInt();
+            Bundle options = data.readInt() != 0
+                    ? Bundle.CREATOR.createFromParcel(data) : null;
             IIntentSender res = getIntentSender(type, packageName, token,
                     resultWho, requestCode, requestIntents,
-                    requestResolvedTypes, fl);
+                    requestResolvedTypes, fl, options);
             reply.writeNoException();
             reply.writeStrongBinder(res != null ? res.asBinder() : null);
             return true;
@@ -2607,8 +2609,8 @@
     }
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags)
-            throws RemoteException {
+            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+            Bundle options) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2625,6 +2627,12 @@
             data.writeInt(0);
         }
         data.writeInt(flags);
+        if (options != null) {
+            data.writeInt(1);
+            options.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
         mRemote.transact(GET_INTENT_SENDER_TRANSACTION, data, reply, 0);
         reply.readException();
         IIntentSender res = IIntentSender.Stub.asInterface(
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
new file mode 100644
index 0000000..03bc338
--- /dev/null
+++ b/core/java/android/app/ActivityOptions.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Helper class for building an options Bundle that can be used with
+ * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
+ * Context.startActivity(Intent, Bundle)} and related methods.
+ */
+public class ActivityOptions {
+    /**
+     * The package name that created the options.
+     * @hide
+     */
+    public static final String KEY_PACKAGE_NAME = "android:packageName";
+
+    /**
+     * Custom enter animation resource ID.
+     * @hide
+     */
+    public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes";
+
+    /**
+     * Custom exit animation resource ID.
+     * @hide
+     */
+    public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
+
+    private String mPackageName;
+    private boolean mIsCustomAnimation;
+    private int mCustomEnterResId;
+    private int mCustomExitResId;
+
+    /**
+     * Create an ActivityOptions specifying a custom animation to run when
+     * the activity is displayed.
+     *
+     * @param context Who is defining this.  This is the application that the
+     * animation resources will be loaded from.
+     * @param enterResId A resource ID of the animation resource to use for
+     * the incoming activity.  Use 0 for no animation.
+     * @param exitResId A resource ID of the animation resource to use for
+     * the outgoing activity.  Use 0 for no animation.
+     * @return Returns a new ActivityOptions object that you can use to
+     * supply these options as the options Bundle when starting an activity.
+     */
+    public static ActivityOptions makeCustomAnimation(Context context,
+            int enterResId, int exitResId) {
+        ActivityOptions opts = new ActivityOptions();
+        opts.mPackageName = context.getPackageName();
+        opts.mIsCustomAnimation = true;
+        opts.mCustomEnterResId = enterResId;
+        opts.mCustomExitResId = exitResId;
+        return opts;
+    }
+
+    private ActivityOptions() {
+    }
+
+    /** @hide */
+    public ActivityOptions(Bundle opts) {
+        mPackageName = opts.getString(KEY_PACKAGE_NAME);
+        if (opts.containsKey(KEY_ANIM_ENTER_RES_ID)) {
+            mIsCustomAnimation = true;
+            mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
+            mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+        }
+    }
+
+    /** @hide */
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /** @hide */
+    public boolean isCustomAnimation() {
+        return mIsCustomAnimation;
+    }
+
+    /** @hide */
+    public int getCustomEnterResId() {
+        return mCustomEnterResId;
+    }
+
+    /** @hide */
+    public int getCustomExitResId() {
+        return mCustomExitResId;
+    }
+
+    /**
+     * Join the values in <var>otherOptions</var> in to this one.  Any values
+     * defined in <var>otherOptions</var> replace those in the base options.
+     */
+    public void join(ActivityOptions otherOptions) {
+        if (otherOptions.mPackageName != null) {
+            mPackageName = otherOptions.mPackageName;
+        }
+        if (otherOptions.mIsCustomAnimation) {
+            mIsCustomAnimation = true;
+            mCustomEnterResId = otherOptions.mCustomEnterResId;
+            mCustomExitResId = otherOptions.mCustomExitResId;
+        }
+    }
+
+    /**
+     * Returns the created options as a Bundle, which can be passed to
+     * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
+     * Context.startActivity(Intent, Bundle)} and related methods.
+     * Note that the returned Bundle is still owned by the ActivityOptions
+     * object; you must not modify it, but can supply it to the startActivity
+     * methods that take an options Bundle.
+     */
+    public Bundle toBundle() {
+        Bundle b = new Bundle();
+        if (mPackageName != null) {
+            b.putString(KEY_PACKAGE_NAME, mPackageName);
+        }
+        if (mIsCustomAnimation) {
+            b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
+            b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
+        }
+        return b;
+    }
+}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index dadc4e5..c493f0f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -965,6 +965,8 @@
     /**
      * Call {@link Activity#startActivity(Intent)} on the fragment's
      * containing Activity.
+     *
+     * @param intent The intent to start.
      */
     public void startActivity(Intent intent) {
         startActivity(intent, null);
@@ -973,6 +975,11 @@
     /**
      * Call {@link Activity#startActivity(Intent, Bundle)} on the fragment's
      * containing Activity.
+     *
+     * @param intent The intent to start.
+     * @param options Additional options for how the Activity should be started.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      */
     public void startActivity(Intent intent, Bundle options) {
         if (mActivity == null) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9306bd2..31066b5 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -169,7 +169,7 @@
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes,
-            int flags) throws RemoteException;
+            int flags, Bundle options) throws RemoteException;
     public void cancelIntentSender(IIntentSender sender) throws RemoteException;
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, int userId) throws RemoteException;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 57192c3..aa366b6 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -188,6 +188,35 @@
      */
     public static PendingIntent getActivity(Context context, int requestCode,
             Intent intent, int flags) {
+        return getActivity(context, requestCode, intent, flags, null);
+    }
+
+    /**
+     * Retrieve a PendingIntent that will start a new activity, like calling
+     * {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
+     * Note that the activity will be started outside of the context of an
+     * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK
+     * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent.
+     *
+     * @param context The Context in which this PendingIntent should start
+     * the activity.
+     * @param requestCode Private request code for the sender (currently
+     * not used).
+     * @param intent Intent of the activity to be launched.
+     * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
+     * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
+     * or any of the flags as supported by
+     * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
+     * of the intent that can be supplied when the actual send happens.
+     * @param options Additional options for how the Activity should be started.
+     * May be null if there are no options.
+     *
+     * @return Returns an existing or new PendingIntent matching the given
+     * parameters.  May return null only if {@link #FLAG_NO_CREATE} has been
+     * supplied.
+     */
+    public static PendingIntent getActivity(Context context, int requestCode,
+            Intent intent, int flags, Bundle options) {
         String packageName = context.getPackageName();
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
@@ -197,7 +226,8 @@
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                     null, null, requestCode, new Intent[] { intent },
-                    resolvedType != null ? new String[] { resolvedType } : null, flags);
+                    resolvedType != null ? new String[] { resolvedType } : null,
+                    flags, options);
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
         }
@@ -247,6 +277,52 @@
      */
     public static PendingIntent getActivities(Context context, int requestCode,
             Intent[] intents, int flags) {
+        return getActivities(context, requestCode, intents, flags, null);
+    }
+
+    /**
+     * Like {@link #getActivity(Context, int, Intent, int)}, but allows an
+     * array of Intents to be supplied.  The first Intent in the array is
+     * taken as the primary key for the PendingIntent, like the single Intent
+     * given to {@link #getActivity(Context, int, Intent, int)}.  Upon sending
+     * the resulting PendingIntent, all of the Intents are started in the same
+     * way as they would be by passing them to {@link Context#startActivities(Intent[])}.
+     *
+     * <p class="note">
+     * The <em>first</em> intent in the array will be started outside of the context of an
+     * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK
+     * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent.  (Activities after
+     * the first in the array are started in the context of the previous activity
+     * in the array, so FLAG_ACTIVITY_NEW_TASK is not needed nor desired for them.)
+     * </p>
+     *
+     * <p class="note">
+     * The <em>last</em> intent in the array represents the key for the
+     * PendingIntent.  In other words, it is the significant element for matching
+     * (as done with the single intent given to {@link #getActivity(Context, int, Intent, int)},
+     * its content will be the subject of replacement by
+     * {@link #send(Context, int, Intent)} and {@link #FLAG_UPDATE_CURRENT}, etc.
+     * This is because it is the most specific of the supplied intents, and the
+     * UI the user actually sees when the intents are started.
+     * </p>
+     *
+     * @param context The Context in which this PendingIntent should start
+     * the activity.
+     * @param requestCode Private request code for the sender (currently
+     * not used).
+     * @param intents Array of Intents of the activities to be launched.
+     * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
+     * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
+     * or any of the flags as supported by
+     * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
+     * of the intent that can be supplied when the actual send happens.
+     *
+     * @return Returns an existing or new PendingIntent matching the given
+     * parameters.  May return null only if {@link #FLAG_NO_CREATE} has been
+     * supplied.
+     */
+    public static PendingIntent getActivities(Context context, int requestCode,
+            Intent[] intents, int flags, Bundle options) {
         String packageName = context.getPackageName();
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
@@ -257,7 +333,7 @@
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
-                    null, null, requestCode, intents, resolvedTypes, flags);
+                    null, null, requestCode, intents, resolvedTypes, flags, options);
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
         }
@@ -294,7 +370,8 @@
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_BROADCAST, packageName,
                     null, null, requestCode, new Intent[] { intent },
-                    resolvedType != null ? new String[] { resolvedType } : null, flags);
+                    resolvedType != null ? new String[] { resolvedType } : null,
+                    flags, null);
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
         }
@@ -332,7 +409,8 @@
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_SERVICE, packageName,
                     null, null, requestCode, new Intent[] { intent },
-                    resolvedType != null ? new String[] { resolvedType } : null, flags);
+                    resolvedType != null ? new String[] { resolvedType } : null,
+                    flags, null);
             return target != null ? new PendingIntent(target) : null;
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 19a5bc0..741a6e9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -846,7 +846,9 @@
      *
      * @param intent The description of the activity to start.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * May be null if there are no options.  See {@link android.app.ActivityOptions}
+     * for how to build the Bundle supplied here; there are no supported definitions
+     * for building it manually.
      *
      * @throws ActivityNotFoundException
      *
@@ -884,7 +886,8 @@
      *
      * @param intents An array of Intents to be started.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.
      *
      * @throws ActivityNotFoundException
      *
@@ -930,7 +933,10 @@
      * <var>flagsMask</var>
      * @param extraFlags Always set to 0.
      * @param options Additional options for how the Activity should be started.
-     * May be null if there are no options.
+     * See {@link android.content.Context#startActivity(Intent, Bundle)
+     * Context.startActivity(Intent, Bundle)} for more details.  If options
+     * have also been supplied by the IntentSender, options given here will
+     * override any that conflict with those given by the IntentSender.
      *
      * @see #startActivity(Intent, Bundle)
      * @see #startIntentSender(IntentSender, Intent, int, int, int)
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 95b6fee..9bd1940 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -370,4 +370,7 @@
     boolean isFirstBoot();
 
     List<UserInfo> getUsers();
+
+    void setPermissionEnforcement(String permission, int enforcement);
+    int getPermissionEnforcement(String permission);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 544bd9c..55426b8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1090,6 +1090,11 @@
     public static final String EXTRA_VERIFICATION_INSTALL_FLAGS
             = "android.content.pm.extra.VERIFICATION_INSTALL_FLAGS";
 
+    /** {@hide} */
+    public static final int ENFORCEMENT_DEFAULT = 0;
+    /** {@hide} */
+    public static final int ENFORCEMENT_YES = 1;
+
     /**
      * Retrieve overall information about an application package that is
      * installed on the system.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6139296..770bf1c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -98,6 +98,12 @@
     public static final int SDCARD_RW_GID = 1015;
 
     /**
+     * Defines the UID/GID for the group that controls VPN services.
+     * @hide
+     */
+    public static final int VPN_UID = 1016;
+
+    /**
      * Defines the UID/GID for the NFC service process.
      * @hide
      */
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d08a61f..b98257c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -704,7 +704,7 @@
             return null;
         }
 
-        private void printConfig(EGLConfig config) {
+        private static void printConfig(EGLConfig config) {
             int[] value = new int[1];
 
             Log.d(LOG_TAG, "EGL configuration " + config + ":");
@@ -990,10 +990,11 @@
                             }
 
                             if (invalidateNeeded) {
-                                if (mRedrawClip.isEmpty() || view.getParent() == null) {
-                                    view.invalidate();
+                                if (mRedrawClip.isEmpty()) {
+                                    attachInfo.mViewRootImpl.invalidate();
                                 } else {
-                                    view.getParent().invalidateChild(view, mRedrawClip);
+                                    attachInfo.mViewRootImpl.invalidateChildInParent(
+                                            null, mRedrawClip);
                                 }
                                 mRedrawClip.setEmpty();
                             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fdf3a814..6c195c4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -698,14 +698,14 @@
     private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE};
 
     /**
-     * This view is enabled. Intrepretation varies by subclass.
+     * This view is enabled. Interpretation varies by subclass.
      * Use with ENABLED_MASK when calling setFlags.
      * {@hide}
      */
     static final int ENABLED = 0x00000000;
 
     /**
-     * This view is disabled. Intrepretation varies by subclass.
+     * This view is disabled. Interpretation varies by subclass.
      * Use with ENABLED_MASK when calling setFlags.
      * {@hide}
      */
@@ -955,50 +955,6 @@
     static final int PARENT_SAVE_DISABLED_MASK = 0x20000000;
 
     /**
-     * Horizontal direction of this view is from Left to Right.
-     * Use with {@link #setLayoutDirection}.
-     */
-    public static final int LAYOUT_DIRECTION_LTR = 0x00000000;
-
-    /**
-     * Horizontal direction of this view is from Right to Left.
-     * Use with {@link #setLayoutDirection}.
-     */
-    public static final int LAYOUT_DIRECTION_RTL = 0x40000000;
-
-    /**
-     * Horizontal direction of this view is inherited from its parent.
-     * Use with {@link #setLayoutDirection}.
-     */
-    public static final int LAYOUT_DIRECTION_INHERIT = 0x80000000;
-
-    /**
-     * Horizontal direction of this view is from deduced from the default language
-     * script for the locale. Use with {@link #setLayoutDirection}.
-     */
-    public static final int LAYOUT_DIRECTION_LOCALE = 0xC0000000;
-
-    /**
-     * Mask for use with setFlags indicating bits used for horizontalDirection.
-     * {@hide}
-     */
-    static final int LAYOUT_DIRECTION_MASK = 0xC0000000;
-
-    /*
-     * Array of horizontal direction flags for mapping attribute "horizontalDirection" to correct
-     * flag value.
-     * {@hide}
-     */
-    private static final int[] LAYOUT_DIRECTION_FLAGS = {LAYOUT_DIRECTION_LTR,
-        LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE};
-
-    /**
-     * Default horizontalDirection.
-     * {@hide}
-     */
-    private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
-
-    /**
      * View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
      * should add all focusable Views regardless if they are focusable in touch mode.
      */
@@ -1748,19 +1704,73 @@
     static final int DRAG_HOVERED                 = 0x00000002;
 
     /**
-     * Indicates whether the view layout direction has been resolved and drawn to the
-     * right-to-left direction.
-     *
-     * @hide
+     * Horizontal layout direction of this view is from Left to Right.
+     * Use with {@link #setLayoutDirection}.
      */
-    static final int LAYOUT_DIRECTION_RESOLVED_RTL = 0x00000004;
+    public static final int LAYOUT_DIRECTION_LTR = 0x00000001;
 
     /**
-     * Indicates whether the view layout direction has been resolved.
-     *
+     * Horizontal layout direction of this view is from Right to Left.
+     * Use with {@link #setLayoutDirection}.
+     */
+    public static final int LAYOUT_DIRECTION_RTL = 0x00000002;
+
+    /**
+     * Horizontal layout direction of this view is inherited from its parent.
+     * Use with {@link #setLayoutDirection}.
+     */
+    public static final int LAYOUT_DIRECTION_INHERIT = 0x00000004;
+
+    /**
+     * Horizontal layout direction of this view is from deduced from the default language
+     * script for the locale. Use with {@link #setLayoutDirection}.
+     */
+    public static final int LAYOUT_DIRECTION_LOCALE = 0x00000008;
+
+    /**
+     * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED = 0x00000008;
+    static final int LAYOUT_DIRECTION_MASK_SHIFT = 2;
+
+    /**
+     * Mask for use with private flags indicating bits used for horizontal layout direction.
+     * @hide
+     */
+    static final int LAYOUT_DIRECTION_MASK = 0x0000000F << LAYOUT_DIRECTION_MASK_SHIFT;
+
+    /**
+     * Indicates whether the view horizontal layout direction has been resolved and drawn to the
+     * right-to-left direction.
+     * @hide
+     */
+    static final int LAYOUT_DIRECTION_RESOLVED_RTL = 0x00000010 << LAYOUT_DIRECTION_MASK_SHIFT;
+
+    /**
+     * Indicates whether the view horizontal layout direction has been resolved.
+     * @hide
+     */
+    static final int LAYOUT_DIRECTION_RESOLVED = 0x00000020 << LAYOUT_DIRECTION_MASK_SHIFT;
+
+    /**
+     * Mask for use with private flags indicating bits used for resolved horizontal layout direction.
+     * @hide
+     */
+    static final int LAYOUT_DIRECTION_RESOLVED_MASK = 0x00000030 << LAYOUT_DIRECTION_MASK_SHIFT;
+
+    /*
+     * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct
+     * flag value.
+     * @hide
+     */
+    private static final int[] LAYOUT_DIRECTION_FLAGS = {LAYOUT_DIRECTION_LTR,
+            LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE};
+
+    /**
+     * Default horizontal layout direction.
+     * @hide
+     */
+    private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
 
 
     /**
@@ -1770,7 +1780,7 @@
      *
      * @hide
      */
-    static final int HAS_TRANSIENT_STATE = 0x00000010;
+    static final int HAS_TRANSIENT_STATE = 0x00000100;
 
 
     /* End of masks for mPrivateFlags2 */
@@ -2739,7 +2749,8 @@
     public View(Context context) {
         mContext = context;
         mResources = context != null ? context.getResources() : null;
-        mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | LAYOUT_DIRECTION_INHERIT;
+        mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
+        mPrivateFlags2 |= (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = -1;
@@ -2949,17 +2960,13 @@
                     }
                     break;
                 case com.android.internal.R.styleable.View_layoutDirection:
-                    // Clear any HORIZONTAL_DIRECTION flag already set
-                    viewFlagValues &= ~LAYOUT_DIRECTION_MASK;
-                    // Set the HORIZONTAL_DIRECTION flags depending on the value of the attribute
+                    // Clear any layout direction flags (included resolved bits) already set
+                    mPrivateFlags2 &= ~(LAYOUT_DIRECTION_MASK | LAYOUT_DIRECTION_RESOLVED_MASK);
+                    // Set the layout direction flags depending on the value of the attribute
                     final int layoutDirection = a.getInt(attr, -1);
-                    if (layoutDirection != -1) {
-                        viewFlagValues |= LAYOUT_DIRECTION_FLAGS[layoutDirection];
-                    } else {
-                        // Set to default (LAYOUT_DIRECTION_INHERIT)
-                        viewFlagValues |= LAYOUT_DIRECTION_DEFAULT;
-                    }
-                    viewFlagMasks |= LAYOUT_DIRECTION_MASK;
+                    final int value = (layoutDirection != -1) ?
+                            LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT;
+                    mPrivateFlags2 |= (value << LAYOUT_DIRECTION_MASK_SHIFT);
                     break;
                 case com.android.internal.R.styleable.View_drawingCacheQuality:
                     final int cacheQuality = a.getInt(attr, 0);
@@ -4882,7 +4889,7 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE,  to = "LOCALE")
     })
     public int getLayoutDirection() {
-        return mViewFlags & LAYOUT_DIRECTION_MASK;
+        return (mPrivateFlags2 & LAYOUT_DIRECTION_MASK) >> LAYOUT_DIRECTION_MASK_SHIFT;
     }
 
     /**
@@ -4899,9 +4906,14 @@
     @RemotableViewMethod
     public void setLayoutDirection(int layoutDirection) {
         if (getLayoutDirection() != layoutDirection) {
+            // Reset the current layout direction
+            mPrivateFlags2 &= ~LAYOUT_DIRECTION_MASK;
+            // Reset the current resolved layout direction
             resetResolvedLayoutDirection();
-            // Setting the flag will also request a layout.
-            setFlags(layoutDirection, LAYOUT_DIRECTION_MASK);
+            // Set the new layout direction (filtered) and ask for a layout pass
+            mPrivateFlags2 |=
+                    ((layoutDirection << LAYOUT_DIRECTION_MASK_SHIFT) & LAYOUT_DIRECTION_MASK);
+            requestLayout();
         }
     }
 
@@ -4909,11 +4921,11 @@
      * Returns the resolved layout direction for this view.
      *
      * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
-     * {@link #LAYOUT_DIRECTION_LTR} id the layout direction is not RTL.
+     * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
      */
     @ViewDebug.ExportedProperty(category = "layout", mapping = {
-        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR,     to = "RESOLVED_DIRECTION_LTR"),
-        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL,     to = "RESOLVED_DIRECTION_RTL")
+        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
+        @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
     })
     public int getResolvedLayoutDirection() {
         resolveLayoutDirectionIfNeeded();
@@ -4922,8 +4934,8 @@
     }
 
     /**
-     * <p>Indicates whether or not this view's layout is right-to-left. This is resolved from
-     * layout attribute and/or the inherited value from the parent.</p>
+     * Indicates whether or not this view's layout is right-to-left. This is resolved from
+     * layout attribute and/or the inherited value from the parent
      *
      * @return true if the layout is right-to-left.
      */
@@ -6940,10 +6952,6 @@
                 mParent.recomputeViewAttributes(this);
             }
         }
-
-        if ((changed & LAYOUT_DIRECTION_MASK) != 0) {
-            requestLayout();
-        }
     }
 
     /**
@@ -9834,7 +9842,7 @@
         if ((mPrivateFlags2 & LAYOUT_DIRECTION_RESOLVED) == LAYOUT_DIRECTION_RESOLVED) return;
 
         // Clear any previous layout direction resolution
-        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_RTL;
+        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_MASK;
 
         // Set resolved depending on layout direction
         switch (getLayoutDirection()) {
@@ -9966,8 +9974,8 @@
      * when reset is done.
      */
     public void resetResolvedLayoutDirection() {
-        // Reset the current View resolution
-        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
+        // Reset the current resolved bits
+        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_MASK;
         onResolvedLayoutDirectionReset();
         // Reset also the text direction
         resetResolvedTextDirection();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 42426b98..b8fbf17 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2679,15 +2679,6 @@
         return child.draw(canvas, this, drawingTime);
     }
 
-    @Override
-    public void requestLayout() {
-        if (mChildrenCount > 0 && getAccessibilityNodeProvider() != null) {
-            throw new IllegalStateException("Views with AccessibilityNodeProvider"
-                    + " can't have children.");
-        }
-        super.requestLayout();
-    }
-
     /**
      * 
      * @param enabled True if children should be drawn with layers, false otherwise.
@@ -3109,11 +3100,6 @@
     private void addViewInner(View child, int index, LayoutParams params,
             boolean preventRequestLayout) {
 
-        if (getAccessibilityNodeProvider() != null) {
-            throw new IllegalStateException("Views with AccessibilityNodeProvider"
-                    + " can't have children.");
-        }
-
         if (mTransition != null) {
             // Don't prevent other add transitions from completing, but cancel remove
             // transitions to let them complete the process before we add to the container
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 04ad649..4eb70ab 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -841,7 +841,9 @@
         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
         // Intersect with the bounds of the window to skip
         // updates that lie outside of the visible region
-        localDirty.intersect(0, 0, mWidth, mHeight);
+        final float appScale = mAttachInfo.mApplicationScale;
+        localDirty.intersect(0, 0,
+                (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
 
         if (!mWillDrawSoon) {
             scheduleTraversals();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5e09416..dd373de 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -21,6 +21,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -1980,4 +1981,10 @@
     public void setBackgroundColor(int color) {
         mProvider.getViewDelegate().setBackgroundColor(color);
     }
+
+    @Override
+    public void setLayerType(int layerType, Paint paint) {
+        super.setLayerType(layerType, paint);
+        mProvider.getViewDelegate().setLayerType(layerType, paint);
+    }
 }
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index e5434ce..d835947 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -5638,6 +5638,7 @@
         addAccessibilityApisToJavaScript();
 
         mTouchEventQueue.reset();
+        updateHwAccelerated();
     }
 
     @Override
@@ -5657,6 +5658,7 @@
         }
 
         removeAccessibilityApisFromJavaScript();
+        updateHwAccelerated();
     }
 
     @Override
@@ -6221,6 +6223,7 @@
                     ted.mReprocess = mDeferTouchProcess;
                     ted.mNativeLayer = mCurrentScrollingLayerId;
                     ted.mNativeLayerRect.set(mScrollingLayerRect);
+                    ted.mMotionEvent = MotionEvent.obtain(ev);
                     ted.mSequence = mTouchEventQueue.nextTouchSequence();
                     mTouchEventQueue.preQueueTouchEventData(ted);
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
@@ -9359,6 +9362,30 @@
         nativeDiscardAllTextures();
     }
 
+    @Override
+    public void setLayerType(int layerType, Paint paint) {
+        updateHwAccelerated();
+    }
+
+    private void updateHwAccelerated() {
+        if (mNativeClass == 0) {
+            return;
+        }
+        boolean hwAccelerated = false;
+        if (mWebView.isHardwareAccelerated()
+                && mWebView.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
+            hwAccelerated = true;
+        }
+        int result = nativeSetHwAccelerated(mNativeClass, hwAccelerated);
+        if (mWebViewCore == null || mBlockWebkitViewMessages) {
+            return;
+        }
+        if (result == 1) {
+            // Sync layers
+            mWebViewCore.layersDraw();
+        }
+    }
+
     /**
      * Begin collecting per-tile profiling data
      *
@@ -9480,4 +9507,6 @@
     private static native boolean nativeIsBaseFirst(int instance);
     private static native void nativeMapLayerRect(int instance, int layerId,
             Rect rect);
+    // Returns 1 if a layer sync is needed, else 0
+    private static native int nativeSetHwAccelerated(int instance, boolean hwAccelerated);
 }
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 9016fbc..7d47e14 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -337,6 +338,8 @@
         public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate);
 
         public void setBackgroundColor(int color);
+
+        public void setLayerType(int layerType, Paint paint);
     }
 
     interface ScrollDelegate {
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index fd93980..c5066b6 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -29,8 +29,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -280,9 +280,7 @@
         reorderSpinners();
 
         // set content descriptions
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            setContentDescriptions();
-        }
+        setContentDescriptions();
     }
 
     /**
@@ -717,20 +715,27 @@
 
     private void setContentDescriptions() {
         // Day
-        String text = mContext.getString(R.string.date_picker_increment_day_button);
-        mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_day_button);
-        mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
+        trySetContentDescription(mDaySpinner, R.id.increment,
+                R.string.date_picker_increment_day_button);
+        trySetContentDescription(mDaySpinner, R.id.decrement,
+                R.string.date_picker_decrement_day_button);
         // Month
-        text = mContext.getString(R.string.date_picker_increment_month_button);
-        mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_month_button);
-        mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        trySetContentDescription(mMonthSpinner, R.id.increment,
+                R.string.date_picker_increment_month_button);
+        trySetContentDescription(mMonthSpinner, R.id.decrement,
+                R.string.date_picker_decrement_month_button);
         // Year
-        text = mContext.getString(R.string.date_picker_increment_year_button);
-        mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.date_picker_decrement_year_button);
-        mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        trySetContentDescription(mYearSpinner, R.id.increment,
+                R.string.date_picker_increment_year_button);
+        trySetContentDescription(mYearSpinner, R.id.decrement,
+                R.string.date_picker_decrement_year_button);
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
+        }
     }
 
     private void updateInputState() {
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 0db6ef2..4e13ea1 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -715,6 +715,7 @@
         } else {
             super.scrollTo(scrollX, scrollY);
         }
+        
         awakenScrollBars();
     }
 
@@ -1204,10 +1205,9 @@
                 }
             }
 
-            awakenScrollBars();
-
-            // Keep on drawing until the animation has finished.
-            postInvalidate();
+            if (!awakenScrollBars()) {
+                invalidate();
+            }
         }
     }
 
@@ -1414,7 +1414,7 @@
     /**
      * Return true if child is a descendant of parent, (or equal to the parent).
      */
-    private boolean isViewDescendantOf(View child, View parent) {
+    private static boolean isViewDescendantOf(View child, View parent) {
         if (child == parent) {
             return true;
         }
@@ -1524,7 +1524,7 @@
         }
     }
 
-    private int clamp(int n, int my, int child) {
+    private static int clamp(int n, int my, int child) {
         if (my >= child || n < 0) {
             return 0;
         }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 3335da0..4e56cd6 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -16,10 +16,6 @@
 
 package android.widget;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -48,22 +44,41 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.R;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * A widget that enables the user to select a number form a predefined range.
- * The widget presents an input field and up and down buttons for selecting the
- * current value. Pressing/long-pressing the up and down buttons increments and
- * decrements the current value respectively. Touching the input field shows a
- * scroll wheel, which when touched allows direct edit
- * of the current value. Sliding gestures up or down hide the buttons and the
- * input filed, show and rotate the scroll wheel. Flinging is
- * also supported. The widget enables mapping from positions to strings such
- * that, instead of the position index, the corresponding string is displayed.
+ * There are two flavors of this widget and which one is presented to the user
+ * depends on the current theme.
+ * <ul>
+ * <li>
+ * If the current theme is derived from {@link android.R.style#Theme} the widget
+ * presents the current value as an editable input field with an increment button
+ * above and a decrement button below. Long pressing the buttons allows for a quick
+ * change of the current value. Tapping on the input field allows to type in
+ * a desired value.
+ * </li>
+ * <li>
+ * If the current theme is derived from {@link android.R.style#Theme_Holo} or
+ * {@link android.R.style#Theme_Holo_Light} the widget presents the current
+ * value as an editable input field with a lesser value above and a greater
+ * value below. Tapping on the lesser or greater value selects it by animating
+ * the number axis up or down to make the chosen value current. Flinging up
+ * or down allows for multiple increments or decrements of the current value.
+ * Long pressing on the lesser and greater values also allows for a quick change
+ * of the current value. Tapping on the current value allows to type in a
+ * desired value.
+ * </li>
+ * </ul>
  * <p>
  * For an example of using this widget, see {@link android.widget.TimePicker}.
  * </p>
@@ -74,7 +89,7 @@
     /**
      * The number of items show in the selector wheel.
      */
-    public static final int SELECTOR_WHEEL_ITEM_COUNT = 5;
+    private static final int SELECTOR_WHEEL_ITEM_COUNT = 3;
 
     /**
      * The default update interval during long press.
@@ -84,7 +99,7 @@
     /**
      * The index of the middle selector item.
      */
-    private static final int SELECTOR_MIDDLE_ITEM_INDEX = 2;
+    private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2;
 
     /**
      * The coefficient by which to adjust (divide) the max fling velocity.
@@ -97,19 +112,12 @@
     private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
 
     /**
-     * The duration of scrolling to the next/previous value while changing
-     * the current value by one, i.e. increment or decrement.
+     * The duration of scrolling to the next/previous value while changing the
+     * current value by one, i.e. increment or decrement.
      */
     private static final int CHANGE_CURRENT_BY_ONE_SCROLL_DURATION = 300;
 
     /**
-     * The the delay for showing the input controls after a single tap on the
-     * input text.
-     */
-    private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration
-            .getDoubleTapTimeout();
-
-    /**
      * The strength of fading in the top and bottom while drawing the selector.
      */
     private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f;
@@ -120,56 +128,31 @@
     private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2;
 
     /**
-     * In this state the selector wheel is not shown.
+     * The default unscaled distance between the selection dividers.
      */
-    private static final int SELECTOR_WHEEL_STATE_NONE = 0;
+    private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48;
 
     /**
-     * In this state the selector wheel is small.
+     * The default unscaled minimal distance for a swipe to be considered a fling.
      */
-    private static final int SELECTOR_WHEEL_STATE_SMALL = 1;
+    private static final int UNSCALED_DEFAULT_MIN_FLING_DISTANCE = 150;
 
     /**
-     * In this state the selector wheel is large.
+     * Coefficient for adjusting touch scroll distance.
      */
-    private static final int SELECTOR_WHEEL_STATE_LARGE = 2;
+    private static final float TOUCH_SCROLL_DECELERATION_COEFFICIENT = 2.5f;
 
     /**
-     * The alpha of the selector wheel when it is bright.
+     * The resource id for the default layout.
      */
-    private static final int SELECTOR_WHEEL_BRIGHT_ALPHA = 255;
-
-    /**
-     * The alpha of the selector wheel when it is dimmed.
-     */
-    private static final int SELECTOR_WHEEL_DIM_ALPHA = 60;
-
-    /**
-     * The alpha for the increment/decrement button when it is transparent.
-     */
-    private static final int BUTTON_ALPHA_TRANSPARENT = 0;
-
-    /**
-     * The alpha for the increment/decrement button when it is opaque.
-     */
-    private static final int BUTTON_ALPHA_OPAQUE = 1;
-
-    /**
-     * The property for setting the selector paint.
-     */
-    private static final String PROPERTY_SELECTOR_PAINT_ALPHA = "selectorPaintAlpha";
-
-    /**
-     * The property for setting the increment/decrement button alpha.
-     */
-    private static final String PROPERTY_BUTTON_ALPHA = "alpha";
+    private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker;
 
     /**
      * The numbers accepted by the input text's {@link Filter}
      */
     private static final char[] DIGIT_CHARACTERS = new char[] {
             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
-    };
+     };
 
     /**
      * Constant for unspecified size.
@@ -215,6 +198,11 @@
     private final EditText mInputText;
 
     /**
+     * The distance between the two selection dividers.
+     */
+    private final int mSelectionDividersDistance;
+
+    /**
      * The min height of this widget.
      */
     private final int mMinHeight;
@@ -245,6 +233,11 @@
     private final int mTextSize;
 
     /**
+     * The minimal distance for a swipe to be considered a fling.
+     */
+    private final int mMinFlingDistance;
+
+    /**
      * The height of the gap between text elements if the selector wheel.
      */
     private int mSelectorTextGapHeight;
@@ -297,10 +290,7 @@
     /**
      * The selector indices whose value are show by the selector.
      */
-    private final int[] mSelectorIndices = new int[] {
-            Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE,
-            Integer.MIN_VALUE
-    };
+    private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT];
 
     /**
      * The {@link Paint} for drawing the selector.
@@ -343,25 +333,15 @@
     private SetSelectionCommand mSetSelectionCommand;
 
     /**
-     * Handle to the reusable command for adjusting the scroller.
-     */
-    private AdjustScrollerCommand mAdjustScrollerCommand;
-
-    /**
      * Handle to the reusable command for changing the current value from long
      * press by one.
      */
     private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand;
 
     /**
-     * {@link Animator} for showing the up/down arrows.
+     * Command for beginning an edit of the current value via IME on long press.
      */
-    private final AnimatorSet mShowInputControlsAnimator;
-
-    /**
-     * {@link Animator} for dimming the selector wheel.
-     */
-    private final Animator mDimSelectorWheelAnimator;
+    private BeginSoftInputOnLongPressCommand mBeginSoftInputOnLongPressCommand;
 
     /**
      * The Y position of the last down event.
@@ -369,24 +349,14 @@
     private float mLastDownEventY;
 
     /**
-     * The Y position of the last motion event.
+     * The time of the last down event.
      */
-    private float mLastMotionEventY;
+    private long mLastDownEventTime;
 
     /**
-     * Flag if to check for double tap and potentially start edit.
+     * The Y position of the last down or move event.
      */
-    private boolean mCheckBeginEditOnUpEvent;
-
-    /**
-     * Flag if to adjust the selector wheel on next up event.
-     */
-    private boolean mAdjustScrollerOnUpEvent;
-
-    /**
-     * The state of the selector wheel.
-     */
-    private int mSelectorWheelState;
+    private float mLastDownOrMoveEventY;
 
     /**
      * Determines speed during touch scrolling.
@@ -419,9 +389,9 @@
     private final int mSolidColor;
 
     /**
-     * Flag indicating if this widget supports flinging.
+     * Flag whether this widget has a selector wheel.
      */
-    private final boolean mFlingable;
+    private final boolean mHasSelectorWheel;
 
     /**
      * Divider for showing item to be selected while scrolling
@@ -434,29 +404,40 @@
     private final int mSelectionDividerHeight;
 
     /**
-     * Reusable {@link Rect} instance.
-     */
-    private final Rect mTempRect = new Rect();
-
-    /**
      * The current scroll state of the number picker.
      */
     private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
 
     /**
-     * The duration of the animation for showing the input controls.
+     * Flag whether to ignore move events - we ignore such when we show in IME
+     * to prevent the content from scrolling.
      */
-    private final long mShowInputControlsAnimimationDuration;
+    private boolean mIngonreMoveEvents;
 
     /**
-     * Flag whether the scoll wheel and the fading edges have been initialized.
+     * Flag whether to show soft input on tap.
      */
-    private boolean mScrollWheelAndFadingEdgesInitialized;
+    private boolean mShowSoftInputOnTap;
 
     /**
-     * The time of the last up event.
+     * The top of the top selection divider.
      */
-    private long mLastUpEventTimeMillis;
+    private int mTopSelectionDividerTop;
+
+    /**
+     * The bottom of the bottom selection divider.
+     */
+    private int mBottomSelectionDividerBottom;
+
+    /**
+     * The virtual id of the last hovered child.
+     */
+    private int mLastHoveredChildVirtualViewId;
+
+    /**
+     * Provider to report to clients the semantic structure of this widget.
+     */
+    private AccessibilityNodeProviderImpl mAccessibilityNodeProvider;
 
     /**
      * Interface to listen for changes of the current value.
@@ -484,7 +465,7 @@
         public static int SCROLL_STATE_IDLE = 0;
 
         /**
-         * The user is scrolling using touch, and their finger is still on the screen.
+         * The user is scrolling using touch, and his finger is still on the screen.
          */
         public static int SCROLL_STATE_TOUCH_SCROLL = 1;
 
@@ -549,58 +530,78 @@
         super(context, attrs, defStyle);
 
         // process style attributes
-        TypedArray attributesArray = context.obtainStyledAttributes(attrs,
-                R.styleable.NumberPicker, defStyle, 0);
+        TypedArray attributesArray = context.obtainStyledAttributes(
+                attrs, R.styleable.NumberPicker, defStyle, 0);
+        final int layoutResId = attributesArray.getResourceId(
+                R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID);
+
+        mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID);
+
         mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0);
-        mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true);
+
         mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider);
-        int defSelectionDividerHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT,
+
+        final int defSelectionDividerHeight = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT,
                 getResources().getDisplayMetrics());
         mSelectionDividerHeight = attributesArray.getDimensionPixelSize(
                 R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight);
+
+        final int defSelectionDividerDistance = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE,
+                getResources().getDisplayMetrics());
+        mSelectionDividersDistance = attributesArray.getDimensionPixelSize(
+                R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance);
+
+        final int defMinFlingDistance = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_MIN_FLING_DISTANCE,
+                getResources().getDisplayMetrics());
+        mMinFlingDistance = attributesArray.getDimensionPixelSize(
+                R.styleable.NumberPicker_minFlingDistance, defMinFlingDistance);
+
         mMinHeight = attributesArray.getDimensionPixelSize(
                 R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED);
+
         mMaxHeight = attributesArray.getDimensionPixelSize(
                 R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED);
         if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED
                 && mMinHeight > mMaxHeight) {
             throw new IllegalArgumentException("minHeight > maxHeight");
         }
-        mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_internalMinWidth,
-                SIZE_UNSPECIFIED);
-        mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_internalMaxWidth,
-                SIZE_UNSPECIFIED);
+
+        mMinWidth = attributesArray.getDimensionPixelSize(
+                R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED);
+
+        mMaxWidth = attributesArray.getDimensionPixelSize(
+                R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED);
         if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED
                 && mMinWidth > mMaxWidth) {
             throw new IllegalArgumentException("minWidth > maxWidth");
         }
-        mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
-        attributesArray.recycle();
 
-        mShowInputControlsAnimimationDuration = getResources().getInteger(
-                R.integer.config_longAnimTime);
+        mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
+
+        attributesArray.recycle();
 
         // By default Linearlayout that we extend is not drawn. This is
         // its draw() method is not called but dispatchDraw() is called
         // directly (see ViewGroup.drawChild()). However, this class uses
         // the fading edge effect implemented by View and we need our
         // draw() method to be called. Therefore, we declare we will draw.
-        setWillNotDraw(false);
-        setSelectorWheelState(SELECTOR_WHEEL_STATE_NONE);
+        setWillNotDraw(!mHasSelectorWheel);
 
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        inflater.inflate(R.layout.number_picker, this, true);
+        inflater.inflate(layoutResId, this, true);
 
         OnClickListener onClickListener = new OnClickListener() {
             public void onClick(View v) {
                 hideSoftInput();
                 mInputText.clearFocus();
                 if (v.getId() == R.id.increment) {
-                    changeCurrentByOne(true);
+                    changeValueByOne(true);
                 } else {
-                    changeCurrentByOne(false);
+                    changeValueByOne(false);
                 }
             }
         };
@@ -610,23 +611,31 @@
                 hideSoftInput();
                 mInputText.clearFocus();
                 if (v.getId() == R.id.increment) {
-                    postChangeCurrentByOneFromLongPress(true);
+                    postChangeCurrentByOneFromLongPress(true, 0);
                 } else {
-                    postChangeCurrentByOneFromLongPress(false);
+                    postChangeCurrentByOneFromLongPress(false, 0);
                 }
                 return true;
             }
         };
 
         // increment button
-        mIncrementButton = (ImageButton) findViewById(R.id.increment);
-        mIncrementButton.setOnClickListener(onClickListener);
-        mIncrementButton.setOnLongClickListener(onLongClickListener);
+        if (!mHasSelectorWheel) {
+            mIncrementButton = (ImageButton) findViewById(R.id.increment);
+            mIncrementButton.setOnClickListener(onClickListener);
+            mIncrementButton.setOnLongClickListener(onLongClickListener);
+        } else {
+            mIncrementButton = null;
+        }
 
         // decrement button
-        mDecrementButton = (ImageButton) findViewById(R.id.decrement);
-        mDecrementButton.setOnClickListener(onClickListener);
-        mDecrementButton.setOnLongClickListener(onLongClickListener);
+        if (!mHasSelectorWheel) {
+            mDecrementButton = (ImageButton) findViewById(R.id.decrement);
+            mDecrementButton.setOnClickListener(onClickListener);
+            mDecrementButton.setOnLongClickListener(onLongClickListener);
+        } else {
+            mDecrementButton = null;
+        }
 
         // input text
         mInputText = (EditText) findViewById(R.id.numberpicker_input);
@@ -648,7 +657,6 @@
         mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE);
 
         // initialize constants
-        mTouchSlop = ViewConfiguration.getTapTimeout();
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mTouchSlop = configuration.getScaledTouchSlop();
         mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
@@ -667,69 +675,22 @@
         paint.setColor(color);
         mSelectorWheelPaint = paint;
 
-        // create the animator for showing the input controls
-        mDimSelectorWheelAnimator = ObjectAnimator.ofInt(this, PROPERTY_SELECTOR_PAINT_ALPHA,
-                SELECTOR_WHEEL_BRIGHT_ALPHA, SELECTOR_WHEEL_DIM_ALPHA);
-        final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton,
-                PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
-        final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton,
-                PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
-        mShowInputControlsAnimator = new AnimatorSet();
-        mShowInputControlsAnimator.playTogether(mDimSelectorWheelAnimator, showIncrementButton,
-                showDecrementButton);
-        mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCanceled = false;
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!mCanceled) {
-                    // if canceled => we still want the wheel drawn
-                    setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
-                }
-                mCanceled = false;
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                if (mShowInputControlsAnimator.isRunning()) {
-                    mCanceled = true;
-                }
-            }
-        });
-
         // create the fling and adjust scrollers
         mFlingScroller = new Scroller(getContext(), null, true);
         mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f));
 
         updateInputTextView();
-        updateIncrementAndDecrementButtonsVisibilityState();
-
-        if (mFlingable) {
-           if (isInEditMode()) {
-               setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
-           } else {
-                // Start with shown selector wheel and hidden controls. When made
-                // visible hide the selector and fade-in the controls to suggest
-                // fling interaction.
-                setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
-                hideInputControls();
-           }
-        }
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!mHasSelectorWheel) {
+            super.onLayout(changed, left, top, right, bottom);
+            return;
+        }
         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);
-
         // Input text centered horizontally.
         final int inptTxtMsrdWdth = mInputText.getMeasuredWidth();
         final int inptTxtMsrdHght = mInputText.getMeasuredHeight();
@@ -739,24 +700,23 @@
         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);
-
-        if (!mScrollWheelAndFadingEdgesInitialized) {
-            mScrollWheelAndFadingEdgesInitialized = true;
+        if (changed) {
             // need to do all this when we know our size
             initializeSelectorWheel();
             initializeFadingEdges();
+            mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2
+                    - mSelectionDividerHeight;
+            mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight
+                    + mSelectionDividersDistance;
         }
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (!mHasSelectorWheel) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
         // Try greedily to fit the max width and height.
         final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth);
         final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight);
@@ -769,120 +729,143 @@
         setMeasuredDimension(widthSize, heightSize);
     }
 
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (!isEnabled() || !mFlingable) {
-            return false;
-        }
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                mLastMotionEventY = mLastDownEventY = event.getY();
-                removeAllCallbacks();
-                mShowInputControlsAnimator.cancel();
-                mDimSelectorWheelAnimator.cancel();
-                mCheckBeginEditOnUpEvent = false;
-                mAdjustScrollerOnUpEvent = true;
-                if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
-                    mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
-                    boolean scrollersFinished = mFlingScroller.isFinished()
-                            && mAdjustScroller.isFinished();
-                    if (!scrollersFinished) {
-                        mFlingScroller.forceFinished(true);
-                        mAdjustScroller.forceFinished(true);
-                        onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                    }
-                    mCheckBeginEditOnUpEvent = scrollersFinished;
-                    mAdjustScrollerOnUpEvent = true;
-                    hideSoftInput();
-                    hideInputControls();
-                    return true;
+    /**
+     * Move to the final position of a scroller. Ensures to force finish the scroller
+     * and if it is not at its final position a scroll of the selector wheel is
+     * performed to fast forward to the final position.
+     *
+     * @param scroller The scroller to whose final position to get.
+     * @return True of the a move was performed, i.e. the scroller was not in final position.
+     */
+    private boolean moveToFinalScrollerPosition(Scroller scroller) {
+        scroller.forceFinished(true);
+        int amountToScroll = scroller.getFinalY() - scroller.getCurrY();
+        int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight;
+        int overshootAdjustment = mInitialScrollOffset - futureScrollOffset;
+        if (overshootAdjustment != 0) {
+            if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) {
+                if (overshootAdjustment > 0) {
+                    overshootAdjustment -= mSelectorElementHeight;
+                } else {
+                    overshootAdjustment += mSelectorElementHeight;
                 }
-                if (isEventInVisibleViewHitRect(event, mIncrementButton)
-                        || isEventInVisibleViewHitRect(event, mDecrementButton)) {
-                    return false;
-                }
-                mAdjustScrollerOnUpEvent = false;
-                setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
-                hideSoftInput();
-                hideInputControls();
-                return true;
-            case MotionEvent.ACTION_MOVE:
-                float currentMoveY = event.getY();
-                int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
-                if (deltaDownY > mTouchSlop) {
-                    mCheckBeginEditOnUpEvent = false;
-                    onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-                    setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
-                    hideSoftInput();
-                    hideInputControls();
-                    return true;
-                }
-                break;
+            }
+            amountToScroll += overshootAdjustment;
+            scrollBy(0, amountToScroll);
+            return true;
         }
         return false;
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (!isEnabled()) {
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (!mHasSelectorWheel || !isEnabled()) {
+            return false;
+        }
+        final int action = event.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                removeAllCallbacks();
+                mInputText.setVisibility(View.INVISIBLE);
+                mLastDownOrMoveEventY = mLastDownEventY = event.getY();
+                mLastDownEventTime = event.getEventTime();
+                mIngonreMoveEvents = false;
+                mShowSoftInputOnTap = false;
+                if (!mFlingScroller.isFinished()) {
+                    mFlingScroller.forceFinished(true);
+                    mAdjustScroller.forceFinished(true);
+                    onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+                } else if (!mAdjustScroller.isFinished()) {
+                    mFlingScroller.forceFinished(true);
+                    mAdjustScroller.forceFinished(true);
+                } else if (mLastDownEventY < mTopSelectionDividerTop) {
+                    hideSoftInput();
+                    postChangeCurrentByOneFromLongPress(
+                            false, ViewConfiguration.getLongPressTimeout());
+                } else if (mLastDownEventY > mBottomSelectionDividerBottom) {
+                    hideSoftInput();
+                    postChangeCurrentByOneFromLongPress(
+                            true, ViewConfiguration.getLongPressTimeout());
+                } else {
+                    mShowSoftInputOnTap = true;
+                    postBeginSoftInputOnLongPressCommand();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (!isEnabled() || !mHasSelectorWheel) {
             return false;
         }
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
         }
-        mVelocityTracker.addMovement(ev);
-        int action = ev.getActionMasked();
+        mVelocityTracker.addMovement(event);
+        int action = event.getActionMasked();
         switch (action) {
-            case MotionEvent.ACTION_MOVE:
-                float currentMoveY = ev.getY();
-                if (mCheckBeginEditOnUpEvent
-                        || mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
+            case MotionEvent.ACTION_MOVE: {
+                if (mIngonreMoveEvents) {
+                    break;
+                }
+                float currentMoveY = event.getY();
+                if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                     int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
                     if (deltaDownY > mTouchSlop) {
-                        mCheckBeginEditOnUpEvent = false;
+                        removeAllCallbacks();
                         onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
                     }
+                } else {
+                    int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)
+                            / TOUCH_SCROLL_DECELERATION_COEFFICIENT);
+                    scrollBy(0, deltaMoveY);
+                    invalidate();
                 }
-                int deltaMoveY = (int) (currentMoveY - mLastMotionEventY);
-                scrollBy(0, deltaMoveY);
-                invalidate();
-                mLastMotionEventY = currentMoveY;
-                break;
-            case MotionEvent.ACTION_UP:
-                if (mCheckBeginEditOnUpEvent) {
-                    mCheckBeginEditOnUpEvent = false;
-                    final long deltaTapTimeMillis = ev.getEventTime() - mLastUpEventTimeMillis;
-                    if (deltaTapTimeMillis < ViewConfiguration.getDoubleTapTimeout()) {
-                        setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
-                        showInputControls(mShowInputControlsAnimimationDuration);
-                        mInputText.requestFocus();
-                        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
-                        if (inputMethodManager != null) {
-                            inputMethodManager.showSoftInput(mInputText, 0);
-                        }
-                        mLastUpEventTimeMillis = ev.getEventTime();
-                        return true;
-                    }
-                }
+                mLastDownOrMoveEventY = currentMoveY;
+            } break;
+            case MotionEvent.ACTION_UP: {
+                removeBeginSoftInputCommand();
+                removeChangeCurrentByOneFromLongPress();
                 VelocityTracker velocityTracker = mVelocityTracker;
                 velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                 int initialVelocity = (int) velocityTracker.getYVelocity();
                 if (Math.abs(initialVelocity) > mMinimumFlingVelocity) {
-                    fling(initialVelocity);
+                    int deltaMove = (int) (event.getY() - mLastDownEventY);
+                    int absDeltaMoveY = Math.abs(deltaMove);
+                    if (absDeltaMoveY > mMinFlingDistance) {
+                        fling(initialVelocity);
+                    } else {
+                        changeValueByOne(deltaMove < 0);
+                    }
                     onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
                 } else {
-                    if (mAdjustScrollerOnUpEvent) {
-                        if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) {
-                            postAdjustScrollerCommand(0);
+                    int eventY = (int) event.getY();
+                    int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY);
+                    long deltaTime = event.getEventTime() - mLastDownEventTime;
+                    if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) {
+                        if (mShowSoftInputOnTap) {
+                            mShowSoftInputOnTap = false;
+                            showSoftInput();
+                        } else {
+                            int selectorIndexOffset = (eventY / mSelectorElementHeight)
+                                    - SELECTOR_MIDDLE_ITEM_INDEX;
+                            if (selectorIndexOffset > 0) {
+                                changeValueByOne(true);
+                            } else if (selectorIndexOffset < 0) {
+                                changeValueByOne(false);
+                            }
                         }
                     } else {
-                        postAdjustScrollerCommand(SHOW_INPUT_CONTROLS_DELAY_MILLIS);
+                        ensureScrollWheelAdjusted();
                     }
+                    onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                 }
                 mVelocityTracker.recycle();
                 mVelocityTracker = null;
-                mLastUpEventTimeMillis = ev.getEventTime();
-                break;
+            } break;
         }
         return true;
     }
@@ -891,12 +874,6 @@
     public boolean dispatchTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
         switch (action) {
-            case MotionEvent.ACTION_MOVE:
-                if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
-                    removeAllCallbacks();
-                    forceCompleteChangeCurrentByOneViaScroll();
-                }
-                break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 removeAllCallbacks();
@@ -907,27 +884,75 @@
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        int keyCode = event.getKeyCode();
-        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
-            removeAllCallbacks();
+        final int keyCode = event.getKeyCode();
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_ENTER:
+                removeAllCallbacks();
+                break;
         }
         return super.dispatchKeyEvent(event);
     }
 
     @Override
     public boolean dispatchTrackballEvent(MotionEvent event) {
-        int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
-            removeAllCallbacks();
+        final int action = event.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                removeAllCallbacks();
+                break;
         }
         return super.dispatchTrackballEvent(event);
     }
 
     @Override
-    public void computeScroll() {
-        if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
-            return;
+    protected boolean dispatchHoverEvent(MotionEvent event) {
+        if (!mHasSelectorWheel) {
+            return super.dispatchHoverEvent(event);
         }
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            final int eventY = (int) event.getY();
+            final int hoveredVirtualViewId;
+            if (eventY < mTopSelectionDividerTop) {
+                hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT;
+            } else if (eventY > mBottomSelectionDividerBottom) {
+                hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT;
+            } else {
+                hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT;
+            }
+            final int action = event.getActionMasked();
+            AccessibilityNodeProviderImpl provider =
+                (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider();
+            switch (action) {
+                case MotionEvent.ACTION_HOVER_ENTER: {
+                    provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
+                            AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+                    mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
+                } break;
+                case MotionEvent.ACTION_HOVER_MOVE: {
+                    if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId
+                            && mLastHoveredChildVirtualViewId != View.NO_ID) {
+                        provider.sendAccessibilityEventForVirtualView(
+                                mLastHoveredChildVirtualViewId,
+                                AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                        provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
+                                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+                        mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
+                    }
+                } break;
+                case MotionEvent.ACTION_HOVER_EXIT: {
+                    provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
+                            AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                    mLastHoveredChildVirtualViewId = View.NO_ID;
+                } break;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void computeScroll() {
         Scroller scroller = mFlingScroller;
         if (scroller.isFinished()) {
             scroller = mAdjustScroller;
@@ -952,16 +977,17 @@
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
-        mIncrementButton.setEnabled(enabled);
-        mDecrementButton.setEnabled(enabled);
+        if (!mHasSelectorWheel) {
+            mIncrementButton.setEnabled(enabled);
+        }
+        if (!mHasSelectorWheel) {
+            mDecrementButton.setEnabled(enabled);
+        }
         mInputText.setEnabled(enabled);
     }
 
     @Override
     public void scrollBy(int x, int y) {
-        if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
-            return;
-        }
         int[] selectorIndices = mSelectorIndices;
         if (!mWrapSelectorWheel && y > 0
                 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
@@ -977,7 +1003,7 @@
         while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) {
             mCurrentScrollOffset -= mSelectorElementHeight;
             decrementSelectorIndices(selectorIndices);
-            changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
+            setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true);
             if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
                 mCurrentScrollOffset = mInitialScrollOffset;
             }
@@ -985,7 +1011,7 @@
         while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) {
             mCurrentScrollOffset += mSelectorElementHeight;
             incrementSelectorIndices(selectorIndices);
-            changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
+            setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true);
             if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) {
                 mCurrentScrollOffset = mInitialScrollOffset;
             }
@@ -1024,8 +1050,7 @@
      *
      * @param formatter The formatter object. If formatter is <code>null</code>,
      *            {@link String#valueOf(int)} will be used.
-     *
-     * @see #setDisplayedValues(String[])
+     *@see #setDisplayedValues(String[])
      */
     public void setFormatter(Formatter formatter) {
         if (formatter == mFormatter) {
@@ -1068,26 +1093,35 @@
         if (mValue == value) {
             return;
         }
-        if (value < mMinValue) {
-            value = mWrapSelectorWheel ? mMaxValue : mMinValue;
-        }
-        if (value > mMaxValue) {
-            value = mWrapSelectorWheel ? mMinValue : mMaxValue;
-        }
-        mValue = value;
+        setValueInternal(value, false);
         initializeSelectorWheelIndices();
-        updateInputTextView();
-        updateIncrementAndDecrementButtonsVisibilityState();
         invalidate();
     }
 
     /**
-     * Hides the soft input of it is active for the input text.
+     * Shows the soft input for its input text.
+     */
+    private void showSoftInput() {
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (mHasSelectorWheel) {
+                mInputText.setVisibility(View.VISIBLE);
+            }
+            mInputText.requestFocus();
+            inputMethodManager.showSoftInput(mInputText, 0);
+        }
+    }
+
+    /**
+     * Hides the soft input if it is active for the input text.
      */
     private void hideSoftInput() {
         InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
         if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
             inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            if (mHasSelectorWheel) {
+                mInputText.setVisibility(View.INVISIBLE);
+            }
         }
     }
 
@@ -1151,23 +1185,22 @@
      * wrap around the {@link NumberPicker#getMinValue()} and
      * {@link NumberPicker#getMaxValue()} values.
      * <p>
-     * By default if the range (max - min) is more than five (the number of
-     * items shown on the selector wheel) the selector wheel wrapping is
-     * enabled.
+     * By default if the range (max - min) is more than the number of items shown
+     * on the selector wheel the selector wheel wrapping is enabled.
      * </p>
      * <p>
-     * <strong>Note:</strong> If the number of items, i.e. the range
-     * ({@link #getMaxValue()} - {@link #getMinValue()}) is less than
-     * {@link #SELECTOR_WHEEL_ITEM_COUNT}, the selector wheel will not
-     * wrap. Hence, in such a case calling this method is a NOP.
+     * <strong>Note:</strong> If the number of items, i.e. the range (
+     * {@link #getMaxValue()} - {@link #getMinValue()}) is less than
+     * the number of items shown on the selector wheel, the selector wheel will
+     * not wrap. Hence, in such a case calling this method is a NOP.
      * </p>
+     *
      * @param wrapSelectorWheel Whether to wrap.
      */
     public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
         final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length;
         if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) {
             mWrapSelectorWheel = wrapSelectorWheel;
-            updateIncrementAndDecrementButtonsVisibilityState();
         }
     }
 
@@ -1224,6 +1257,7 @@
         initializeSelectorWheelIndices();
         updateInputTextView();
         tryComputeMaxWidth();
+        invalidate();
     }
 
     /**
@@ -1256,6 +1290,7 @@
         initializeSelectorWheelIndices();
         updateInputTextView();
         tryComputeMaxWidth();
+        invalidate();
     }
 
     /**
@@ -1300,102 +1335,49 @@
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        // make sure we show the controls only the very
-        // first time the user sees this widget
-        if (mFlingable && !isInEditMode()) {
-            // animate a bit slower the very first time
-            showInputControls(mShowInputControlsAnimimationDuration * 2);
-        }
-    }
-
-    @Override
     protected void onDetachedFromWindow() {
         removeAllCallbacks();
     }
 
     @Override
-    protected void dispatchDraw(Canvas canvas) {
-        // There is a good reason for doing this. See comments in draw().
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        // Dispatch draw to our children only if we are not currently running
-        // the animation for simultaneously dimming the scroll wheel and
-        // showing in the buttons. This class takes advantage of the View
-        // implementation of fading edges effect to draw the selector wheel.
-        // However, in View.draw(), the fading is applied after all the children
-        // have been drawn and we do not want this fading to be applied to the
-        // buttons. Therefore, we draw our children after we have completed
-        // drawing ourselves.
-        super.draw(canvas);
-
-        // Draw our children if we are not showing the selector wheel of fading
-        // it out
-        if (mShowInputControlsAnimator.isRunning()
-                || mSelectorWheelState != SELECTOR_WHEEL_STATE_LARGE) {
-            long drawTime = getDrawingTime();
-            for (int i = 0, count = getChildCount(); i < count; i++) {
-                View child = getChildAt(i);
-                if (!child.isShown()) {
-                    continue;
-                }
-                drawChild(canvas, getChildAt(i), drawTime);
-            }
-        }
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
-        if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
+        if (!mHasSelectorWheel) {
+            super.onDraw(canvas);
             return;
         }
-
         float x = (mRight - mLeft) / 2;
         float y = mCurrentScrollOffset;
 
-        final int restoreCount = canvas.save();
-
-        if (mSelectorWheelState == SELECTOR_WHEEL_STATE_SMALL) {
-            Rect clipBounds = canvas.getClipBounds();
-            clipBounds.inset(0, mSelectorElementHeight);
-            canvas.clipRect(clipBounds);
-        }
-
         // draw the selector wheel
         int[] selectorIndices = mSelectorIndices;
         for (int i = 0; i < selectorIndices.length; i++) {
             int selectorIndex = selectorIndices[i];
             String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
-            // Do not draw the middle item if input is visible since the input is shown only
-            // if the wheel is static and it covers the middle item. Otherwise, if the user
-            // starts editing the text via the IME he may see a dimmed version of the old
-            // value intermixed with the new one.
+            // Do not draw the middle item if input is visible since the input
+            // is shown only if the wheel is static and it covers the middle
+            // item. Otherwise, if the user starts editing the text via the
+            // IME he may see a dimmed version of the old value intermixed
+            // with the new one.
             if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) {
                 canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
             }
             y += mSelectorElementHeight;
         }
 
-        // draw the selection dividers (only if scrolling and drawable specified)
+        // draw the selection dividers
         if (mSelectionDivider != null) {
             // draw the top divider
-            int topOfTopDivider =
-                (getHeight() - mSelectorElementHeight - mSelectionDividerHeight) / 2;
+            int topOfTopDivider = mTopSelectionDividerTop;
             int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight;
             mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider);
             mSelectionDivider.draw(canvas);
 
             // draw the bottom divider
-            int topOfBottomDivider =  topOfTopDivider + mSelectorElementHeight;
-            int bottomOfBottomDivider = bottomOfTopDivider + mSelectorElementHeight;
+            int bottomOfBottomDivider = mBottomSelectionDividerBottom;
+            int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight;
             mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider);
             mSelectionDivider.draw(canvas);
         }
-
-        canvas.restoreToCount(restoreCount);
     }
 
     @Override
@@ -1408,12 +1390,20 @@
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         event.setClassName(NumberPicker.class.getName());
+        event.setScrollable(true);
+        event.setScrollY((mMinValue + mValue) * mSelectorElementHeight);
+        event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight);
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(NumberPicker.class.getName());
+    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
+        if (!mHasSelectorWheel) {
+            return super.getAccessibilityNodeProvider();
+        }
+        if (mAccessibilityNodeProvider == null) {
+            mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl();
+        }
+        return mAccessibilityNodeProvider;
     }
 
     /**
@@ -1442,17 +1432,17 @@
     }
 
     /**
-     * Utility to reconcile a desired size and state, with constraints imposed by
-     * a MeasureSpec. Tries to respect the min size, unless a different size is
-     * imposed by the constraints.
+     * Utility to reconcile a desired size and state, with constraints imposed
+     * by a MeasureSpec. Tries to respect the min size, unless a different size
+     * is imposed by the constraints.
      *
      * @param minSize The minimal desired size.
      * @param measuredSize The currently measured size.
      * @param measureSpec The current measure spec.
      * @return The resolved size and state.
      */
-    private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize,
-            int measureSpec) {
+    private int resolveSizeAndStateRespectingMinSize(
+            int minSize, int measuredSize, int measureSpec) {
         if (minSize != SIZE_UNSPECIFIED) {
             final int desiredWidth = Math.max(minSize, measuredSize);
             return resolveSizeAndState(desiredWidth, measureSpec, 0);
@@ -1462,8 +1452,8 @@
     }
 
     /**
-     * Resets the selector indices and clear the cached
-     * string representation of these indices.
+     * Resets the selector indices and clear the cached string representation of
+     * these indices.
      */
     private void initializeSelectorWheelIndices() {
         mSelectorIndexToStringCache.clear();
@@ -1480,39 +1470,44 @@
     }
 
     /**
-     * Sets the current value of this NumberPicker, and sets mPrevious to the
-     * previous value. If current is greater than mEnd less than mStart, the
-     * value of mCurrent is wrapped around. Subclasses can override this to
-     * change the wrapping behavior
+     * Sets the current value of this NumberPicker.
      *
-     * @param current the new value of the NumberPicker
+     * @param current The new value of the NumberPicker.
+     * @param notifyChange Whether to notify if the current value changed.
      */
-    private void changeCurrent(int current) {
+    private void setValueInternal(int current, boolean notifyChange) {
         if (mValue == current) {
             return;
         }
         // Wrap around the values if we go past the start or end
         if (mWrapSelectorWheel) {
             current = getWrappedSelectorIndex(current);
+        } else {
+            current = Math.max(current, mMinValue);
+            current = Math.min(current, mMaxValue);
         }
         int previous = mValue;
-        setValue(current);
-        notifyChange(previous, current);
+        mValue = current;
+        updateInputTextView();
+        if (notifyChange) {
+            notifyChange(previous, current);
+        }
     }
 
     /**
      * Changes the current value by one which is increment or
      * decrement based on the passes argument.
+     * decrement the current value.
      *
      * @param increment True to increment, false to decrement.
      */
-    private void changeCurrentByOne(boolean increment) {
-        if (mFlingable) {
-            mDimSelectorWheelAnimator.cancel();
+     private void changeValueByOne(boolean increment) {
+        if (mHasSelectorWheel) {
             mInputText.setVisibility(View.INVISIBLE);
-            mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
+            if (!moveToFinalScrollerPosition(mFlingScroller)) {
+                moveToFinalScrollerPosition(mAdjustScroller);
+            }
             mPreviousScrollerY = 0;
-            forceCompleteChangeCurrentByOneViaScroll();
             if (increment) {
                 mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight,
                         CHANGE_CURRENT_BY_ONE_SCROLL_DURATION);
@@ -1523,81 +1518,26 @@
             invalidate();
         } else {
             if (increment) {
-                changeCurrent(mValue + 1);
+                setValueInternal(mValue + 1, true);
             } else {
-                changeCurrent(mValue - 1);
+                setValueInternal(mValue - 1, true);
             }
         }
     }
 
-    /**
-     * Ensures that if we are in the process of changing the current value
-     * by one via scrolling the scroller gets to its final state and the
-     * value is updated.
-     */
-    private void forceCompleteChangeCurrentByOneViaScroll() {
-        Scroller scroller = mFlingScroller;
-        if (!scroller.isFinished()) {
-            final int yBeforeAbort = scroller.getCurrY();
-            scroller.abortAnimation();
-            final int yDelta = scroller.getCurrY() - yBeforeAbort;
-            scrollBy(0, yDelta);
-        }
-    }
-
-    /**
-     * Sets the <code>alpha</code> of the {@link Paint} for drawing the selector
-     * wheel.
-     */
-    @SuppressWarnings("unused")
-    // Called via reflection
-    private void setSelectorPaintAlpha(int alpha) {
-        mSelectorWheelPaint.setAlpha(alpha);
-        invalidate();
-    }
-
-    /**
-     * @return If the <code>event</code> is in the visible <code>view</code>.
-     */
-    private boolean isEventInVisibleViewHitRect(MotionEvent event, View view) {
-        if (view.getVisibility() == VISIBLE) {
-            view.getHitRect(mTempRect);
-            return mTempRect.contains((int) event.getX(), (int) event.getY());
-        }
-        return false;
-    }
-
-    /**
-     * Sets the <code>selectorWheelState</code>.
-     */
-    private void setSelectorWheelState(int selectorWheelState) {
-        mSelectorWheelState = selectorWheelState;
-        if (selectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
-            mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
-        }
-
-        if (mFlingable && selectorWheelState == SELECTOR_WHEEL_STATE_LARGE
-                && AccessibilityManager.getInstance(mContext).isEnabled()) {
-            AccessibilityManager.getInstance(mContext).interrupt();
-            String text = mContext.getString(R.string.number_picker_increment_scroll_action);
-            mInputText.setContentDescription(text);
-            mInputText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            mInputText.setContentDescription(null);
-        }
-    }
-
     private void initializeSelectorWheel() {
         initializeSelectorWheelIndices();
         int[] selectorIndices = mSelectorIndices;
         int totalTextHeight = selectorIndices.length * mTextSize;
         float totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
-        float textGapCount = selectorIndices.length - 1;
+        float textGapCount = selectorIndices.length;
         mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
         mSelectorElementHeight = mTextSize + mSelectorTextGapHeight;
-        // Ensure that the middle item is positioned the same as the text in mInputText
+        // Ensure that the middle item is positioned the same as the text in
+        // mInputText
         int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop();
-        mInitialScrollOffset = editTextTextPosition -
-                (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX);
+        mInitialScrollOffset = editTextTextPosition
+                - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX);
         mCurrentScrollOffset = mInitialScrollOffset;
         updateInputTextView();
     }
@@ -1612,16 +1552,14 @@
      */
     private void onScrollerFinished(Scroller scroller) {
         if (scroller == mFlingScroller) {
-            if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
-                postAdjustScrollerCommand(0);
-                onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-            } else {
+            if (!ensureScrollWheelAdjusted()) {
                 updateInputTextView();
-                fadeSelectorWheel(mShowInputControlsAnimimationDuration);
             }
+            onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
         } else {
-            updateInputTextView();
-            showInputControls(mShowInputControlsAnimimationDuration);
+            if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
+                updateInputTextView();
+            }
         }
     }
 
@@ -1654,56 +1592,6 @@
     }
 
     /**
-     * Hides the input controls which is the up/down arrows and the text field.
-     */
-    private void hideInputControls() {
-        mShowInputControlsAnimator.cancel();
-        mIncrementButton.setVisibility(INVISIBLE);
-        mDecrementButton.setVisibility(INVISIBLE);
-        mInputText.setVisibility(INVISIBLE);
-    }
-
-    /**
-     * Show the input controls by making them visible and animating the alpha
-     * property up/down arrows.
-     *
-     * @param animationDuration The duration of the animation.
-     */
-    private void showInputControls(long animationDuration) {
-        updateIncrementAndDecrementButtonsVisibilityState();
-        mInputText.setVisibility(VISIBLE);
-        mShowInputControlsAnimator.setDuration(animationDuration);
-        mShowInputControlsAnimator.start();
-    }
-
-    /**
-     * Fade the selector wheel via an animation.
-     *
-     * @param animationDuration The duration of the animation.
-     */
-    private void fadeSelectorWheel(long animationDuration) {
-        mInputText.setVisibility(VISIBLE);
-        mDimSelectorWheelAnimator.setDuration(animationDuration);
-        mDimSelectorWheelAnimator.start();
-    }
-
-    /**
-     * Updates the visibility state of the increment and decrement buttons.
-     */
-    private void updateIncrementAndDecrementButtonsVisibilityState() {
-        if (mWrapSelectorWheel || mValue < mMaxValue) {
-            mIncrementButton.setVisibility(VISIBLE);
-        } else {
-            mIncrementButton.setVisibility(INVISIBLE);
-        }
-        if (mWrapSelectorWheel || mValue > mMinValue) {
-            mDecrementButton.setVisibility(VISIBLE);
-        } else {
-            mDecrementButton.setVisibility(INVISIBLE);
-        }
-    }
-
-    /**
      * @return The wrapped index <code>selectorIndex</code> value.
      */
     private int getWrappedSelectorIndex(int selectorIndex) {
@@ -1749,8 +1637,7 @@
 
     /**
      * Ensures we have a cached string representation of the given <code>
-     * selectorIndex</code>
-     * to avoid multiple instantiations of the same string.
+     * selectorIndex</code> to avoid multiple instantiations of the same string.
      */
     private void ensureCachedScrollSelectorValue(int selectorIndex) {
         SparseArray<String> cache = mSelectorIndexToStringCache;
@@ -1783,7 +1670,7 @@
         } else {
             // Check the new value and ensure it's in range
             int current = getSelectedPos(str.toString());
-            changeCurrent(current);
+            setValueInternal(current, true);
         }
     }
 
@@ -1792,25 +1679,23 @@
      * the string corresponding to the index specified by the current value will
      * be returned. Otherwise, the formatter specified in {@link #setFormatter}
      * will be used to format the number.
+     *
+     * @return Whether the text was updated.
      */
-    private void updateInputTextView() {
+    private boolean updateInputTextView() {
         /*
          * If we don't have displayed values then use the current number else
          * find the correct value in the displayed values for the current
          * number.
          */
-        if (mDisplayedValues == null) {
-            mInputText.setText(formatNumber(mValue));
-        } else {
-            mInputText.setText(mDisplayedValues[mValue - mMinValue]);
+        String text = (mDisplayedValues == null) ? formatNumber(mValue)
+                : mDisplayedValues[mValue - mMinValue];
+        if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) {
+            mInputText.setText(text);
+            return true;
         }
-        mInputText.setSelection(mInputText.getText().length());
 
-        if (mFlingable && AccessibilityManager.getInstance(mContext).isEnabled()) {
-            String text = mContext.getString(R.string.number_picker_increment_scroll_mode,
-                    mInputText.getText());
-            mInputText.setContentDescription(text);
-        }
+        return false;
     }
 
     /**
@@ -1828,14 +1713,45 @@
      *
      * @param increment Whether to increment or decrement the value.
      */
-    private void postChangeCurrentByOneFromLongPress(boolean increment) {
-        mInputText.clearFocus();
-        removeAllCallbacks();
+    private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) {
         if (mChangeCurrentByOneFromLongPressCommand == null) {
             mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand();
+        } else {
+            removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
         }
-        mChangeCurrentByOneFromLongPressCommand.setIncrement(increment);
-        post(mChangeCurrentByOneFromLongPressCommand);
+        mChangeCurrentByOneFromLongPressCommand.setStep(increment);
+        postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis);
+    }
+
+    /**
+     * Removes the command for changing the current value by one.
+     */
+    private void removeChangeCurrentByOneFromLongPress() {
+        if (mChangeCurrentByOneFromLongPressCommand != null) {
+            removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
+        }
+    }
+
+    /**
+     * Posts a command for beginning an edit of the current value via IME on
+     * long press.
+     */
+    private void postBeginSoftInputOnLongPressCommand() {
+        if (mBeginSoftInputOnLongPressCommand == null) {
+            mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand();
+        } else {
+            removeCallbacks(mBeginSoftInputOnLongPressCommand);
+        }
+        postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout());
+    }
+
+    /**
+     * Removes the command for beginning an edit of the current value via IME.
+     */
+    private void removeBeginSoftInputCommand() {
+        if (mBeginSoftInputOnLongPressCommand != null) {
+            removeCallbacks(mBeginSoftInputOnLongPressCommand);
+        }
     }
 
     /**
@@ -1845,12 +1761,12 @@
         if (mChangeCurrentByOneFromLongPressCommand != null) {
             removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
         }
-        if (mAdjustScrollerCommand != null) {
-            removeCallbacks(mAdjustScrollerCommand);
-        }
         if (mSetSelectionCommand != null) {
             removeCallbacks(mSetSelectionCommand);
         }
+        if (mBeginSoftInputOnLongPressCommand != null) {
+            removeCallbacks(mBeginSoftInputOnLongPressCommand);
+        }
     }
 
     /**
@@ -1888,8 +1804,7 @@
 
     /**
      * Posts an {@link SetSelectionCommand} from the given <code>selectionStart
-     * </code> to
-     * <code>selectionEnd</code>.
+     * </code> to <code>selectionEnd</code>.
      */
     private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
         if (mSetSelectionCommand == null) {
@@ -1903,20 +1818,6 @@
     }
 
     /**
-     * Posts an {@link AdjustScrollerCommand} within the given <code>
-     * delayMillis</code>
-     * .
-     */
-    private void postAdjustScrollerCommand(int delayMillis) {
-        if (mAdjustScrollerCommand == null) {
-            mAdjustScrollerCommand = new AdjustScrollerCommand();
-        } else {
-            removeCallbacks(mAdjustScrollerCommand);
-        }
-        postDelayed(mAdjustScrollerCommand, delayMillis);
-    }
-
-    /**
      * Filter for accepting only valid indices or prefixes of the string
      * representation of valid indices.
      */
@@ -1934,8 +1835,8 @@
         }
 
         @Override
-        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
-                int dstart, int dend) {
+        public CharSequence filter(
+                CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
             if (mDisplayedValues == null) {
                 CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
                 if (filtered == null) {
@@ -1981,6 +1882,27 @@
     }
 
     /**
+     * Ensures that the scroll wheel is adjusted i.e. there is no offset and the
+     * middle element is in the middle of the widget.
+     *
+     * @return Whether an adjustment has been made.
+     */
+    private boolean ensureScrollWheelAdjusted() {
+        // adjust to the closest value
+        int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
+        if (deltaY != 0) {
+            mPreviousScrollerY = 0;
+            if (Math.abs(deltaY) > mSelectorElementHeight / 2) {
+                deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight;
+            }
+            mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS);
+            invalidate();
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Command for setting the input text selection.
      */
     class SetSelectionCommand implements Runnable {
@@ -1994,39 +1916,18 @@
     }
 
     /**
-     * Command for adjusting the scroller to show in its center the closest of
-     * the displayed items.
-     */
-    class AdjustScrollerCommand implements Runnable {
-        public void run() {
-            mPreviousScrollerY = 0;
-            if (mInitialScrollOffset == mCurrentScrollOffset) {
-                updateInputTextView();
-                showInputControls(mShowInputControlsAnimimationDuration);
-                return;
-            }
-            // adjust to the closest value
-            int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
-            if (Math.abs(deltaY) > mSelectorElementHeight / 2) {
-                deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight;
-            }
-            mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS);
-            invalidate();
-        }
-    }
-
-    /**
      * Command for changing the current value from a long press by one.
      */
     class ChangeCurrentByOneFromLongPressCommand implements Runnable {
         private boolean mIncrement;
 
-        private void setIncrement(boolean increment) {
+        private void setStep(boolean increment) {
             mIncrement = increment;
         }
 
+        @Override
         public void run() {
-            changeCurrentByOne(mIncrement);
+            changeValueByOne(mIncrement);
             postDelayed(this, mLongPressUpdateInterval);
         }
     }
@@ -2048,4 +1949,248 @@
             }
         }
     }
+
+    /**
+     * Command for beginning soft input on long press.
+     */
+    class BeginSoftInputOnLongPressCommand implements Runnable {
+
+        @Override
+        public void run() {
+            showSoftInput();
+            mIngonreMoveEvents = true;
+        }
+    }
+
+    class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider {
+        private static final int VIRTUAL_VIEW_ID_INCREMENT = 1;
+
+        private static final int VIRTUAL_VIEW_ID_INPUT = 2;
+
+        private static final int VIRTUAL_VIEW_ID_DECREMENT = 3;
+
+        private final Rect mTempRect = new Rect();
+
+        private final int[] mTempArray = new int[2];
+
+        @Override
+        public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
+            switch (virtualViewId) {
+                case View.NO_ID:
+                    return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY,
+                            mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop));
+                case VIRTUAL_VIEW_ID_DECREMENT:
+                    return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT,
+                            getVirtualDecrementButtonText(), mScrollX, mScrollY,
+                            mScrollX + (mRight - mLeft),
+                            mTopSelectionDividerTop + mSelectionDividerHeight);
+                case VIRTUAL_VIEW_ID_INPUT:
+                    return createAccessibiltyNodeInfoForInputText();
+                case VIRTUAL_VIEW_ID_INCREMENT:
+                    return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT,
+                            getVirtualIncrementButtonText(), mScrollX,
+                            mBottomSelectionDividerBottom - mSelectionDividerHeight,
+                            mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop));
+            }
+            return super.createAccessibilityNodeInfo(virtualViewId);
+        }
+
+        @Override
+        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched,
+                int virtualViewId) {
+            if (TextUtils.isEmpty(searched)) {
+                return Collections.emptyList();
+            }
+            String searchedLowerCase = searched.toLowerCase();
+            List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>();
+            switch (virtualViewId) {
+                case View.NO_ID: {
+                    findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
+                            VIRTUAL_VIEW_ID_DECREMENT, result);
+                    findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
+                            VIRTUAL_VIEW_ID_INPUT, result);
+                    findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
+                            VIRTUAL_VIEW_ID_INCREMENT, result);
+                    return result;
+                }
+                case VIRTUAL_VIEW_ID_DECREMENT:
+                case VIRTUAL_VIEW_ID_INCREMENT:
+                case VIRTUAL_VIEW_ID_INPUT: {
+                    findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId,
+                            result);
+                    return result;
+                }
+            }
+            return super.findAccessibilityNodeInfosByText(searched, virtualViewId);
+        }
+
+        @Override
+        public boolean performAccessibilityAction(int action, int virtualViewId) {
+            switch (virtualViewId) {
+                case VIRTUAL_VIEW_ID_INPUT: {
+                    switch (action) {
+                        case AccessibilityNodeInfo.ACTION_FOCUS: {
+                            if (!mInputText.isFocused()) {
+                                return mInputText.requestFocus();
+                            }
+                        } break;
+                        case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
+                            if (mInputText.isFocused()) {
+                                mInputText.clearFocus();
+                                return true;
+                            }
+                        } break;
+                    }
+                } break;
+            }
+            return super.performAccessibilityAction(action, virtualViewId);
+        }
+
+        public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) {
+            switch (virtualViewId) {
+                case VIRTUAL_VIEW_ID_DECREMENT: {
+                    sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
+                            getVirtualDecrementButtonText());
+                } break;
+                case VIRTUAL_VIEW_ID_INPUT: {
+                    sendAccessibilityEventForVirtualText(eventType);
+                } break;
+                case VIRTUAL_VIEW_ID_INCREMENT: {
+                    sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
+                            getVirtualIncrementButtonText());
+                } break;
+            }
+        }
+
+        private void sendAccessibilityEventForVirtualText(int eventType) {
+            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+            mInputText.onInitializeAccessibilityEvent(event);
+            mInputText.onPopulateAccessibilityEvent(event);
+            event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+            requestSendAccessibilityEvent(NumberPicker.this, event);
+        }
+
+        private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType,
+                String text) {
+            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+            event.setClassName(Button.class.getName());
+            event.setPackageName(mContext.getPackageName());
+            event.getText().add(text);
+            event.setEnabled(NumberPicker.this.isEnabled());
+            event.setSource(NumberPicker.this, virtualViewId);
+            requestSendAccessibilityEvent(NumberPicker.this, event);
+        }
+
+        private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase,
+                int virtualViewId, List<AccessibilityNodeInfo> outResult) {
+            switch (virtualViewId) {
+                case VIRTUAL_VIEW_ID_DECREMENT: {
+                    String text = getVirtualDecrementButtonText();
+                    if (!TextUtils.isEmpty(text)
+                            && text.toString().toLowerCase().contains(searchedLowerCase)) {
+                        outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT));
+                    }
+                } return;
+                case VIRTUAL_VIEW_ID_INPUT: {
+                    CharSequence text = mInputText.getText();
+                    if (!TextUtils.isEmpty(text) &&
+                            text.toString().toLowerCase().contains(searchedLowerCase)) {
+                        outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT));
+                        return;
+                    }
+                    CharSequence contentDesc = mInputText.getText();
+                    if (!TextUtils.isEmpty(contentDesc) &&
+                            contentDesc.toString().toLowerCase().contains(searchedLowerCase)) {
+                        outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT));
+                        return;
+                    }
+                } break;
+                case VIRTUAL_VIEW_ID_INCREMENT: {
+                    String text = getVirtualIncrementButtonText();
+                    if (!TextUtils.isEmpty(text)
+                            && text.toString().toLowerCase().contains(searchedLowerCase)) {
+                        outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT));
+                    }
+                } return;
+            }
+        }
+
+        private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() {
+            AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo();
+            info.setLongClickable(true);
+            info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+            return info;
+        }
+
+        private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId,
+                String text, int left, int top, int right, int bottom) {
+            AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+            info.setClassName(Button.class.getName());
+            info.setPackageName(mContext.getPackageName());
+            info.setSource(NumberPicker.this, virtualViewId);
+            info.setParent(NumberPicker.this);
+            info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT);
+            info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+            info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
+            info.setText(text);
+            info.setClickable(true);
+            info.setLongClickable(true);
+            info.setEnabled(NumberPicker.this.isEnabled());
+            Rect boundsInParent = mTempRect;
+            boundsInParent.set(left, top, right, bottom);
+            info.setBoundsInParent(boundsInParent);
+            Rect boundsInScreen = boundsInParent;
+            int[] locationOnScreen = mTempArray;
+            getLocationOnScreen(locationOnScreen);
+            boundsInScreen.offsetTo(0, 0);
+            boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
+            info.setBoundsInScreen(boundsInScreen);
+            return info;
+        }
+
+        private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top,
+                int right, int bottom) {
+            AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+            info.setClassName(Button.class.getName());
+            info.setPackageName(mContext.getPackageName());
+            info.setSource(NumberPicker.this);
+            info.setParent((View) getParent());
+            info.setEnabled(NumberPicker.this.isEnabled());
+            info.setScrollable(true);
+            Rect boundsInParent = mTempRect;
+            boundsInParent.set(left, top, right, bottom);
+            info.setBoundsInParent(boundsInParent);
+            Rect boundsInScreen = boundsInParent;
+            int[] locationOnScreen = mTempArray;
+            getLocationOnScreen(locationOnScreen);
+            boundsInScreen.offsetTo(0, 0);
+            boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
+            info.setBoundsInScreen(boundsInScreen);
+            return info;
+        }
+
+        private String getVirtualDecrementButtonText() {
+            int value = mValue - 1;
+            if (mWrapSelectorWheel) {
+                value = getWrappedSelectorIndex(value);
+            }
+            if (value >= mMinValue) {
+                return (mDisplayedValues == null) ? formatNumber(value)
+                        : mDisplayedValues[value - mMinValue];
+            }
+            return null;
+        }
+
+        private String getVirtualIncrementButtonText() {
+            int value = mValue + 1;
+            if (mWrapSelectorWheel) {
+                value = getWrappedSelectorIndex(value);
+            }
+            if (value <= mMaxValue) {
+                return (mDisplayedValues == null) ? formatNumber(value)
+                        : mDisplayedValues[value - mMinValue];
+            }
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 25dd438..e0e3e93 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -642,8 +642,7 @@
                 break;
             case MotionEvent.ACTION_POINTER_DOWN: {
                 final int index = ev.getActionIndex();
-                final float y = ev.getY(index);
-                mLastMotionY = y;
+                mLastMotionY = ev.getY(index);
                 mActivePointerId = ev.getPointerId(index);
                 break;
             }
@@ -715,6 +714,7 @@
         } else {
             super.scrollTo(scrollX, scrollY);
         }
+
         awakenScrollBars();
     }
 
@@ -749,42 +749,6 @@
 
     /**
      * <p>
-     * Finds the next focusable component that fits in this View's bounds
-     * (excluding fading edges) pretending that this View's top is located at
-     * the parameter top.
-     * </p>
-     *
-     * @param topFocus           look for a candidate at the top of the bounds if topFocus is true,
-     *                           or at the bottom of the bounds if topFocus is false
-     * @param top                the top offset of the bounds in which a focusable must be
-     *                           found (the fading edge is assumed to start at this position)
-     * @param preferredFocusable the View that has highest priority and will be
-     *                           returned if it is within my bounds (null is valid)
-     * @return the next focusable component in the bounds or null if none can be found
-     */
-    private View findFocusableViewInMyBounds(final boolean topFocus,
-            final int top, View preferredFocusable) {
-        /*
-         * The fading edge's transparent side should be considered for focus
-         * since it's mostly visible, so we divide the actual fading edge length
-         * by 2.
-         */
-        final int fadingEdgeLength = getVerticalFadingEdgeLength() / 2;
-        final int topWithoutFadingEdge = top + fadingEdgeLength;
-        final int bottomWithoutFadingEdge = top + getHeight() - fadingEdgeLength;
-
-        if ((preferredFocusable != null)
-                && (preferredFocusable.getTop() < bottomWithoutFadingEdge)
-                && (preferredFocusable.getBottom() > topWithoutFadingEdge)) {
-            return preferredFocusable;
-        }
-
-        return findFocusableViewInBounds(topFocus, topWithoutFadingEdge,
-                bottomWithoutFadingEdge);
-    }
-
-    /**
-     * <p>
      * Finds the next focusable component that fits in the specified bounds.
      * </p>
      *
@@ -1208,10 +1172,10 @@
                 }
             }
 
-            awakenScrollBars();
-
-            // Keep on drawing until the animation has finished.
-            postInvalidate();
+            if (!awakenScrollBars()) {
+                // Keep on drawing until the animation has finished.
+                invalidate();
+            }
         } else {
             if (mFlingStrictSpan != null) {
                 mFlingStrictSpan.finish();
@@ -1438,7 +1402,7 @@
     /**
      * Return true if child is a descendant of parent, (or equal to the parent).
      */
-    private boolean isViewDescendantOf(View child, View parent) {
+    private static boolean isViewDescendantOf(View child, View parent) {
         if (child == parent) {
             return true;
         }
@@ -1462,8 +1426,6 @@
             mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0,
                     Math.max(0, bottom - height), 0, height/2);
 
-            final boolean movingDown = velocityY > 0;
-
             if (mFlingStrictSpan == null) {
                 mFlingStrictSpan = StrictMode.enterCriticalSpan("ScrollView-fling");
             }
@@ -1554,7 +1516,7 @@
         }
     }
 
-    private int clamp(int n, int my, int child) {
+    private static int clamp(int n, int my, int child) {
         if (my >= child || n < 0) {
             /* my >= child is this case:
              *                    |--------------- me ---------------|
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 7eff1aa..bc88b62 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -532,21 +532,28 @@
 
     private void setContentDescriptions() {
         // Minute
-        String text = mContext.getString(R.string.time_picker_increment_minute_button);
-        mMinuteSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.time_picker_decrement_minute_button);
-        mMinuteSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        trySetContentDescription(mMinuteSpinner, R.id.increment,
+                R.string.time_picker_increment_minute_button);
+        trySetContentDescription(mMinuteSpinner, R.id.decrement,
+                R.string.time_picker_decrement_minute_button);
         // Hour
-        text = mContext.getString(R.string.time_picker_increment_hour_button);
-        mHourSpinner.findViewById(R.id.increment).setContentDescription(text);
-        text = mContext.getString(R.string.time_picker_decrement_hour_button);
-        mHourSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        trySetContentDescription(mHourSpinner, R.id.increment,
+                R.string.time_picker_increment_hour_button);
+        trySetContentDescription(mHourSpinner, R.id.decrement,
+                R.string.time_picker_decrement_hour_button);
         // AM/PM
         if (mAmPmSpinner != null) {
-            text = mContext.getString(R.string.time_picker_increment_set_pm_button);
-            mAmPmSpinner.findViewById(R.id.increment).setContentDescription(text);
-            text = mContext.getString(R.string.time_picker_decrement_set_am_button);
-            mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text);
+            trySetContentDescription(mAmPmSpinner, R.id.increment,
+                    R.string.time_picker_increment_set_pm_button);
+            trySetContentDescription(mAmPmSpinner, R.id.decrement,
+                    R.string.time_picker_decrement_set_am_button);
+        }
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 04147ab..2564921 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -382,7 +382,10 @@
         }
 
         if (mIconResId != NO_ICON) {
-            return mMenu.getResources().getDrawable(mIconResId);
+            Drawable icon =  mMenu.getResources().getDrawable(mIconResId);
+            mIconResId = NO_ICON;
+            mIconDrawable = icon;
+            return icon;
         }
         
         return null;
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index d51ced11..f2b6e45 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -164,9 +164,10 @@
         mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount,
                 mFeedbackCount);
         mHandleDrawable = new TargetDrawable(res,
-                a.getDrawable(R.styleable.MultiWaveView_handleDrawable));
+                a.peekValue(R.styleable.MultiWaveView_handleDrawable).resourceId);
         mTapRadius = mHandleDrawable.getWidth()/2;
-        mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable));
+        mOuterRing = new TargetDrawable(res,
+                a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
 
         // Read chevron animation drawables
         final int chevrons[] = { R.styleable.MultiWaveView_leftChevronDrawable,
@@ -174,11 +175,12 @@
                 R.styleable.MultiWaveView_topChevronDrawable,
                 R.styleable.MultiWaveView_bottomChevronDrawable
         };
+
         for (int chevron : chevrons) {
-            Drawable chevronDrawable = a.getDrawable(chevron);
+            TypedValue typedValue = a.peekValue(chevron);
             for (int i = 0; i < mFeedbackCount; i++) {
                 mChevronDrawables.add(
-                    chevronDrawable != null ? new TargetDrawable(res, chevronDrawable) : null);
+                    typedValue != null ? new TargetDrawable(res, typedValue.resourceId) : null);
             }
         }
 
@@ -519,8 +521,8 @@
         int count = array.length();
         ArrayList<TargetDrawable> targetDrawables = new ArrayList<TargetDrawable>(count);
         for (int i = 0; i < count; i++) {
-            Drawable drawable = array.getDrawable(i);
-            targetDrawables.add(new TargetDrawable(res, drawable));
+            TypedValue value = array.peekValue(i);
+            targetDrawables.add(new TargetDrawable(res, value != null ? value.resourceId : 0));
         }
         array.recycle();
         mTargetResourceId = resourceId;
@@ -679,7 +681,7 @@
         if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
         switchToState(STATE_FINISH, event.getX(), event.getY());
     }
-    
+
     private void handleCancel(MotionEvent event) {
         if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
         mActiveTarget = -1; // Drop the active target if canceled.
@@ -723,7 +725,7 @@
                     float dx = limitX - target.getX();
                     float dy = limitY - target.getY();
                     float dist2 = dx*dx + dy*dy;
-                    if (target.isValid() && dist2 < hitRadius2 && dist2 < best) {
+                    if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
                         activeTarget = i;
                         best = dist2;
                     }
@@ -968,4 +970,34 @@
         array.recycle();
         return targetContentDescriptions;
     }
+
+    public int getResourceIdForTarget(int index) {
+        final TargetDrawable drawable = mTargetDrawables.get(index);
+        return drawable == null ? 0 : drawable.getResourceId();
+    }
+
+    public void setEnableTarget(int resourceId, boolean enabled) {
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            final TargetDrawable target = mTargetDrawables.get(i);
+            if (target.getResourceId() == resourceId) {
+                target.setEnabled(enabled);
+                break; // should never be more than one match
+            }
+        }
+    }
+
+    /**
+     * Gets the position of a target in the array that matches the given resource.
+     * @param resourceId
+     * @return the index or -1 if not found
+     */
+    public int getTargetPosition(int resourceId) {
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            final TargetDrawable target = mTargetDrawables.get(i);
+            if (target.getResourceId() == resourceId) {
+                return i; // should never be more than one match
+            }
+        }
+        return -1;
+    }
 }
diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
index aa9fa45..ec2c945 100644
--- a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
+++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
@@ -40,6 +40,8 @@
     private float mScaleY = 1.0f;
     private float mAlpha = 1.0f;
     private Drawable mDrawable;
+    private boolean mEnabled = true;
+    private int mResourceId;
 
     /* package */ static class DrawableWithAlpha extends Drawable {
         private float mAlpha = 1.0f;
@@ -72,10 +74,8 @@
     }
 
     public TargetDrawable(Resources res, int resId) {
-        this(res, resId == 0 ? null : res.getDrawable(resId));
-    }
-
-    public TargetDrawable(Resources res, Drawable drawable) {
+        mResourceId = resId;
+        Drawable drawable = resId == 0 ? null : res.getDrawable(resId);
         // Mutate the drawable so we can animate shared drawable properties.
         mDrawable = drawable != null ? drawable.mutate() : null;
         resizeDrawables();
@@ -122,8 +122,8 @@
      *
      * @return
      */
-    public boolean isValid() {
-        return mDrawable != null;
+    public boolean isEnabled() {
+        return mDrawable != null && mEnabled;
     }
 
     /**
@@ -205,7 +205,7 @@
     }
 
     public void draw(Canvas canvas) {
-        if (mDrawable == null) {
+        if (mDrawable == null || !mEnabled) {
             return;
         }
         canvas.save(Canvas.MATRIX_SAVE_FLAG);
@@ -216,4 +216,12 @@
         mDrawable.draw(canvas);
         canvas.restore();
     }
+
+    public void setEnabled(boolean enabled) {
+        mEnabled  = enabled;
+    }
+
+    public int getResourceId() {
+        return mResourceId;
+    }
 }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index c9eb640..dcd1d28 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -90,8 +90,54 @@
     return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID);
 }
 
+static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale) {
+    chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
+    chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
+    chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
+    chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
+
+    for (int i = 0; i < chunk->numXDivs; i++) {
+        chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
+        if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
+            chunk->xDivs[i]++;
+        }
+    }
+
+    for (int i = 0; i < chunk->numYDivs; i++) {
+        chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
+        if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
+            chunk->yDivs[i]++;
+        }
+    }
+}
+
+static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
+        jobject padding) {
+
+    jbyte* array = env->GetByteArrayElements(chunkObject, 0);
+    if (array != NULL) {
+        size_t chunkSize = env->GetArrayLength(chunkObject);
+        void* storage = alloca(chunkSize);
+        android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
+        memcpy(chunk, array, chunkSize);
+        android::Res_png_9patch::deserialize(chunk);
+
+        scaleNinePatchChunk(chunk, scale);
+        memcpy(array, chunk, chunkSize);
+
+        if (padding) {
+            GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
+                    chunk->paddingRight, chunk->paddingBottom);
+        }
+
+        env->ReleaseByteArrayElements(chunkObject, array, 0);
+    }
+    return chunkObject;
+}
+
 static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
-                                   int sampleSize, bool ditherImage) {
+        int sampleSize, bool ditherImage) {
+
     SkImageRef* pr;
     // only use ashmem for large images, since mmaps come at a price
     if (bitmap->getSize() >= 32 * 1024) {
@@ -109,22 +155,29 @@
 // i.e. dynamically allocated, since its lifetime may exceed the current stack
 // frame.
 static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
-                        jobject options, bool allowPurgeable,
-                        bool forcePurgeable = false) {
+        jobject options, bool allowPurgeable, bool forcePurgeable = false,
+        bool applyScale = false, float scale = 1.0f) {
+
     int sampleSize = 1;
+
     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
     SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
+
     bool doDither = true;
     bool isMutable = false;
-    bool isPurgeable = forcePurgeable || (allowPurgeable && optionsPurgeable(env, options));
+    bool willScale = applyScale && scale != 1.0f;
+    bool isPurgeable = !willScale &&
+            (forcePurgeable || (allowPurgeable && optionsPurgeable(env, options)));
     bool preferQualityOverSpeed = false;
+
     jobject javaBitmap = NULL;
 
-    if (NULL != options) {
+    if (options != NULL) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
         if (optionsJustBounds(env, options)) {
             mode = SkImageDecoder::kDecodeBounds_Mode;
         }
+
         // initialize these, in case we fail later on
         env->SetIntField(options, gOptions_widthFieldID, -1);
         env->SetIntField(options, gOptions_heightFieldID, -1);
@@ -139,8 +192,12 @@
         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
     }
 
+    if (willScale && javaBitmap != NULL) {
+        return nullObjectReturn("Cannot pre-scale a reused bitmap");
+    }
+
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
-    if (NULL == decoder) {
+    if (decoder == NULL) {
         return nullObjectReturn("SkImageDecoder::Factory returned null");
     }
 
@@ -148,35 +205,35 @@
     decoder->setDitherImage(doDither);
     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
 
-    NinePatchPeeker     peeker(decoder);
-    JavaPixelAllocator  javaAllocator(env);
-    SkBitmap*           bitmap;
+    NinePatchPeeker peeker(decoder);
+    JavaPixelAllocator javaAllocator(env);
+
+    SkBitmap* bitmap;
     if (javaBitmap == NULL) {
         bitmap = new SkBitmap;
     } else {
         if (sampleSize != 1) {
             return nullObjectReturn("SkImageDecoder: Cannot reuse bitmap with sampleSize != 1");
         }
-        bitmap = (SkBitmap *) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
+        bitmap = (SkBitmap*) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
         // config of supplied bitmap overrules config set in options
         prefConfig = bitmap->getConfig();
     }
-    Res_png_9patch      dummy9Patch;
 
-    SkAutoTDelete<SkImageDecoder>   add(decoder);
-    SkAutoTDelete<SkBitmap>         adb(bitmap, (javaBitmap == NULL));
+    SkAutoTDelete<SkImageDecoder> add(decoder);
+    SkAutoTDelete<SkBitmap> adb(bitmap, javaBitmap == NULL);
 
     decoder->setPeeker(&peeker);
     if (!isPurgeable) {
         decoder->setAllocator(&javaAllocator);
     }
 
-    AutoDecoderCancel   adc(options, decoder);
+    AutoDecoderCancel adc(options, decoder);
 
     // To fix the race condition in case "requestCancelDecode"
     // happens earlier than AutoDecoderCancel object is added
     // to the gAutoDecoderCancelMutex linked list.
-    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
+    if (options != NULL && env->GetBooleanField(options, gOptions_mCancelID)) {
         return nullObjectReturn("gOptions_mCancelID");
     }
 
@@ -184,38 +241,57 @@
     if (isPurgeable) {
         decodeMode = SkImageDecoder::kDecodeBounds_Mode;
     }
-    if (!decoder->decode(stream, bitmap, prefConfig, decodeMode, javaBitmap != NULL)) {
+
+    SkBitmap* decoded;
+    if (willScale) {
+        decoded = new SkBitmap;
+    } else {
+        decoded = bitmap;
+    }
+    SkAutoTDelete<SkBitmap> adb2(willScale ? decoded : NULL);
+
+    if (!decoder->decode(stream, decoded, prefConfig, decodeMode, javaBitmap != NULL)) {
         return nullObjectReturn("decoder->decode returned false");
     }
 
+    int scaledWidth = decoded->width();
+    int scaledHeight = decoded->height();
+
+    if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) {
+        scaledWidth = int(scaledWidth * scale + 0.5f);
+        scaledHeight = int(scaledHeight * scale + 0.5f);
+    }
+
     // update options (if any)
-    if (NULL != options) {
-        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
-        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
-        // TODO: set the mimeType field with the data from the codec.
-        // but how to reuse a set of strings, rather than allocating new one
-        // each time?
+    if (options != NULL) {
+        env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
+        env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
         env->SetObjectField(options, gOptions_mimeFieldID,
-                            getMimeTypeString(env, decoder->getFormat()));
+                getMimeTypeString(env, decoder->getFormat()));
     }
 
     // if we're in justBounds mode, return now (skip the java bitmap)
-    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+    if (mode == SkImageDecoder::kDecodeBounds_Mode) {
         return NULL;
     }
 
     jbyteArray ninePatchChunk = NULL;
     if (peeker.fPatchIsValid) {
+        if (willScale) {
+            scaleNinePatchChunk(peeker.fPatch, scale);
+        }
+
         size_t ninePatchArraySize = peeker.fPatch->serializedSize();
         ninePatchChunk = env->NewByteArray(ninePatchArraySize);
-        if (NULL == ninePatchChunk) {
+        if (ninePatchChunk == NULL) {
             return nullObjectReturn("ninePatchChunk == null");
         }
-        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk,
-                                                              NULL);
-        if (NULL == array) {
+
+        jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL);
+        if (array == NULL) {
             return nullObjectReturn("primitive array == null");
         }
+
         peeker.fPatch->serialize(array);
         env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
     }
@@ -223,13 +299,32 @@
     // detach bitmap from its autodeleter, since we want to own it now
     adb.detach();
 
+    if (willScale) {
+        // This is weird so let me explain: we could use the scale parameter
+        // directly, but for historical reasons this is how the corresponding
+        // Dalvik code has always behaved. We simply recreate the behavior here.
+        // The result is slightly different from simply using scale because of
+        // the 0.5f rounding bias applied when computing the target image size
+        const float sx = scaledWidth / float(decoded->width());
+        const float sy = scaledHeight / float(decoded->height());
+
+        bitmap->setConfig(decoded->getConfig(), scaledWidth, scaledHeight);
+        bitmap->allocPixels(&javaAllocator, NULL);
+        bitmap->eraseColor(0);
+
+        SkPaint paint;
+        paint.setFilterBitmap(true);
+
+        SkCanvas canvas(*bitmap);
+        canvas.scale(sx, sy);
+        canvas.drawBitmap(*decoded, 0.0f, 0.0f, &paint);
+    }
+
     if (padding) {
         if (peeker.fPatchIsValid) {
             GraphicsJNI::set_jrect(env, padding,
-                                   peeker.fPatch->paddingLeft,
-                                   peeker.fPatch->paddingTop,
-                                   peeker.fPatch->paddingRight,
-                                   peeker.fPatch->paddingBottom);
+                    peeker.fPatch->paddingLeft, peeker.fPatch->paddingTop,
+                    peeker.fPatch->paddingRight, peeker.fPatch->paddingBottom);
         } else {
             GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
         }
@@ -258,22 +353,26 @@
             isMutable, ninePatchChunk);
 }
 
-static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
-                                  jobject is,       // InputStream
-                                  jbyteArray storage,   // byte[]
-                                  jobject padding,
-                                  jobject options) {  // BitmapFactory$Options
+static jobject nativeDecodeStreamScaled(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
+        jobject padding, jobject options, jboolean applyScale, jfloat scale) {
+
     jobject bitmap = NULL;
     SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0);
 
     if (stream) {
         // for now we don't allow purgeable with java inputstreams
-        bitmap = doDecode(env, stream, padding, options, false);
+        bitmap = doDecode(env, stream, padding, options, false, false, applyScale, scale);
         stream->unref();
     }
     return bitmap;
 }
 
+static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
+        jobject padding, jobject options) {
+
+    return nativeDecodeStreamScaled(env, clazz, is, storage, padding, options, false, 1.0f);
+}
+
 static ssize_t getFDSize(int fd) {
     off64_t curr = ::lseek64(fd, 0, SEEK_CUR);
     if (curr < 0) {
@@ -284,10 +383,9 @@
     return size;
 }
 
-static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
-                                          jobject fileDescriptor,
-                                          jobject padding,
-                                          jobject bitmapFactoryOptions) {
+static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
+        jobject padding, jobject bitmapFactoryOptions) {
+
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -349,10 +447,9 @@
     return stream;
 }
 
-static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz,
-                                 jint native_asset,    // Asset
-                                 jobject padding,       // Rect
-                                 jobject options) { // BitmapFactory$Options
+static jobject nativeDecodeAssetScaled(JNIEnv* env, jobject clazz, jint native_asset,
+        jobject padding, jobject options, jboolean applyScale, jfloat scale) {
+
     SkStream* stream;
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     bool forcePurgeable = optionsPurgeable(env, options);
@@ -360,7 +457,7 @@
         // if we could "ref/reopen" the asset, we may not need to copy it here
         // and we could assume optionsShareable, since assets are always RO
         stream = copyAssetToStream(asset);
-        if (NULL == stream) {
+        if (stream == NULL) {
             return NULL;
         }
     } else {
@@ -369,18 +466,24 @@
         stream = new AssetStreamAdaptor(asset);
     }
     SkAutoUnref aur(stream);
-    return doDecode(env, stream, padding, options, true, forcePurgeable);
+    return doDecode(env, stream, padding, options, true, forcePurgeable, applyScale, scale);
+}
+
+static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset,
+        jobject padding, jobject options) {
+
+    return nativeDecodeAssetScaled(env, clazz, native_asset, padding, options, false, 1.0f);
 }
 
 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
-                                     int offset, int length, jobject options) {
+        int offset, int length, jobject options) {
+
     /*  If optionsShareable() we could decide to just wrap the java array and
         share it, but that means adding a globalref to the java array object
         and managing its lifetime. For now we just always copy the array's data
         if optionsPurgeable(), unless we're just decoding bounds.
      */
-    bool purgeable = optionsPurgeable(env, options)
-            && !optionsJustBounds(env, options);
+    bool purgeable = optionsPurgeable(env, options) && !optionsJustBounds(env, options);
     AutoJavaByteArray ar(env, byteArray);
     SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable);
     SkAutoUnref aur(stream);
@@ -391,48 +494,6 @@
     (void)AutoDecoderCancel::RequestCancel(joptions);
 }
 
-static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
-        jobject padding) {
-
-    jbyte* array = env->GetByteArrayElements(chunkObject, 0);
-    if (array != NULL) {
-        size_t chunkSize = env->GetArrayLength(chunkObject);
-        void* storage = alloca(chunkSize);
-        android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
-        memcpy(chunk, array, chunkSize);
-        android::Res_png_9patch::deserialize(chunk);
-
-        chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
-        chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
-        chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
-        chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
-
-        for (int i = 0; i < chunk->numXDivs; i++) {
-            chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
-            if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
-                chunk->xDivs[i]++;
-            }
-        }
-
-        for (int i = 0; i < chunk->numYDivs; i++) {
-            chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
-            if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
-                chunk->yDivs[i]++;
-            }
-        }
-
-        memcpy(array, chunk, chunkSize);
-
-        if (padding) {
-            GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
-                    chunk->paddingRight, chunk->paddingBottom);
-        }
-
-        env->ReleaseByteArrayElements(chunkObject, array, 0);
-    }
-    return chunkObject;
-}
-
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
@@ -445,6 +506,10 @@
         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
     },
+    {   "nativeDecodeStream",
+        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;ZF)Landroid/graphics/Bitmap;",
+        (void*)nativeDecodeStreamScaled
+    },
 
     {   "nativeDecodeFileDescriptor",
         "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
@@ -456,6 +521,11 @@
         (void*)nativeDecodeAsset
     },
 
+    {   "nativeDecodeAsset",
+        "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;ZF)Landroid/graphics/Bitmap;",
+        (void*)nativeDecodeAssetScaled
+    },
+
     {   "nativeDecodeByteArray",
         "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeByteArray
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_dark.png
deleted file mode 100644
index 9584649..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_light.png
deleted file mode 100644
index 5c37873..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_dark.png
deleted file mode 100644
index b5faf6f..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_light.png
deleted file mode 100644
index 041412b..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_dark.png
deleted file mode 100644
index 5717bee..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_light.png
deleted file mode 100644
index e874330..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_dark.png
deleted file mode 100644
index 96a6c8a..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_light.png
deleted file mode 100644
index 96a6c8a..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_dark.png
deleted file mode 100644
index 4631d85..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_light.png
deleted file mode 100644
index 39c7af4..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_dark.png
deleted file mode 100644
index 9c23a18..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_light.png
deleted file mode 100644
index 9c23a18..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_down_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_dark.png
deleted file mode 100644
index 159913c..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_light.png
deleted file mode 100644
index cfee4b7..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_dark.png
deleted file mode 100644
index e5f0430..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_light.png
deleted file mode 100644
index 7e4ec4a..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_dark.png
deleted file mode 100644
index b06017e..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_light.png
deleted file mode 100644
index a1000f8..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_dark.png
deleted file mode 100644
index b3d6706..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_light.png
deleted file mode 100644
index b3d6706..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_dark.png
deleted file mode 100644
index 9ee35c7..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_light.png
deleted file mode 100644
index 4da4fa7..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_dark.png b/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_dark.png
deleted file mode 100644
index 358a13f..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_light.png b/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_light.png
deleted file mode 100644
index 358a13f..0000000
--- a/core/res/res/drawable-hdpi/numberpicker_up_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_dark.png
deleted file mode 100644
index 50f6e98..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_light.png
deleted file mode 100644
index 67434f6..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_dark.png
deleted file mode 100644
index 9c2b833..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_light.png
deleted file mode 100644
index dcf2fb7..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_dark.png
deleted file mode 100644
index b63c510d..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_light.png
deleted file mode 100644
index 55312a1..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_dark.png
deleted file mode 100644
index 48e300c..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_light.png
deleted file mode 100644
index 48e300c..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_dark.png
deleted file mode 100644
index 1558d3d..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_light.png
deleted file mode 100644
index 6b6e7e1..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_dark.png
deleted file mode 100644
index eb16f8d..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_light.png
deleted file mode 100644
index eb16f8d..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_down_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_dark.png
deleted file mode 100644
index 58a3b64..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_light.png
deleted file mode 100644
index 382943b..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_dark.png
deleted file mode 100644
index cf856a1..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_light.png
deleted file mode 100644
index 6665953..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_dark.png
deleted file mode 100644
index d63d797..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_light.png
deleted file mode 100644
index 22b6dbd..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_dark.png
deleted file mode 100644
index 4bcce98..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_light.png
deleted file mode 100644
index 4bcce98..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_dark.png
deleted file mode 100644
index 12ba823..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_light.png
deleted file mode 100644
index d841f5a..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_dark.png b/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_dark.png
deleted file mode 100644
index bc5e3fa..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_light.png b/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_light.png
deleted file mode 100644
index bc5e3fa..0000000
--- a/core/res/res/drawable-mdpi/numberpicker_up_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_dark.png
deleted file mode 100644
index 111f57e..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_light.png
deleted file mode 100644
index d0ef05b..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_dark.png
deleted file mode 100644
index ff21941..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_light.png
deleted file mode 100644
index 3e9bdda..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_dark.png
deleted file mode 100644
index 0462fca..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_light.png
deleted file mode 100644
index a488e8e..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_dark.png
deleted file mode 100644
index f61b076..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_light.png
deleted file mode 100644
index f61b076..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_dark.png
deleted file mode 100644
index 211944e..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_light.png
deleted file mode 100644
index 12bc11a..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_dark.png
deleted file mode 100644
index 635184c..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_light.png
deleted file mode 100644
index 635184c..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_down_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_dark.png
deleted file mode 100644
index 470e569..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_light.png
deleted file mode 100644
index 16df74d..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_dark.png
deleted file mode 100644
index edd4c04..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_light.png
deleted file mode 100644
index d8f459a..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_disabled_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_dark.png
deleted file mode 100644
index 08bf241..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_light.png
deleted file mode 100644
index b2c40f1..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_dark.png
deleted file mode 100644
index f4f7331..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_light.png
deleted file mode 100644
index f4f7331..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_longpressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_dark.png
deleted file mode 100644
index 83650b1..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_light.png
deleted file mode 100644
index 78085d3..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_dark.png
deleted file mode 100644
index b8f6849..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_light.png b/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_light.png
deleted file mode 100644
index b8f6849..0000000
--- a/core/res/res/drawable-xhdpi/numberpicker_up_pressed_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/numberpicker_down_btn_holo_dark.xml b/core/res/res/drawable/numberpicker_down_btn_holo_dark.xml
deleted file mode 100644
index dd6332d..0000000
--- a/core/res/res/drawable/numberpicker_down_btn_holo_dark.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_down_normal_holo_dark" />
-
-    <item android:state_pressed="true"
-          android:state_enabled="true"
-          android:drawable="@drawable/numberpicker_down_pressed_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_down_focused_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_down_disabled_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_down_disabled_focused_holo_dark" />
-
-</selector>
diff --git a/core/res/res/drawable/numberpicker_down_btn_holo_light.xml b/core/res/res/drawable/numberpicker_down_btn_holo_light.xml
deleted file mode 100644
index 565fd86..0000000
--- a/core/res/res/drawable/numberpicker_down_btn_holo_light.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_down_normal_holo_light" />
-
-    <item android:state_pressed="true"
-          android:state_enabled="true"
-          android:drawable="@drawable/numberpicker_down_pressed_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_down_focused_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_down_disabled_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_down_disabled_focused_holo_light" />
-
-</selector>
diff --git a/core/res/res/drawable/numberpicker_up_btn_holo_dark.xml b/core/res/res/drawable/numberpicker_up_btn_holo_dark.xml
deleted file mode 100644
index 7af3ee4..0000000
--- a/core/res/res/drawable/numberpicker_up_btn_holo_dark.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_up_normal_holo_dark" />
-
-    <item android:state_pressed="true"
-          android:state_enabled="true"
-          android:drawable="@drawable/numberpicker_up_pressed_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_up_focused_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_up_disabled_holo_dark" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_up_disabled_focused_holo_dark" />
-
-</selector>
diff --git a/core/res/res/drawable/numberpicker_up_btn_holo_light.xml b/core/res/res/drawable/numberpicker_up_btn_holo_light.xml
deleted file mode 100644
index cbcbb07..0000000
--- a/core/res/res/drawable/numberpicker_up_btn_holo_light.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_up_normal_holo_light" />
-
-    <item android:state_pressed="true"
-          android:state_enabled="true"
-          android:drawable="@drawable/numberpicker_up_pressed_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="true"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_up_focused_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="false"
-          android:drawable="@drawable/numberpicker_up_focused_holo_light" />
-
-    <item android:state_pressed="false"
-          android:state_enabled="false"
-          android:state_focused="true"
-          android:drawable="@drawable/numberpicker_up_disabled_focused_holo_light" />
-
-</selector>
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 2967696..b7e7ae1 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -22,19 +22,26 @@
     <ImageButton android:id="@+id/increment"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        style="?android:attr/numberPickerUpButtonStyle"
+        android:background="@android:drawable/numberpicker_up_btn"
+        android:paddingTop="22dip"
+        android:paddingBottom="22dip"
         android:contentDescription="@string/number_picker_increment_button" />
 
-    <view class="android.widget.NumberPicker$CustomEditText"
+    <EditText
         android:id="@+id/numberpicker_input"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        style="?android:attr/numberPickerInputTextStyle" />
+        android:textAppearance="@style/TextAppearance.Large.Inverse.NumberPickerInputText"
+        android:gravity="center"
+        android:singleLine="true"
+        android:background="@drawable/numberpicker_input" />
 
     <ImageButton android:id="@+id/decrement"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        style="?android:attr/numberPickerDownButtonStyle"
+        android:background="@android:drawable/numberpicker_down_btn"
+        android:paddingTop="22dip"
+        android:paddingBottom="22dip"
         android:contentDescription="@string/number_picker_decrement_button" />
 
 </merge>
diff --git a/core/res/res/layout/number_picker_with_selector_wheel.xml b/core/res/res/layout/number_picker_with_selector_wheel.xml
new file mode 100644
index 0000000..c8fa0f7
--- /dev/null
+++ b/core/res/res/layout/number_picker_with_selector_wheel.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, 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">
+
+    <view class="android.widget.NumberPicker$CustomEditText"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:id="@+id/numberpicker_input"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:singleLine="true"
+        android:background="@null" />
+
+</merge>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index fd9eff3..f020f5d 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -335,7 +335,7 @@
     <string name="permlab_writeContacts" msgid="644616215860933284">"skryf kontakdata"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Laat die program toe om die kontakdata (adresse) wat op jou tablet gestoor is, te verander. Kwaadwillige programme kan dit dalk gebruik om jou kontakdata uit te vee of te verander."</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Laat die program toe om die kontakdata (adresse) wat op jou foon gestoor is, te verander. Kwaadwillige programme kan dit dalk gebruik om jou kontakdata uit te vee of te verander."</string>
-    <string name="permlab_readCallLog" msgid="3478133184624102739">"Lees oproeprekord"</string>
+    <string name="permlab_readCallLog" msgid="3478133184624102739">"lees oproeprekord"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Laat die program toe om jou tablet se oproeprekord, insluitende data oor inkomende en uitgaande oproepe, te lees. Kwaadwillige programme kan dit gebruik om jou data na ander mense te stuur."</string>
     <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Laat die program toe om jou foon se oproeprekord, insluitende data oor inkomende en uitgaande oproepe, te lees. Kwaadwillige programme kan dit gebruik om jou data na ander mense te stuur."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"skryf oproeprekord"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0b14edb..b139e5e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -507,8 +507,8 @@
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Tillader, at appen kan skrive nye ord i brugerordbogen."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="4086221374639183281">"læse USB-lagerets indhold"</string>
     <string name="permlab_sdcardRead" product="default" msgid="8537875151845139539">"læse indholdet af SD-kortet"</string>
-    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Tillader, at app\'en læser indhold på USB-lager."</string>
-    <string name="permdesc_sdcardRead" product="default" msgid="7947792373570683542">"Tillader, at app\'en læser indholdet af SD-kortet."</string>
+    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Tillader, at appen læser indhold på USB-lageret."</string>
+    <string name="permdesc_sdcardRead" product="default" msgid="7947792373570683542">"Tillader, at appen læser indholdet af SD-kortet."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"rette/slette i USB-lager"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"ret/slet indholdet på SD-kortet"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Lader appen skrive til USB."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5ef9483a..8761ca9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -336,11 +336,11 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu tableta. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"leer el registro de llamadas"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Permite que la aplicación lea el registro de llamadas del tablet, incluidos datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para enviar tus datos a otros usuarios."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Permite que la aplicación lea el registro de llamadas del teléfono, incluidos datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para enviar tus datos a otros usuarios."</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Permite que la aplicación lea el registro de llamadas de la tableta, incluidos los datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para enviar tus datos a otros usuarios."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Permite que la aplicación lea el registro de llamadas del dispositivo, incluidos los datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para enviar tus datos a otros usuarios."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"escribir en el registro de llamadas"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite que la aplicación modifique el registro de llamadas del tablet, incluidos datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para borrar o modificar el registro de llamadas."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite que la aplicación modifique el registro de llamadas del teléfono, incluidos datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para borrar o modificar el registro de llamadas."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite que la aplicación modifique el registro de llamadas de la tableta, incluidos los datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para borrar o modificar el registro de llamadas."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite que la aplicación modifique el registro de llamadas del dispositivo, incluidos los datos sobre llamadas entrantes y salientes. Las aplicaciones malintencionadas pueden usar este permiso para borrar o modificar el registro de llamadas."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"Leer tus datos de perfil"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Permite que la aplicación lea la información de perfil almacenada en tu dispositivo, como tu nombre e información de contacto. Esto significa que la aplicación puede identificarte y enviar tu información de perfil a otros."</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"Escrib. en datos de tu perfil"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 88fe721..d044a70 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -507,7 +507,7 @@
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Permet à l\'application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="4086221374639183281">"lire contenu de la mémoire USB"</string>
     <string name="permlab_sdcardRead" product="default" msgid="8537875151845139539">"lire le contenu de la carte SD"</string>
-    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Permet à l\'appli de lire contenu mémoire USB."</string>
+    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Permet à l\'appli de lire contenu de mémoire USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="7947792373570683542">"Permet à l\'application de lire le contenu de la carte SD."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"Modifier/Supprimer contenu mémoire USB"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modifier/supprimer le contenu de la carte SD"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 40a4d01..f51f232 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -130,7 +130,7 @@
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטבלט מלא. מחק קבצים כדי לפנות מקום."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"שטח האחסון של הטלפון מלא. מחק חלק מהקבצים כדי לפנות שטח."</string>
     <string name="me" msgid="6545696007631404292">"אני"</string>
-    <string name="power_dialog" product="tablet" msgid="8545351420865202853">"אפשרויות טבלט"</string>
+    <string name="power_dialog" product="tablet" msgid="8545351420865202853">"אפשרויות טאבלט"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"אפשרויות טלפון"</string>
     <string name="silent_mode" msgid="7167703389802618663">"מצב שקט"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"הפעל חיבור אלחוטי"</string>
@@ -146,7 +146,7 @@
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"האם ברצונך לבצע כיבוי?"</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"נוצרו לאחרונה"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"אין יישומים אחרונים"</string>
-    <string name="global_actions" product="tablet" msgid="408477140088053665">"אפשרויות טבלט"</string>
+    <string name="global_actions" product="tablet" msgid="408477140088053665">"אפשרויות טאבלט"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"אפשרויות טלפון"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
@@ -376,7 +376,7 @@
     <string name="permdesc_recordAudio" msgid="2387462233976248635">"מאפשר ליישום לגשת לנתיב להקלטת אודיו."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"צלם תמונות וסרטונים"</string>
     <string name="permdesc_camera" msgid="1507407407002492176">"מאפשר ליישום לצלם תמונות וסרטוני וידאו עם המצלמה. הגדרה זו מאפשרת ליישום לאסוף תמונות שהמצלמה קולטת בכל עת."</string>
-    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"השבת טבלט לצמיתות"</string>
+    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"השבת טאבלט לצמיתות"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"השבת טלפון לצמיתות"</string>
     <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"מאפשר ליישום להשבית את הטבלט כולו לצמיתות. זו הרשאה מסוכנת מאוד."</string>
     <string name="permdesc_brick" product="default" msgid="5788903297627283099">"מאפשר ליישום להשבית את הטלפון כולו לצמיתות. זו הרשאה מסוכנת מאוד."</string>
@@ -412,7 +412,7 @@
     <string name="permdesc_callPhone" msgid="6396463004110544744">"מאפשר ליישום להתקשר למספרי טלפון ללא התערבותך. יישומים זדוניים עלולים לגרום לחיובי שיחות בלתי צפויים בחשבון הטלפון שלך. לתשומת לבך, הרשאה זו לא מאפשרת ליישום להתקשר למספרי חירום."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"התקשר ישירות לכל מספר טלפון"</string>
     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"מאפשר ליישום להתקשר לכל מספר טלפון שהוא, כולל מספרי חירום, ללא התערבותך. יישומים זדוניים עלולים לבצע שיחות מיותרות ולא חוקיות לשירותי חירום."</string>
-    <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"הפעל ישירות התקנת טבלט מסוג CDMA"</string>
+    <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"הפעל ישירות התקנת טאבלט מסוג CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"הפעל ישירות הגדרה של טלפון CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"מאפשר ליישום להפעיל הקצאת CDMA. יישומים זדוניים עלולים להפעיל הקצאת CDMA ללא צורך."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"שלוט בהתראות על עדכון מיקום"</string>
@@ -429,7 +429,7 @@
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר ליישום למנוע מהטבלט לעבור למצב שינה."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"מאפשר ליישום למנוע מהטלפון לעבור למצב שינה."</string>
-    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"הפעלה או כיבוי של טבלט"</string>
+    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"הפעלה או כיבוי של טאבלט"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"הפעל או כבה את הטלפון"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"מאפשר ליישום להפעיל או לכבות את הטבלט."</string>
     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"מאפשר ליישום להפעיל או לכבות את הטלפון."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 87f8f8d..363832d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -336,11 +336,11 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Membenarkan apl untuk mengubah suai data kenalan (alamat) yang disimpan pada tablet anda. Apl hasad boleh menggunakannya untuk memadam atau mengubah suai data kenalan anda."</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Membenarkan apl untuk mengubah suai data kenalan (alamat) yang disimpan pada telefon anda. Apl hasad boleh menggunakannya untuk memadam atau mengubah suai data kenalan anda."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"baca log panggilan"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Membenarkan apl membaca log panggilan tablet anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakan ini untuk menghantar data anda kepada orang lain."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Membenarkan apl membaca log panggilan telefon anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakan ini untuk menghantar data anda kepada orang lain."</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Membenarkan apl membaca log panggilan tablet anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakannya untuk menghantar data anda kepada orang lain."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Membenarkan apl membaca log panggilan telefon anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakannya untuk menghantar data anda kepada orang lain."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"tulis log panggilan"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Membenarkan apl untuk mengubah suai panggilan tablet anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakan ini untuk memadam atau mengubah suai log panggilan anda."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Membenarkan apl untuk mengubah suai panggilan telefon anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakan ini untuk memadam atau mengubah suai log panggilan anda."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Membenarkan apl untuk mengubah suai panggilan tablet anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakannya untuk memadam atau mengubah suai log panggilan anda."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Membenarkan apl untuk mengubah suai panggilan telefon anda, termasuk data tentang panggilan masuk dan keluar. Apl hasad boleh menggunakannya untuk memadam atau mengubah suai log panggilan anda."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"baca data profil anda"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Membenarkan apl untuk membaca maklumat profil peribadi yang disimpan dalam peranti anda, seperti nama dan maklumat kenalan anda. Ini bermakna apl lain boleh mengenal pasti anda dan menghantar maklumat profil anda kepada orang lain."</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"tulis ke data profil anda"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index fec439d..384fdac 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -507,7 +507,7 @@
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Lar appen skrive nye ord i brukerordlisten."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="4086221374639183281">"lese innhold på USB-lagr."</string>
     <string name="permlab_sdcardRead" product="default" msgid="8537875151845139539">"lese innhold på SD-kortet"</string>
-    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Lar appen lese innhold på USB-lagringsenheten."</string>
+    <string name="permdesc_sdcardRead" product="nosdcard" msgid="1055302898999352339">"Lar appen lese innhold på USB-lager."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="7947792373570683542">"Lar appen lese innhold på SD-kortet."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"endre/slette innh. i USB-lagr."</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"redigere/slette innhold på minnekort"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0542f8e..4b59923 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -336,11 +336,11 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"อนุญาตให้แอปพลิเคชันแก้ไขข้อมูลการติดต่อ (ที่อยู่) ที่เก็บไว้ในแท็บเล็ตของคุณ แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบหรือแก้ไขข้อมูลการติดต่อของคุณ"</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"อนุญาตให้แอปพลิเคชันแก้ไขข้อมูลการติดต่อ (ที่อยู่) ที่เก็บไว้ในโทรศัพท์ของคุณ แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบหรือแก้ไขข้อมูลการติดต่อของคุณ"</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"อ่านประวัติการโทร"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"อนุญาตให้แอปพลิเคชันอ่านประวัติการโทรของแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปพลิเคชันที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อส่งข้อมูลของคุณให้กับบุคคลอื่น"</string>
-    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"อนุญาตให้แอปพลิเคชันอ่านประวัติการโทรของโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปพลิเคชันที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อส่งข้อมูลของคุณให้กับบุคคลอื่น"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"อนุญาตให้แอปอ่านประวัติการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อส่งข้อมูลของคุณให้กับบุคคลอื่น"</string>
+    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"อนุญาตให้แอปอ่านประวัติการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อส่งข้อมูลของคุณให้กับบุคคลอื่น"</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"เขียนประวัติการโทร"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"อนุญาตให้แอปพลิเคชันแก้ไขประวัติการโทรของแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปพลิเคชันที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"อนุญาตให้แอปพลิเคชันแก้ไขประวัติการโทรของโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปพลิเคชันที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"อนุญาตให้แอปแก้ไขประวัติการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"อนุญาตให้แอปแก้ไขประวัติการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"อ่านข้อมูลโปรไฟล์ของคุณ"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลโปรไฟล์ส่วนบุคคลที่เก็บไว้บนอุปกรณ์ของคุณ เช่น ชื่อและข้อมูลติดต่อ ซึ่งหมายความว่าแอปพลิเคชันจะสามารถระบุตัวตนของคุณและส่งข้อมูลโปรไฟล์ของคุณแก่ผู้อื่นได้"</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"เขียนลงในข้อมูลโปรไฟล์ของคุณ"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db908ca..428790f 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -589,12 +589,6 @@
 
         <!-- NumberPicker style. -->
         <attr name="numberPickerStyle" format="reference" />
-        <!-- NumberPicker up button style. -->
-        <attr name="numberPickerUpButtonStyle" format="reference" />
-        <!-- NumberPicker down button style. -->
-        <attr name="numberPickerDownButtonStyle" format="reference" />
-        <!-- NumberPicker input text style. -->
-        <attr name="numberPickerInputTextStyle" format="reference" />
 
         <!-- The CalendarView style. -->
         <attr name="calendarViewStyle" format="reference" />
@@ -3617,12 +3611,12 @@
     <declare-styleable name="NumberPicker">
         <!-- @hide Color for the solid color background if such for optimized rendering. -->
         <attr name="solidColor" format="color|reference" />
-        <!-- @hide Whether the number picker supports fligning. -->
-        <attr name="flingable" format="boolean" />
         <!-- @hide The divider for making the selection area. -->
         <attr name="selectionDivider" format="reference" />
         <!-- @hide The height of the selection divider. -->
         <attr name="selectionDividerHeight" format="dimension" />
+        <!-- @hide The distance between the two selection dividers. -->
+        <attr name="selectionDividersDistance" format="dimension" />
         <!-- @hide The min height of the NumberPicker. -->
         <attr name="internalMinHeight" format="dimension" />
         <!-- @hide The max height of the NumberPicker. -->
@@ -3631,6 +3625,10 @@
         <attr name="internalMinWidth" format="dimension" />
         <!-- @hide The max width of the NumberPicker. -->
         <attr name="internalMaxWidth" format="dimension" />
+        <!-- @hide The layout of the number picker. -->
+        <attr name="internalLayout" />
+        <!-- @hide The minimal move distance of a swipe to be considered a fling. -->
+       <attr name="minFlingDistance" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="TimePicker">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a089021..ea1a70a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -974,6 +974,9 @@
   <java-symbol type="drawable" name="unlock_halo" />
   <java-symbol type="drawable" name="unlock_ring" />
   <java-symbol type="drawable" name="unlock_wave" />
+  <java-symbol type="drawable" name="ic_lockscreen_camera" />
+  <java-symbol type="drawable" name="ic_lockscreen_silent" />
+  <java-symbol type="drawable" name="ic_lockscreen_unlock" />
 
   <java-symbol type="layout" name="action_bar_home" />
   <java-symbol type="layout" name="action_bar_title_item" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7799f74..f6125f00 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3190,8 +3190,6 @@
     <string name="number_picker_increment_button">Increment</string>
     <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_decrement_button">Decrement</string>
-    <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] -->
-    <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch and hold.</string>
     <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] -->
     <string name="number_picker_increment_scroll_action">Slide up to increment and down to decrement.</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a51f3f9..288b8b2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -521,10 +521,10 @@
     </style>
 
     <style name="Widget.NumberPicker">
+        <item name="android:internalLayout">@android:layout/number_picker</item>
         <item name="android:orientation">vertical</item>
         <item name="android:fadingEdge">vertical</item>
         <item name="android:fadingEdgeLength">50dip</item>
-        <item name="android:flingable">false</item>
     </style>
 
     <style name="Widget.TimePicker">
@@ -536,25 +536,6 @@
         <item name="android:calendarViewShown">false</item>
     </style>
 
-    <style name="Widget.ImageButton.NumberPickerUpButton">
-        <item name="android:background">@android:drawable/numberpicker_up_btn</item>
-        <item name="android:paddingTop">22dip</item>
-        <item name="android:paddingBottom">22dip</item>
-    </style>
-
-    <style name="Widget.ImageButton.NumberPickerDownButton">
-        <item name="android:background">@android:drawable/numberpicker_down_btn</item>
-        <item name="android:paddingTop">22dip</item>
-        <item name="android:paddingBottom">22dip</item>
-    </style>
-
-    <style name="Widget.EditText.NumberPickerInputText">
-        <item name="android:textAppearance">@style/TextAppearance.Large.Inverse.NumberPickerInputText</item>
-        <item name="android:gravity">center</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:background">@drawable/numberpicker_input</item>
-    </style>
-
     <style name="Widget.AutoCompleteTextView" parent="Widget.EditText">
         <item name="android:completionHintView">@android:layout/simple_dropdown_hint</item>
         <item name="android:completionThreshold">2</item>
@@ -1656,12 +1637,14 @@
     </style>
 
     <style name="Widget.Holo.NumberPicker" parent="Widget.NumberPicker">
+        <item name="android:internalLayout">@android:layout/number_picker_with_selector_wheel</item>
         <item name="android:solidColor">@android:color/transparent</item>
-        <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:selectionDividersDistance">48dip</item>
         <item name="android:internalMinWidth">48dip</item>
         <item name="android:internalMaxHeight">200dip</item>
+        <item name="android:minFlingDistance">150dip</item>
     </style>
 
     <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
@@ -1673,31 +1656,6 @@
         <item name="android:calendarViewShown">true</item>
     </style>
 
-    <style name="Widget.Holo.ImageButton.NumberPickerUpButton">
-        <item name="android:background">@null</item>
-        <item name="android:src">@android:drawable/numberpicker_up_btn_holo_dark</item>
-        <item name="android:paddingTop">16dip</item>
-        <item name="android:paddingBottom">22dip</item>
-    </style>
-
-    <style name="Widget.Holo.ImageButton.NumberPickerDownButton">
-        <item name="android:background">@null</item>
-        <item name="android:src">@android:drawable/numberpicker_down_btn_holo_dark</item>
-        <item name="android:paddingTop">22dip</item>
-        <item name="android:paddingBottom">16dip</item>
-    </style>
-
-    <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>
-        <item name="android:background">@null</item>
-    </style>
-
     <style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView">
     </style>
 
@@ -2109,17 +2067,6 @@
     <style name="Widget.Holo.Light.DatePicker" parent="Widget.Holo.DatePicker">
     </style>
 
-    <style name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
-        <item name="android:src">@android:drawable/numberpicker_up_btn_holo_light</item>
-    </style>
-
-    <style name="Widget.Holo.Light.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
-        <item name="android:src">@android:drawable/numberpicker_down_btn_holo_light</item>
-    </style>
-
-    <style name="Widget.Holo.Light.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
-    </style>
-
     <style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
         <item name="android:background">@android:drawable/ab_share_pack_holo_light</item>
     </style>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 6419872..330e68c 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -200,9 +200,6 @@
     <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Holo.CompoundButton.Switch">
 
     </style>
-    <style name="Widget.DeviceDefault.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
-
-    </style>
     <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Holo.ExpandableListView.White">
 
     </style>
@@ -212,12 +209,6 @@
     <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Holo.GestureOverlayView">
 
     </style>
-    <style name="Widget.DeviceDefault.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
-
-    </style>
-    <style name="Widget.DeviceDefault.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
-
-    </style>
     <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Holo.ImageWell">
 
     </style>
@@ -465,9 +456,6 @@
     <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Holo.Light.DatePicker">
 
     </style>
-    <style name="Widget.DeviceDefault.Light.EditText.NumberPickerInputText" parent="Widget.Holo.Light.EditText.NumberPickerInputText">
-
-    </style>
     <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Holo.Light.ExpandableListView.White">
 
     </style>
@@ -477,12 +465,6 @@
     <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Holo.Light.GestureOverlayView">
 
     </style>
-    <style name="Widget.DeviceDefault.Light.ImageButton.NumberPickerDownButton" parent="Widget.Holo.Light.ImageButton.NumberPickerDownButton">
-
-    </style>
-    <style name="Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.Light.ImageButton.NumberPickerUpButton">
-
-    </style>
     <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Holo.Light.ImageWell">
 
     </style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 55438b2..7e06e24 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -345,10 +345,7 @@
         <!-- PreferenceFrameLayout attributes -->
         <item name="preferenceFrameLayoutStyle">@android:style/Widget.PreferenceFrameLayout</item>
 
-        <!-- NumberPicker styles-->
-        <item name="numberPickerUpButtonStyle">@style/Widget.ImageButton.NumberPickerUpButton</item>
-        <item name="numberPickerDownButtonStyle">@style/Widget.ImageButton.NumberPickerDownButton</item>
-        <item name="numberPickerInputTextStyle">@style/Widget.EditText.NumberPickerInputText</item>
+        <!-- NumberPicker style-->
         <item name="numberPickerStyle">@style/Widget.NumberPicker</item>
 
         <!-- CalendarView style-->
@@ -1141,10 +1138,7 @@
         <!-- PreferenceFrameLayout attributes -->
         <item name="preferenceFrameLayoutStyle">@android:style/Widget.Holo.PreferenceFrameLayout</item>
 
-        <!-- NumberPicker styles-->
-        <item name="numberPickerUpButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerUpButton</item>
-        <item name="numberPickerDownButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerDownButton</item>
-        <item name="numberPickerInputTextStyle">@style/Widget.Holo.EditText.NumberPickerInputText</item>
+        <!-- NumberPicker style-->
         <item name="numberPickerStyle">@style/Widget.Holo.NumberPicker</item>
 
         <!-- CalendarView style-->
@@ -1443,10 +1437,7 @@
 
         <item name="searchDialogTheme">@style/Theme.Holo.Light.SearchBar</item>
 
-        <!-- NumberPicker attributes and styles-->
-        <item name="numberPickerUpButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerUpButton</item>
-        <item name="numberPickerDownButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerDownButton</item>
-        <item name="numberPickerInputTextStyle">@style/Widget.Holo.Light.EditText.NumberPickerInputText</item>
+        <!-- NumberPicker style-->
         <item name="numberPickerStyle">@style/Widget.Holo.Light.NumberPicker</item>
 
         <!-- CalendarView style-->
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 7fd981c..ae9255a 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -179,10 +179,7 @@
         <!-- PreferenceFrameLayout attributes -->
         <item name="preferenceFrameLayoutStyle">@android:style/Widget.DeviceDefault.PreferenceFrameLayout</item>
 
-        <!-- NumberPicker styles-->
-        <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerUpButton</item>
-        <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerDownButton</item>
-        <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.EditText.NumberPickerInputText</item>
+        <!-- NumberPicker style-->
         <item name="numberPickerStyle">@style/Widget.DeviceDefault.NumberPicker</item>
 
         <!-- CalendarView style-->
@@ -329,10 +326,7 @@
 
         <item name="searchDialogTheme">@style/Theme.DeviceDefault.Light.SearchBar</item>
 
-        <!-- NumberPicker attributes and styles-->
-        <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton</item>
-        <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerDownButton</item>
-        <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.Light.EditText.NumberPickerInputText</item>
+        <!-- NumberPicker style -->
         <item name="numberPickerStyle">@style/Widget.DeviceDefault.Light.NumberPicker</item>
 
         <!-- CalendarView style-->
diff --git a/test-runner/src/android/test/BandwidthTest.java b/core/tests/utillib/src/android/test/BandwidthTest.java
similarity index 91%
rename from test-runner/src/android/test/BandwidthTest.java
rename to core/tests/utillib/src/android/test/BandwidthTest.java
index e02ae00..6cff0ff 100644
--- a/test-runner/src/android/test/BandwidthTest.java
+++ b/core/tests/utillib/src/android/test/BandwidthTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -24,8 +24,6 @@
  * annotation is present, the test method is profiled for bandwidth metrics and the results
  * written through instrumentation output. It can also be used on the class itself,
  * which is equivalent to tagging all test methods with this annotation.
- *
- * {@hide} Pending approval for public API.
  */
 @Retention(RetentionPolicy.RUNTIME)
 public @interface BandwidthTest {
diff --git a/core/tests/utillib/src/android/test/BandwidthTestCase.java b/core/tests/utillib/src/android/test/BandwidthTestCase.java
new file mode 100644
index 0000000..4f95f77
--- /dev/null
+++ b/core/tests/utillib/src/android/test/BandwidthTestCase.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.test;
+
+import android.net.NetworkStats;
+import android.net.TrafficStats;
+import android.os.Bundle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * A bandwidth test case that collects bandwidth statistics for tests that are
+ * annotated with {@link BandwidthTest} otherwise the test is executed
+ * as an {@link InstrumentationTestCase}
+ */
+public class BandwidthTestCase extends InstrumentationTestCase {
+    private static final String REPORT_KEY_PACKETS_SENT = "txPackets";
+    private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets";
+    private static final String REPORT_KEY_BYTES_SENT = "txBytes";
+    private static final String REPORT_KEY_BYTES_RECEIVED = "rxBytes";
+    private static final String REPORT_KEY_OPERATIONS = "operations";
+
+    @Override
+    protected void runTest() throws Throwable {
+        //This is a copy of {@link InstrumentationTestCase#runTest} with
+        //added logic to handle bandwidth measurements
+        String fName = getName();
+        assertNotNull(fName);
+        Method method = null;
+        Class testClass = null;
+        try {
+            // use getMethod to get all public inherited
+            // methods. getDeclaredMethods returns all
+            // methods of this class but excludes the
+            // inherited ones.
+            testClass = getClass();
+            method = testClass.getMethod(fName, (Class[]) null);
+        } catch (NoSuchMethodException e) {
+            fail("Method \""+fName+"\" not found");
+        }
+
+        if (!Modifier.isPublic(method.getModifiers())) {
+            fail("Method \""+fName+"\" should be public");
+        }
+
+        int runCount = 1;
+        boolean isRepetitive = false;
+        if (method.isAnnotationPresent(FlakyTest.class)) {
+            runCount = method.getAnnotation(FlakyTest.class).tolerance();
+        } else if (method.isAnnotationPresent(RepetitiveTest.class)) {
+            runCount = method.getAnnotation(RepetitiveTest.class).numIterations();
+            isRepetitive = true;
+        }
+
+        if (method.isAnnotationPresent(UiThreadTest.class)) {
+            final int tolerance = runCount;
+            final boolean repetitive = isRepetitive;
+            final Method testMethod = method;
+            final Throwable[] exceptions = new Throwable[1];
+            getInstrumentation().runOnMainSync(new Runnable() {
+                public void run() {
+                    try {
+                        runMethod(testMethod, tolerance, repetitive);
+                    } catch (Throwable throwable) {
+                        exceptions[0] = throwable;
+                    }
+                }
+            });
+            if (exceptions[0] != null) {
+                throw exceptions[0];
+            }
+        } else if (method.isAnnotationPresent(BandwidthTest.class) ||
+                testClass.isAnnotationPresent(BandwidthTest.class)) {
+            TrafficStats.startDataProfiling(null);
+            runMethod(method, 1, false);
+            NetworkStats stats = TrafficStats.stopDataProfiling(null);
+            NetworkStats.Entry entry = stats.getTotal(null);
+            getInstrumentation().sendStatus(2, getBandwidthStats(entry));
+        } else {
+            runMethod(method, runCount, isRepetitive);
+        }
+    }
+
+    private void runMethod(Method runMethod, int tolerance, boolean isRepetitive) throws Throwable {
+        //This is a copy of {@link InstrumentationTestCase#runMethod}
+        Throwable exception = null;
+
+        int runCount = 0;
+        do {
+            try {
+                runMethod.invoke(this, (Object[]) null);
+                exception = null;
+            } catch (InvocationTargetException e) {
+                e.fillInStackTrace();
+                exception = e.getTargetException();
+            } catch (IllegalAccessException e) {
+                e.fillInStackTrace();
+                exception = e;
+            } finally {
+                runCount++;
+                // Report current iteration number, if test is repetitive
+                if (isRepetitive) {
+                    Bundle iterations = new Bundle();
+                    iterations.putInt("currentiterations", runCount);
+                    getInstrumentation().sendStatus(2, iterations);
+                }
+            }
+        } while ((runCount < tolerance) && (isRepetitive || exception != null));
+
+        if (exception != null) {
+            throw exception;
+        }
+    }
+
+    private Bundle getBandwidthStats(NetworkStats.Entry entry){
+        Bundle bundle = new Bundle();
+        bundle.putLong(REPORT_KEY_BYTES_RECEIVED, entry.rxBytes);
+        bundle.putLong(REPORT_KEY_BYTES_SENT, entry.txBytes);
+        bundle.putLong(REPORT_KEY_PACKETS_RECEIVED, entry.rxPackets);
+        bundle.putLong(REPORT_KEY_PACKETS_SENT, entry.txPackets);
+        bundle.putLong(REPORT_KEY_OPERATIONS, entry.operations);
+        return bundle;
+    }
+}
+
diff --git a/docs/html/guide/developing/debugging/ddms.jd b/docs/html/guide/developing/debugging/ddms.jd
index 4398ec9..80b1e47 100644
--- a/docs/html/guide/developing/debugging/ddms.jd
+++ b/docs/html/guide/developing/debugging/ddms.jd
@@ -11,7 +11,19 @@
       <li><a href="#running">Running DDMS</a></li>
         <li><a href="#how-ddms-works">How DDMS Interacts with a Debugger</a></li>
 
-        <li><a href="#using-ddms">Using DDMS</a></li>
+        <li><a href="#using-ddms">Using DDMS</a>
+        <ol>
+                <li><a href="#heap">Viewing heap usage for a process</a></li>
+                <li><a href="#alloc">Tracking memory allocation of objects</a></li>
+                <li><a href="#emulator">Working with an emulator or device's file system</a></li>
+                <li><a href="#thread">Examining thread information</a></li>
+                <li><a href="#profiling">Starting method profiling</a></li>
+                <li><a href="#network">Using the Network Traffic tool</a></li>
+                <li><a href="#logcat">Using LogCat</a></li>
+                <li><a href="#ops-location">Emulating phone operations and location</a></li>
+            </ol>
+        
+        </li>
       </ol>
     </div>
   </div>
@@ -90,7 +102,7 @@
   <a href="#running">Running DDMS</a>.
   
   
-  <h3>Viewing heap usage for a process</h3>
+  <h3 id="heap">Viewing heap usage for a process</h3>
 
   <p>DDMS allows you to view how much heap memory a process is using. This information is useful in
   tracking heap usage at a certain point of time during the execution of your application.</p>
@@ -110,7 +122,7 @@
     allocated for a particular memory size in bytes.</li>
   </ol>
 
-  <h3>Tracking memory allocation of objects</h3>
+  <h3 id="alloc">Tracking memory allocation of objects</h3>
 
   <p>DDMS provides a feature to track objects that are being allocated to memory and to see which
   classes and threads are allocating the objects. This allows you to track, in real time, where
@@ -140,7 +152,7 @@
     line number of the code that allocated the object.</li>
   </ol>
 
-  <h3>Working with an emulator or device's file system</h3>
+  <h3 id="emulator">Working with an emulator or device's file system</h3>
 
   <p>DDMS provides a File Explorer tab that allows you to view, copy, and delete files on the
   device. This feature is useful in examining files that are created by your application or if you
@@ -160,7 +172,7 @@
   <!-- Need to elaborate more on where things are stored in the file system,
    databases, apks, user info, files that are important to look at -->
 
-  <h3>Examining thread information</h3>
+  <h3 id="thread">Examining thread information</h3>
 
   <p>The Threads tab in DDMS shows you the currently running threads for a selected process.</p>
 
@@ -204,6 +216,67 @@
     Profiling</strong>.</li>
   </ol>
 
+   <h3 id="network">Using the Network Traffic tool</h3>
+   
+   <p>In Android 4.0, the DDMS (Dalvik Debug Monitor Server) includes a Detailed
+Network Usage tab that makes it possible to track when your application is
+making network requests. Using this tool, you can monitor how and when your app
+transfers data and optimize the underlying code appropriately. You can also
+distinguish between different traffic types by applying a “tag” to network
+sockets before use.</p>
+
+<p>These tags are shown in a stack area chart in DDMS, as shown in figure 2:</p>
+
+<img src="{@docRoot}images/developing/ddms-network.png" />
+<p class="img-caption"><strong>Figure 2.</strong> Network Usage tab.</p>
+
+<p>By monitoring the frequency of your data transfers, and the amount of data
+transferred during each connection, you can identify areas of your application
+that can be made more battery-efficient. Generally, you should look for
+short spikes that can be delayed, or that should cause a later transfer to be
+pre-empted. </p>
+
+<p>To better identify the cause of transfer spikes, the
+{@link android.net.TrafficStats} API allows you
+to tag the data transfers occurring within a thread using {@link
+android.net.TrafficStats#setThreadStatsTag setThreadStatsTag()}, followed
+by manually tagging (and untagging) individual sockets using {@link
+android.net.TrafficStats#tagSocket tagSocket()} and {@link
+android.net.TrafficStats#untagSocket untagSocket()}. For example:</p>
+
+<pre>TrafficStats.setThreadStatsTag(0xF00D);
+TrafficStats.tagSocket(outputSocket);
+// Transfer data using socket
+TrafficStats.untagSocket(outputSocket);</pre>
+
+<p>Alternatively, the Apache {@link org.apache.http.client.HttpClient} and 
+{@link java.net.URLConnection} APIs included in the platform
+automatically tag sockets internally based on the active tag (as 
+identified by 
+{@link android.net.TrafficStats#getThreadStatsTag getThreadStatsTag()}).
+These APIs correctly tag/untag sockets when recycled through
+keep-alive pools. In the following example,  
+{@link android.net.TrafficStats#setThreadStatsTag setThreadStatsTag()} 
+sets the active tag to be {@code 0xF00D}. 
+There can only be one active tag per thread. 
+That is the value that will 
+be returned by {@link android.net.TrafficStats#getThreadStatsTag getThreadStatsTag()}
+and thus used by {@link org.apache.http.client.HttpClient}  
+ to tag sockets. The {@code finally} statement 
+invokes 
+{@link android.net.TrafficStats#clearThreadStatsTag clearThreadStatsTag()} 
+to clear the tag.</p>
+
+<pre>TrafficStats.setThreadStatsTag(0xF00D);
+    try {
+        // Make network request using HttpClient.execute()
+    } finally {
+        TrafficStats.clearThreadStatsTag();
+}</pre>
+
+<p>Socket tagging is supported in Android 4.0, but real-time stats will only be
+displayed on devices running Android 4.0.3 or higher.</p>
+   
   <h3 id="logcat">Using LogCat</h3>
 
   <p>LogCat is integrated into DDMS, and outputs the messages that you print out using the {@link android.util.Log}
@@ -230,7 +303,7 @@
   with the log tags or with the process id that generated the log message. The add filter,
   edit filter, and delete filter buttons let you manage your custom filters.</p>
 
-  <h3>Emulating phone operations and location</h3>
+  <h3 id="ops-location">Emulating phone operations and location</h3>
   <p>The Emulator control tab lets you simulate a
   phone's voice and data network status. This is useful when you want to test your application's
   robustness in differing network environments.</p>
diff --git a/docs/html/images/developing/ddms-network.png b/docs/html/images/developing/ddms-network.png
new file mode 100644
index 0000000..5aa1290
--- /dev/null
+++ b/docs/html/images/developing/ddms-network.png
Binary files differ
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index f0d1643..c5705f6 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -32,6 +32,8 @@
  * and byte-arrays.
  */
 public class BitmapFactory {
+    private static final int DECODE_BUFFER_SIZE = 16 * 1024;
+
     public static class Options {
         /**
          * Create a default Options object, which if left unchanged will give
@@ -469,7 +471,7 @@
         // we need mark/reset to work properly
 
         if (!is.markSupported()) {
-            is = new BufferedInputStream(is, 16 * 1024);
+            is = new BufferedInputStream(is, DECODE_BUFFER_SIZE);
         }
 
         // so we can call reset() if a given codec gives up after reading up to
@@ -477,11 +479,30 @@
         // value should be.
         is.mark(1024);
 
-        Bitmap  bm;
+        Bitmap bm;
+        boolean finish = true;
 
         if (is instanceof AssetManager.AssetInputStream) {
-            bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
-                    outPadding, opts);
+            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+
+            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
+                float scale = 1.0f;
+                int targetDensity = 0;
+                if (opts != null) {
+                    final int density = opts.inDensity;
+                    targetDensity = opts.inTargetDensity;
+                    if (density != 0 && targetDensity != 0) {
+                        scale = targetDensity / (float) density;
+                    }
+                }
+
+                bm = nativeDecodeAsset(asset, outPadding, opts, true, scale);
+                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
+
+                finish = false;
+            } else {
+                bm = nativeDecodeAsset(asset, outPadding, opts);
+            }
         } else {
             // pass some temp storage down to the native code. 1024 is made up,
             // but should be large enough to avoid too many small calls back
@@ -490,13 +511,32 @@
             byte [] tempStorage = null;
             if (opts != null) tempStorage = opts.inTempStorage;
             if (tempStorage == null) tempStorage = new byte[16 * 1024];
-            bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+
+            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
+                float scale = 1.0f;
+                int targetDensity = 0;
+                if (opts != null) {
+                    final int density = opts.inDensity;
+                    targetDensity = opts.inTargetDensity;
+                    if (density != 0 && targetDensity != 0) {
+                        scale = targetDensity / (float) density;
+                    }
+                }
+
+                bm = nativeDecodeStream(is, tempStorage, outPadding, opts, true, scale);
+                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
+
+                finish = false;
+            } else {
+                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+            }
         }
+
         if (bm == null && opts != null && opts.inBitmap != null) {
             throw new IllegalArgumentException("Problem decoding into existing bitmap");
         }
 
-        return finishDecode(bm, outPadding, opts);
+        return finish ? finishDecode(bm, outPadding, opts) : bm;
     }
 
     private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
@@ -524,12 +564,13 @@
                 bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
                         (int) (bm.getHeight() * scale + 0.5f), true);
                 if (bm != oldBitmap) oldBitmap.recycle();
+
+                if (isNinePatch) {
+                    np = nativeScaleNinePatch(np, scale, outPadding);
+                    bm.setNinePatchChunk(np);
+                }
             }
 
-            if (isNinePatch) {
-                if (scale != 1.0f) np = nativeScaleNinePatch(np, scale, outPadding);
-                bm.setNinePatchChunk(np);
-            }
             bm.setDensity(targetDensity);
         }
 
@@ -597,9 +638,13 @@
 
     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
             Rect padding, Options opts);
+    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+            Rect padding, Options opts, boolean applyScale, float scale);
     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
             Rect padding, Options opts);
     private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
+    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts,
+            boolean applyScale, float scale);
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
             int length, Options opts);
     private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8b4b8ed..00b8679 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -70,6 +70,8 @@
     kKeyThumbnailTime     = 'thbT',  // int64_t (usecs)
     kKeyTrackID           = 'trID',
     kKeyIsDRM             = 'idrm',  // int32_t (bool)
+    kKeyEncoderDelay      = 'encd',  // int32_t (frames)
+    kKeyEncoderPadding    = 'encp',  // int32_t (frames)
 
     kKeyAlbum             = 'albu',  // cstring
     kKeyArtist            = 'arti',  // cstring
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 2fe45ec..2175131 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -124,9 +124,15 @@
     /**
      * Sets a Surface to show a preview of recorded media (video). Calls this
      * before prepare() to make sure that the desirable preview display is
-     * set.
+     * set. If {@link #setCamera(Camera)} is used and the surface has been
+     * already set to the camera, application do not need to call this. If
+     * this is called with non-null surface, the preview surface of the camera
+     * will be replaced by the new surface. If this method is called with null
+     * surface or not called at all, media recorder will not change the preview
+     * surface of the camera.
      *
      * @param sv the Surface to use for the preview
+     * @see android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)
      */
     public void setPreviewDisplay(Surface sv) {
         mSurface = sv;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 0d67800..fd3f892 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -515,9 +515,13 @@
         return err;
     }
 
-    // This CHECK is good, since we just passed the lock/unlock
-    // check earlier by calling mCamera->setParameters().
-    CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
+    // Set the preview display. Skip this if mSurface is null because
+    // applications may already set a surface to the camera.
+    if (mSurface != NULL) {
+        // This CHECK is good, since we just passed the lock/unlock
+        // check earlier by calling mCamera->setParameters().
+        CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
+    }
 
     // By default, do not store metadata in video buffers
     mIsMetaDataStoredInVideoBuffers = false;
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 69209b5..6abaf23 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -311,10 +311,18 @@
     mMeta->setInt32(kKeyBitRate, bitrate * 1000);
     mMeta->setInt32(kKeyChannelCount, num_channels);
 
-    mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
+    sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
 
-    if (mSeeker == NULL) {
+    if (seeker == NULL) {
         mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
+    } else {
+        mSeeker = seeker;
+        int encd = seeker->getEncoderDelay();
+        int encp = seeker->getEncoderPadding();
+        if (encd != 0 || encp != 0) {
+            mMeta->setInt32(kKeyEncoderDelay, encd);
+            mMeta->setInt32(kKeyEncoderPadding, encp);
+        }
     }
 
     if (mSeeker != NULL) {
@@ -340,6 +348,37 @@
     }
 
     mInitCheck = OK;
+
+    // get iTunes-style gapless info if present
+    ID3 id3(mDataSource);
+    if (id3.isValid()) {
+        ID3::Iterator *com = new ID3::Iterator(id3, "COM");
+        if (com->done()) {
+            delete com;
+            com = new ID3::Iterator(id3, "COMM");
+        }
+        while(!com->done()) {
+            String8 commentdesc;
+            String8 commentvalue;
+            com->getString(&commentdesc, &commentvalue);
+            const char * desc = commentdesc.string();
+            const char * value = commentvalue.string();
+
+            // first 3 characters are the language, which we don't care about
+            if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
+
+                int32_t delay, padding;
+                if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
+                    mMeta->setInt32(kKeyEncoderDelay, delay);
+                    mMeta->setInt32(kKeyEncoderPadding, padding);
+                }
+                break;
+            }
+            com->next();
+        }
+        delete com;
+        com = NULL;
+    }
 }
 
 size_t MP3Extractor::countTracks() {
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 8c99c76..9c91134 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "XINGSEEKER"
+#include <utils/Log.h>
+
 #include "include/XINGSeeker.h"
 #include "include/avc_utils.h"
 
@@ -24,7 +27,9 @@
 
 XINGSeeker::XINGSeeker()
     : mDurationUs(-1),
-      mSizeBytes(0) {
+      mSizeBytes(0),
+      mEncoderDelay(0),
+      mEncoderPadding(0) {
 }
 
 bool XINGSeeker::getDuration(int64_t *durationUs) {
@@ -76,8 +81,6 @@
 
     seeker->mFirstFramePos = first_frame_pos;
 
-    ALOGI("xingseeker first frame pos: %lld", first_frame_pos);
-
     seeker->mSizeBytes = 0;
     seeker->mTOCValid = false;
     seeker->mDurationUs = 0;
@@ -111,6 +114,8 @@
         else offset += 9;
     }
 
+    int xingbase = offset;
+
     if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
         return NULL;
     }
@@ -161,10 +166,31 @@
         // do something with the quality indicator
         offset += 4;
     }
+
+    if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags
+        return false;
+    }
+
+    ALOGV("nogap preceding: %s, nogap continued in next: %s",
+              (buffer[0] & 0x80) ? "true" : "false",
+              (buffer[0] & 0x40) ? "true" : "false");
 #endif
 
+    if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) {
+        seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4);
+        seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2];
+    }
+
     return seeker;
 }
 
+int32_t XINGSeeker::getEncoderDelay() {
+    return mEncoderDelay;
+}
+
+int32_t XINGSeeker::getEncoderPadding() {
+    return mEncoderPadding;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 2e92926..ca14054 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -463,40 +463,65 @@
     tmp = NULL;
 }
 
-void ID3::Iterator::getString(String8 *id) const {
+// the 2nd argument is used to get the data following the \0 in a comment field
+void ID3::Iterator::getString(String8 *id, String8 *comment) const {
+    getstring(id, false);
+    if (comment != NULL) {
+        getstring(comment, true);
+    }
+}
+
+// comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
+// followed by more data. The data following the \0 can be retrieved by setting
+// "otherdata" to true.
+void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
     id->setTo("");
 
-    if (mFrameData == NULL) {
+    const uint8_t *frameData = mFrameData;
+    if (frameData == NULL) {
         return;
     }
 
+    uint8_t encoding = *frameData;
+
     if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
         if (mOffset == 126 || mOffset == 127) {
             // Special treatment for the track number and genre.
             char tmp[16];
-            sprintf(tmp, "%d", (int)*mFrameData);
+            sprintf(tmp, "%d", (int)*frameData);
 
             id->setTo(tmp);
             return;
         }
 
-        convertISO8859ToString8(mFrameData, mFrameSize, id);
+        convertISO8859ToString8(frameData, mFrameSize, id);
         return;
     }
 
     size_t n = mFrameSize - getHeaderLength() - 1;
+    if (otherdata) {
+        // skip past the encoding, language, and the 0 separator
+        frameData += 4;
+        int32_t i = n - 4;
+        while(--i >= 0 && *++frameData != 0) ;
+        int skipped = (frameData - mFrameData);
+        if (skipped >= n) {
+            return;
+        }
+        n -= skipped;
+    }
 
-    if (*mFrameData == 0x00) {
+    if (encoding == 0x00) {
         // ISO 8859-1
-        convertISO8859ToString8(mFrameData + 1, n, id);
-    } else if (*mFrameData == 0x03) {
+        convertISO8859ToString8(frameData + 1, n, id);
+    } else if (encoding == 0x03) {
         // UTF-8
-        id->setTo((const char *)(mFrameData + 1), n);
-    } else if (*mFrameData == 0x02) {
+        id->setTo((const char *)(frameData + 1), n);
+    } else if (encoding == 0x02) {
         // UTF-16 BE, no byte order mark.
         // API wants number of characters, not number of bytes...
         int len = n / 2;
-        const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+        const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
 #if BYTE_ORDER == LITTLE_ENDIAN
         framedatacopy = new char16_t[len];
@@ -513,7 +538,7 @@
         // UCS-2
         // API wants number of characters, not number of bytes...
         int len = n / 2;
-        const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+        const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
         if (*framedata == 0xfffe) {
             // endianness marker doesn't match host endianness, convert
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 98c82a4..8714008 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -50,7 +50,7 @@
 
         bool done() const;
         void getID(String8 *id) const;
-        void getString(String8 *s) const;
+        void getString(String8 *s, String8 *ss = NULL) const;
         const uint8_t *getData(size_t *length) const;
         void next();
 
@@ -65,6 +65,7 @@
         void findFrame();
 
         size_t getHeaderLength() const;
+        void getstring(String8 *s, bool secondhalf) const;
 
         Iterator(const Iterator &);
         Iterator &operator=(const Iterator &);
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/libstagefright/include/XINGSeeker.h
index 8510979..c408576 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/libstagefright/include/XINGSeeker.h
@@ -31,10 +31,15 @@
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
 
+    virtual int32_t getEncoderDelay();
+    virtual int32_t getEncoderPadding();
+
 private:
     int64_t mFirstFramePos;
     int64_t mDurationUs;
     int32_t mSizeBytes;
+    int32_t mEncoderDelay;
+    int32_t mEncoderPadding;
 
     // TOC entries in XING header. Skip the first one since it's always 0.
     unsigned char mTOC[99];
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index bb80098..8fbab74 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -144,11 +144,11 @@
                 />
         </LinearLayout>
 
-        <View android:id="@+id/deadzone"
+        <com.android.systemui.statusbar.policy.DeadZone
+            android:id="@+id/deadzone"
             android:layout_height="@dimen/navigation_bar_deadzone_size"
             android:layout_width="match_parent"
             android:layout_gravity="top"
-            android:clickable="true"
             />
     </FrameLayout>
 
@@ -272,11 +272,11 @@
                 />
         </LinearLayout>
 
-        <View android:id="@+id/deadzone"
+        <com.android.systemui.statusbar.policy.DeadZone
+            android:id="@+id/deadzone"
             android:layout_width="@dimen/navigation_bar_deadzone_size"
             android:layout_height="match_parent"
             android:layout_gravity="left"
-            android:clickable="true"
             />
     </FrameLayout>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
new file mode 100644
index 0000000..19fbe96
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public class DeadZone extends View {
+    public DeadZone(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DeadZone(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs);
+    }
+
+    // I made you a touch event
+    @Override
+    public boolean onTouchEvent (MotionEvent event) {
+        return true; // but I eated it
+    }
+}
+
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 9f3de69..25af2e6 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -22,6 +22,7 @@
 import com.android.internal.widget.DigitalClock;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.TransportControlView;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
 import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
 
 import java.util.ArrayList;
@@ -625,9 +626,9 @@
         }
     }
 
-    private KeyguardUpdateMonitor.InfoCallback mInfoCallback
-            = new KeyguardUpdateMonitor.InfoCallback() {
+    private InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
 
+        @Override
         public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
                 int batteryLevel) {
             mShowingBatteryInfo = showBatteryInfo;
@@ -637,33 +638,24 @@
             update(BATTERY_INFO, getAltTextMessage(tmpIcon));
         }
 
+        @Override
         public void onTimeChanged() {
             refreshDate();
         }
 
+        @Override
         public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
             mPlmn = plmn;
             mSpn = spn;
             updateCarrierStateWithSimStatus(mSimState);
         }
 
-        public void onRingerModeChanged(int state) {
-
-        }
-
+        @Override
         public void onPhoneStateChanged(int phoneState) {
             mPhoneState = phoneState;
             updateEmergencyCallButtonState(phoneState);
         }
 
-        /** {@inheritDoc} */
-        public void onClockVisibilityChanged() {
-            // ignored
-        }
-
-        public void onDeviceProvisioned() {
-            // 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 91ab053..804cd9e 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy.impl;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -103,6 +104,7 @@
     private static final int MSG_PHONE_STATE_CHANGED = 306;
     private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
     private static final int MSG_DEVICE_PROVISIONED = 308;
+    protected static final int MSG_DPM_STATE_CHANGED = 309;
 
     /**
      * When we receive a
@@ -204,6 +206,9 @@
                     case MSG_DEVICE_PROVISIONED:
                         handleDeviceProvisioned();
                         break;
+                    case MSG_DPM_STATE_CHANGED:
+                        handleDevicePolicyManagerStateChanged();
+                        break;
                 }
             }
         };
@@ -262,6 +267,7 @@
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(SPN_STRINGS_UPDATED_ACTION);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         context.registerReceiver(new BroadcastReceiver() {
 
             public void onReceive(Context context, Intent intent) {
@@ -293,11 +299,20 @@
                 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
                     String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
+                } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+                        .equals(action)) {
+                    mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
                 }
             }
         }, filter);
     }
 
+    protected void handleDevicePolicyManagerStateChanged() {
+        for (int i = 0; i < mInfoCallbacks.size(); i++) {
+            mInfoCallbacks.get(i).onDevicePolicyManagerStateChanged();
+        }
+    }
+
     protected void handleDeviceProvisioned() {
         for (int i = 0; i < mInfoCallbacks.size(); i++) {
             mInfoCallbacks.get(i).onDeviceProvisioned();
@@ -521,6 +536,40 @@
          * Called when the device becomes provisioned
          */
         void onDeviceProvisioned();
+
+        /**
+         * Called when the device policy changes.
+         * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
+         */
+        void onDevicePolicyManagerStateChanged();
+    }
+
+    // Simple class that allows methods to easily be overwritten
+    public static class InfoCallbackImpl implements InfoCallback {
+        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
+                int batteryLevel) {
+        }
+
+        public void onTimeChanged() {
+        }
+
+        public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+        }
+
+        public void onRingerModeChanged(int state) {
+        }
+
+        public void onPhoneStateChanged(int phoneState) {
+        }
+
+        public void onClockVisibilityChanged() {
+        }
+
+        public void onDeviceProvisioned() {
+        }
+
+        public void onDevicePolicyManagerStateChanged() {
+        }
     }
 
     /**
@@ -653,4 +702,10 @@
     public boolean getMaxFaceUnlockAttemptsReached() {
         return mFailedFaceUnlockAttempts >= FAILED_FACE_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
     }
+
+    public boolean isSimLocked() {
+        return mSimState == IccCard.State.PIN_REQUIRED
+            || mSimState == IccCard.State.PUK_REQUIRED
+            || mSimState == IccCard.State.PERM_DISABLED;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 52d6d24..377ea66 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -18,6 +18,7 @@
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.widget.LockPatternUtils;
 
@@ -90,7 +91,7 @@
  * thread of the keyguard.
  */
 public class KeyguardViewMediator implements KeyguardViewCallback,
-        KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
+        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;
@@ -265,6 +266,20 @@
     private int mLockSoundStreamId;
     private int mMasterStreamMaxVolume;
 
+    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
+
+        @Override
+        public void onClockVisibilityChanged() {
+            adjustStatusBarLocked();
+        }
+
+        @Override
+        public void onDeviceProvisioned() {
+            mContext.sendBroadcast(mUserPresentIntent);
+        }
+
+    };
+
     public KeyguardViewMediator(Context context, PhoneWindowManager callback,
             LocalPowerManager powerManager) {
         mContext = context;
@@ -293,7 +308,8 @@
 
         mUpdateMonitor = new KeyguardUpdateMonitor(context);
 
-        mUpdateMonitor.registerInfoCallback(this);
+        mUpdateMonitor.registerInfoCallback(mInfoCallback);
+
         mUpdateMonitor.registerSimStateCallback(this);
 
         mLockPatternUtils = new LockPatternUtils(mContext);
@@ -750,8 +766,8 @@
             case PUK_REQUIRED:
                 synchronized (this) {
                     if (!isShowing()) {
-                        if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, we need "
-                                + "to show the keyguard so the user can enter their sim pin");
+                        if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, "
+                                + "we need to show keyguard so user can enter their sim pin");
                         doKeyguardLocked();
                     } else {
                         resetStateLocked();
@@ -1306,38 +1322,4 @@
         }
     }
 
-    /** {@inheritDoc} */
-    public void onClockVisibilityChanged() {
-        adjustStatusBarLocked();
-    }
-
-    /** {@inheritDoc} */
-    public void onPhoneStateChanged(int phoneState) {
-        // 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
-    }
-
-    /** {@inheritDoc} */
-    public void onDeviceProvisioned() {
-        mContext.sendBroadcast(mUserPresentIntent);
-    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 3ca57c6..2e7769b 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -17,6 +17,8 @@
 package com.android.internal.policy.impl;
 
 import com.android.internal.R;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
 import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
 import com.android.internal.policy.IFaceLockCallback;
 import com.android.internal.policy.IFaceLockInterface;
@@ -80,8 +82,7 @@
  * {@link com.android.internal.policy.impl.KeyguardViewManager}
  * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
  */
-public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback,
-        KeyguardUpdateMonitor.InfoCallback {
+public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback {
 
     private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000;
 
@@ -133,12 +134,6 @@
     // So the user has a consistent amount of time when brought to the backup method from FaceLock
     private final int BACKUP_LOCK_TIMEOUT = 5000;
 
-    /**
-     * The current {@link KeyguardScreen} will use this to communicate back to us.
-     */
-    KeyguardScreenCallback mKeyguardScreenCallback;
-
-
     private boolean mRequiresSim;
     //True if we have some sort of overlay on top of the Lockscreen
     //Also true if we've activated a phone call, either emergency dialing or incoming
@@ -150,6 +145,10 @@
     //True if this device is currently plugged in
     private boolean mPluggedIn;
 
+    // The music control widget
+    private TransportControlView mTransportControlView;
+
+    private Parcelable mSavedState;
 
     /**
      * Either a lock screen (an informational keyguard screen), or an unlock
@@ -216,7 +215,6 @@
      */
     private boolean mIsVerifyUnlockOnly = false;
 
-
     /**
      * Used to lookup the state of the lock pattern
      */
@@ -274,10 +272,6 @@
         }
     };
 
-    private TransportControlView mTransportControlView;
-
-    private Parcelable mSavedState;
-
     /**
      * @return Whether we are stuck on the lock screen because the sim is
      *   missing.
@@ -290,6 +284,160 @@
     }
 
     /**
+     * The current {@link KeyguardScreen} will use this to communicate back to us.
+     */
+    KeyguardScreenCallback mKeyguardScreenCallback = new KeyguardScreenCallback() {
+
+        public void goToLockScreen() {
+            mForgotPattern = false;
+            if (mIsVerifyUnlockOnly) {
+                // navigating away from unlock screen during verify mode means
+                // we are done and the user failed to authenticate.
+                mIsVerifyUnlockOnly = false;
+                getCallback().keyguardDone(false);
+            } else {
+                updateScreen(Mode.LockScreen, false);
+            }
+        }
+
+        public void goToUnlockScreen() {
+            final IccCard.State simState = mUpdateMonitor.getSimState();
+            if (stuckOnLockScreenBecauseSimMissing()
+                     || (simState == IccCard.State.PUK_REQUIRED
+                         && !mLockPatternUtils.isPukUnlockScreenEnable())){
+                // stuck on lock screen when sim missing or
+                // puk'd but puk unlock screen is disabled
+                return;
+            }
+            if (!isSecure()) {
+                getCallback().keyguardDone(true);
+            } else {
+                updateScreen(Mode.UnlockScreen, false);
+            }
+        }
+
+        public void forgotPattern(boolean isForgotten) {
+            if (mEnableFallback) {
+                mForgotPattern = isForgotten;
+                updateScreen(Mode.UnlockScreen, false);
+            }
+        }
+
+        public boolean isSecure() {
+            return LockPatternKeyguardView.this.isSecure();
+        }
+
+        public boolean isVerifyUnlockOnly() {
+            return mIsVerifyUnlockOnly;
+        }
+
+        public void recreateMe(Configuration config) {
+            removeCallbacks(mRecreateRunnable);
+            post(mRecreateRunnable);
+        }
+
+        public void takeEmergencyCallAction() {
+            mHasOverlay = true;
+
+            // Continue showing FaceLock area until dialer comes up or call is resumed
+            if (usingFaceLock() && mFaceLockServiceRunning) {
+                showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
+            }
+
+            // FaceLock must be stopped if it is running when emergency call is pressed
+            stopAndUnbindFromFaceLock();
+
+            pokeWakelock(EMERGENCY_CALL_TIMEOUT);
+            if (TelephonyManager.getDefault().getCallState()
+                    == TelephonyManager.CALL_STATE_OFFHOOK) {
+                mLockPatternUtils.resumeCall();
+            } else {
+                Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                getContext().startActivity(intent);
+            }
+        }
+
+        public void pokeWakelock() {
+            getCallback().pokeWakelock();
+        }
+
+        public void pokeWakelock(int millis) {
+            getCallback().pokeWakelock(millis);
+        }
+
+        public void keyguardDone(boolean authenticated) {
+            getCallback().keyguardDone(authenticated);
+            mSavedState = null; // clear state so we re-establish when locked again
+        }
+
+        public void keyguardDoneDrawing() {
+            // irrelevant to keyguard screen, they shouldn't be calling this
+        }
+
+        public void reportFailedUnlockAttempt() {
+            mUpdateMonitor.reportFailedAttempt();
+            final int failedAttempts = mUpdateMonitor.getFailedAttempts();
+            if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts +
+                " (enableFallback=" + mEnableFallback + ")");
+
+            final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
+                    == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+
+            final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
+                    .getMaximumFailedPasswordsForWipe(null);
+
+            final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
+                    - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
+
+            final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
+                    (failedAttemptsBeforeWipe - failedAttempts)
+                    : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
+
+            if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
+                // If we reach this code, it means the user has installed a DevicePolicyManager
+                // that requests device wipe after N attempts.  Once we get below the grace
+                // period, we'll post this dialog every time as a clear warning until the
+                // bombshell hits and the device is wiped.
+                if (remainingBeforeWipe > 0) {
+                    showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
+                } else {
+                    // Too many attempts. The device will be wiped shortly.
+                    Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
+                    showWipeDialog(failedAttempts);
+                }
+            } else {
+                boolean showTimeout =
+                    (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
+                if (usingPattern && mEnableFallback) {
+                    if (failedAttempts == failedAttemptWarning) {
+                        showAlmostAtAccountLoginDialog();
+                        showTimeout = false; // don't show both dialogs
+                    } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
+                        mLockPatternUtils.setPermanentlyLocked(true);
+                        updateScreen(mMode, false);
+                        // don't show timeout dialog because we show account unlock screen next
+                        showTimeout = false;
+                    }
+                }
+                if (showTimeout) {
+                    showTimeoutDialog();
+                }
+            }
+            mLockPatternUtils.reportFailedPasswordAttempt();
+        }
+
+        public boolean doesFallbackUnlockScreenExist() {
+            return mEnableFallback;
+        }
+
+        public void reportSuccessfulUnlockAttempt() {
+            mLockPatternUtils.reportSuccessfulPasswordAttempt();
+        }
+    };
+
+    /**
      * @param context Used to inflate, and create views.
      * @param callback Keyguard callback object for pokewakelock(), etc.
      * @param updateMonitor Knows the state of the world, and passed along to each
@@ -313,158 +461,7 @@
         mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
         mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
 
-        mUpdateMonitor.registerInfoCallback(this);
-
-        mKeyguardScreenCallback = new KeyguardScreenCallback() {
-
-            public void goToLockScreen() {
-                mForgotPattern = false;
-                if (mIsVerifyUnlockOnly) {
-                    // navigating away from unlock screen during verify mode means
-                    // we are done and the user failed to authenticate.
-                    mIsVerifyUnlockOnly = false;
-                    getCallback().keyguardDone(false);
-                } else {
-                    updateScreen(Mode.LockScreen, false);
-                }
-            }
-
-            public void goToUnlockScreen() {
-                final IccCard.State simState = mUpdateMonitor.getSimState();
-                if (stuckOnLockScreenBecauseSimMissing()
-                         || (simState == IccCard.State.PUK_REQUIRED
-                             && !mLockPatternUtils.isPukUnlockScreenEnable())){
-                    // stuck on lock screen when sim missing or
-                    // puk'd but puk unlock screen is disabled
-                    return;
-                }
-                if (!isSecure()) {
-                    getCallback().keyguardDone(true);
-                } else {
-                    updateScreen(Mode.UnlockScreen, false);
-                }
-            }
-
-            public void forgotPattern(boolean isForgotten) {
-                if (mEnableFallback) {
-                    mForgotPattern = isForgotten;
-                    updateScreen(Mode.UnlockScreen, false);
-                }
-            }
-
-            public boolean isSecure() {
-                return LockPatternKeyguardView.this.isSecure();
-            }
-
-            public boolean isVerifyUnlockOnly() {
-                return mIsVerifyUnlockOnly;
-            }
-
-            public void recreateMe(Configuration config) {
-                removeCallbacks(mRecreateRunnable);
-                post(mRecreateRunnable);
-            }
-
-            public void takeEmergencyCallAction() {
-                mHasOverlay = true;
-
-                // Continue showing FaceLock area until dialer comes up or call is resumed
-                if (usingFaceLock() && mFaceLockServiceRunning) {
-                    showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
-                }
-
-                // FaceLock must be stopped if it is running when emergency call is pressed
-                stopAndUnbindFromFaceLock();
-
-                pokeWakelock(EMERGENCY_CALL_TIMEOUT);
-                if (TelephonyManager.getDefault().getCallState()
-                        == TelephonyManager.CALL_STATE_OFFHOOK) {
-                    mLockPatternUtils.resumeCall();
-                } else {
-                    Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                    getContext().startActivity(intent);
-                }
-            }
-
-            public void pokeWakelock() {
-                getCallback().pokeWakelock();
-            }
-
-            public void pokeWakelock(int millis) {
-                getCallback().pokeWakelock(millis);
-            }
-
-            public void keyguardDone(boolean authenticated) {
-                getCallback().keyguardDone(authenticated);
-                mSavedState = null; // clear state so we re-establish when locked again
-            }
-
-            public void keyguardDoneDrawing() {
-                // irrelevant to keyguard screen, they shouldn't be calling this
-            }
-
-            public void reportFailedUnlockAttempt() {
-                mUpdateMonitor.reportFailedAttempt();
-                final int failedAttempts = mUpdateMonitor.getFailedAttempts();
-                if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts +
-                    " (enableFallback=" + mEnableFallback + ")");
-
-                final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
-                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-
-                final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
-                        .getMaximumFailedPasswordsForWipe(null);
-
-                final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
-                        - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-
-                final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
-                        (failedAttemptsBeforeWipe - failedAttempts)
-                        : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
-
-                if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
-                    // If we reach this code, it means the user has installed a DevicePolicyManager
-                    // that requests device wipe after N attempts.  Once we get below the grace
-                    // period, we'll post this dialog every time as a clear warning until the
-                    // bombshell hits and the device is wiped.
-                    if (remainingBeforeWipe > 0) {
-                        showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
-                    } else {
-                        // Too many attempts. The device will be wiped shortly.
-                        Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
-                        showWipeDialog(failedAttempts);
-                    }
-                } else {
-                    boolean showTimeout =
-                        (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
-                    if (usingPattern && mEnableFallback) {
-                        if (failedAttempts == failedAttemptWarning) {
-                            showAlmostAtAccountLoginDialog();
-                            showTimeout = false; // don't show both dialogs
-                        } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
-                            mLockPatternUtils.setPermanentlyLocked(true);
-                            updateScreen(mMode, false);
-                            // don't show timeout dialog because we show account unlock screen next
-                            showTimeout = false;
-                        }
-                    }
-                    if (showTimeout) {
-                        showTimeoutDialog();
-                    }
-                }
-                mLockPatternUtils.reportFailedPasswordAttempt();
-            }
-
-            public boolean doesFallbackUnlockScreenExist() {
-                return mEnableFallback;
-            }
-
-            public void reportSuccessfulUnlockAttempt() {
-                mLockPatternUtils.reportSuccessfulPasswordAttempt();
-            }
-        };
+        mUpdateMonitor.registerInfoCallback(mInfoCallback);
 
         /**
          * We'll get key events the current screen doesn't use. see
@@ -707,6 +704,8 @@
 
     @Override
     protected void onDetachedFromWindow() {
+        mUpdateMonitor.removeCallback(mInfoCallback);
+
         removeCallbacks(mRecreateRunnable);
 
         // When view is hidden, need to unbind from FaceLock service if we are using FaceLock
@@ -726,46 +725,39 @@
         post(mRecreateRunnable);
     }
 
-    /** When somebody plugs in or unplugs the device, we don't want to display faceunlock */
-    @Override
-    public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
-        mHasOverlay |= mPluggedIn != pluggedIn;
-        mPluggedIn = pluggedIn;
-        //If it's already running, don't close it down: the unplug didn't start it
-        if (!mFaceLockServiceRunning) {
-            stopAndUnbindFromFaceLock();
-            hideFaceLockArea();
+    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
+
+        /** When somebody plugs in or unplugs the device, we don't want to display faceunlock */
+        @Override
+        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
+                int batteryLevel) {
+            mHasOverlay |= mPluggedIn != pluggedIn;
+            mPluggedIn = pluggedIn;
+            //If it's already running, don't close it down: the unplug didn't start it
+            if (!mFaceLockServiceRunning) {
+                stopAndUnbindFromFaceLock();
+                hideFaceLockArea();
+            }
         }
-    }
 
-    //Ignore these events; they are implemented only because they come from the same interface
-    @Override
-    public void onTimeChanged() {}
-    @Override
-    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {}
-    @Override
-    public void onRingerModeChanged(int state) {}
-
-    @Override
-    public void onClockVisibilityChanged() {
-        int visFlags = getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK;
-        setSystemUiVisibility(visFlags
-                | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0));
-    }
-
-    @Override
-    public void onDeviceProvisioned() {}
-
-    //We need to stop faceunlock when a phonecall comes in
-    @Override
-    public void onPhoneStateChanged(int phoneState) {
-        if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
-        if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
-            mHasOverlay = true;
-            stopAndUnbindFromFaceLock();
-            hideFaceLockArea();
+        @Override
+        public void onClockVisibilityChanged() {
+            int visFlags = getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK;
+            setSystemUiVisibility(visFlags
+                    | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0));
         }
-    }
+
+        //We need to stop faceunlock when a phonecall comes in
+        @Override
+        public void onPhoneStateChanged(int phoneState) {
+            if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
+            if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
+                mHasOverlay = true;
+                stopAndUnbindFromFaceLock();
+                hideFaceLockArea();
+            }
+        }
+    };
 
     @Override
     protected boolean dispatchHoverEvent(MotionEvent event) {
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index edf5199..c9a130b 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -17,6 +17,11 @@
 package com.android.internal.policy.impl;
 
 import com.android.internal.R;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
+import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
+import com.android.internal.policy.impl.LockScreen.MultiWaveViewMethods;
+import com.android.internal.telephony.IccCard.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.SlidingTab;
 import com.android.internal.widget.WaveView;
@@ -60,6 +65,9 @@
     private KeyguardUpdateMonitor mUpdateMonitor;
     private KeyguardScreenCallback mCallback;
 
+    // set to 'true' to show the ring/silence target when camera isn't available
+    private boolean mEnableRingSilenceFallback = false;
+
     // current configuration state of keyboard and display
     private int mKeyboardHidden;
     private int mCreationOrientation;
@@ -71,6 +79,31 @@
     private KeyguardStatusViewManager mStatusViewManager;
     private UnlockWidgetCommonMethods mUnlockWidgetMethods;
     private View mUnlockWidget;
+    public boolean mCameraDisabled;
+
+    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
+
+        @Override
+        public void onRingerModeChanged(int state) {
+            boolean silent = AudioManager.RINGER_MODE_NORMAL != state;
+            if (silent != mSilentMode) {
+                mSilentMode = silent;
+                mUnlockWidgetMethods.updateResources();
+            }
+        }
+
+        @Override
+        public void onDevicePolicyManagerStateChanged() {
+            updateCameraTarget();
+        }
+
+    };
+
+    SimStateCallback mSimStateCallback = new SimStateCallback() {
+        public void onSimStateChanged(State simState) {
+            updateCameraTarget();
+        }
+    };
 
     private interface UnlockWidgetCommonMethods {
         // Update resources based on phone state
@@ -84,6 +117,13 @@
 
         // Animate the widget if it supports ping()
         public void ping();
+
+        // Enable or disable a target. ResourceId is the id of the *drawable* associated with the
+        // target.
+        public void setEnabled(int resourceId, boolean enabled);
+
+        // Get the target position for the given resource. Returns -1 if not found.
+        public int getTargetPosition(int resourceId);
     }
 
     class SlidingTabMethods implements SlidingTab.OnTriggerListener, UnlockWidgetCommonMethods {
@@ -144,6 +184,14 @@
 
         public void ping() {
         }
+
+        public void setEnabled(int resourceId, boolean enabled) {
+            // Not used
+        }
+
+        public int getTargetPosition(int resourceId) {
+            return -1; // Not supported
+        }
     }
 
     class WaveViewMethods implements WaveView.OnTriggerListener, UnlockWidgetCommonMethods {
@@ -181,39 +229,40 @@
         }
         public void ping() {
         }
+        public void setEnabled(int resourceId, boolean enabled) {
+            // Not used
+        }
+        public int getTargetPosition(int resourceId) {
+            return -1; // Not supported
+        }
     }
 
     class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
             UnlockWidgetCommonMethods {
-
         private final MultiWaveView mMultiWaveView;
-        private boolean mCameraDisabled;
 
         MultiWaveViewMethods(MultiWaveView multiWaveView) {
             mMultiWaveView = multiWaveView;
-            final boolean cameraDisabled = mLockPatternUtils.getDevicePolicyManager()
-                    .getCameraDisabled(null);
-            if (cameraDisabled) {
-                Log.v(TAG, "Camera disabled by Device Policy");
-                mCameraDisabled = true;
-            } else {
-                // Camera is enabled if resource is initially defined for MultiWaveView
-                // in the lockscreen layout file
-                mCameraDisabled = mMultiWaveView.getTargetResourceId()
-                        != R.array.lockscreen_targets_with_camera;
-            }
+        }
+
+        public boolean isCameraTargetPresent() {
+            return mMultiWaveView
+                .getTargetPosition(com.android.internal.R.drawable.ic_lockscreen_camera) != -1;
         }
 
         public void updateResources() {
             int resId;
-            if (mCameraDisabled) {
-                // Fall back to showing ring/silence if camera is disabled by DPM...
+            if (mCameraDisabled && mEnableRingSilenceFallback) {
+                // Fall back to showing ring/silence if camera is disabled...
                 resId = mSilentMode ? R.array.lockscreen_targets_when_silent
                     : R.array.lockscreen_targets_when_soundon;
             } else {
                 resId = R.array.lockscreen_targets_with_camera;
             }
-            mMultiWaveView.setTargetResources(resId);
+            if (mMultiWaveView.getTargetResourceId() != resId) {
+                mMultiWaveView.setTargetResources(resId);
+            }
+            setEnabled(com.android.internal.R.drawable.ic_lockscreen_camera, !mCameraDisabled);
         }
 
         public void onGrabbed(View v, int handle) {
@@ -225,29 +274,39 @@
         }
 
         public void onTrigger(View v, int target) {
-            if (target == 0 || target == 1) { // 0 = unlock/portrait, 1 = unlock/landscape
-                mCallback.goToUnlockScreen();
-            } else if (target == 2 || target == 3) { // 2 = alt/portrait, 3 = alt/landscape
-                if (!mCameraDisabled) {
-                    // Start the Camera
-                    Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                    try {
-                        ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "can't dismiss keyguard on launch");
-                    }
-                    try {
-                        mContext.startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.w(TAG, "Camera application not found");
-                    }
-                } else {
-                    toggleRingMode();
-                    mUnlockWidgetMethods.updateResources();
+            final int resId = mMultiWaveView.getResourceIdForTarget(target);
+            switch (resId) {
+                case com.android.internal.R.drawable.ic_lockscreen_camera:
+                    launchCamera();
                     mCallback.pokeWakelock();
-                }
+                    break;
+
+                case com.android.internal.R.drawable.ic_lockscreen_silent:
+                    toggleRingMode();
+                    mCallback.pokeWakelock();
+                break;
+
+                case com.android.internal.R.drawable.ic_lockscreen_unlock:
+                    mCallback.goToUnlockScreen();
+                break;
+            }
+        }
+
+        private void launchCamera() {
+            Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+            intent.setFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            try {
+                ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+            } catch (RemoteException e) {
+                Log.w(TAG, "can't dismiss keyguard on launch");
+            }
+            try {
+                mContext.startActivity(intent);
+            } catch (ActivityNotFoundException e) {
+                Log.w(TAG, "Camera application not found");
             }
         }
 
@@ -271,6 +330,14 @@
         public void ping() {
             mMultiWaveView.ping();
         }
+
+        public void setEnabled(int resourceId, boolean enabled) {
+            mMultiWaveView.setEnableTarget(resourceId, enabled);
+        }
+
+        public int getTargetPosition(int resourceId) {
+            return mMultiWaveView.getTargetPosition(resourceId);
+        }
     }
 
     private void requestUnlockScreen() {
@@ -328,11 +395,8 @@
         mLockPatternUtils = lockPatternUtils;
         mUpdateMonitor = updateMonitor;
         mCallback = callback;
-
         mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
-
         mCreationOrientation = configuration.orientation;
-
         mKeyboardHidden = configuration.hardKeyboardHidden;
 
         if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
@@ -358,10 +422,16 @@
 
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         mSilentMode = isSilentMode();
-
         mUnlockWidget = findViewById(R.id.unlock_widget);
-        if (mUnlockWidget instanceof SlidingTab) {
-            SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
+        mUnlockWidgetMethods = createUnlockMethods(mUnlockWidget);
+
+        if (DBG) Log.v(TAG, "*** LockScreen accel is "
+                + (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
+    }
+
+    private UnlockWidgetCommonMethods createUnlockMethods(View unlockWidget) {
+        if (unlockWidget instanceof SlidingTab) {
+            SlidingTab slidingTabView = (SlidingTab) unlockWidget;
             slidingTabView.setHoldAfterTrigger(true, false);
             slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
             slidingTabView.setLeftTabResources(
@@ -371,26 +441,35 @@
                     R.drawable.jog_tab_left_unlock);
             SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
             slidingTabView.setOnTriggerListener(slidingTabMethods);
-            mUnlockWidgetMethods = slidingTabMethods;
-        } else if (mUnlockWidget instanceof WaveView) {
-            WaveView waveView = (WaveView) mUnlockWidget;
+            return slidingTabMethods;
+        } else if (unlockWidget instanceof WaveView) {
+            WaveView waveView = (WaveView) unlockWidget;
             WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
             waveView.setOnTriggerListener(waveViewMethods);
-            mUnlockWidgetMethods = waveViewMethods;
-        } else if (mUnlockWidget instanceof MultiWaveView) {
-            MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
+            return waveViewMethods;
+        } else if (unlockWidget instanceof MultiWaveView) {
+            MultiWaveView multiWaveView = (MultiWaveView) unlockWidget;
             MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
             multiWaveView.setOnTriggerListener(multiWaveViewMethods);
-            mUnlockWidgetMethods = multiWaveViewMethods;
+            return multiWaveViewMethods;
         } else {
-            throw new IllegalStateException("Unrecognized unlock widget: " + mUnlockWidget);
+            throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget);
         }
+    }
 
-        // Update widget with initial ring state
+    private void updateCameraTarget() {
+        boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager()
+                .getCameraDisabled(null);
+        boolean disabledBySimState = mUpdateMonitor.isSimLocked();
+        boolean targetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
+                ? ((MultiWaveViewMethods) mUnlockWidgetMethods).isCameraTargetPresent() : false;
+        if (disabledByAdmin) {
+            Log.v(TAG, "Camera disabled by Device Policy");
+        } else if (disabledBySimState) {
+            Log.v(TAG, "Camera disabled by Sim State");
+        }
+        mCameraDisabled = disabledByAdmin || disabledBySimState || !targetPresent;
         mUnlockWidgetMethods.updateResources();
-
-        if (DBG) Log.v(TAG, "*** LockScreen accel is "
-                + (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
     }
 
     private boolean isSilentMode() {
@@ -448,6 +527,8 @@
 
     /** {@inheritDoc} */
     public void onPause() {
+        mUpdateMonitor.removeCallback(mInfoCallback);
+        mUpdateMonitor.removeCallback(mSimStateCallback);
         mStatusViewManager.onPause();
         mUnlockWidgetMethods.reset(false);
     }
@@ -460,27 +541,21 @@
 
     /** {@inheritDoc} */
     public void onResume() {
+        // We don't want to show the camera target if SIM state prevents us from
+        // launching the camera. So watch for SIM changes...
+        mUpdateMonitor.registerSimStateCallback(mSimStateCallback);
+        mUpdateMonitor.registerInfoCallback(mInfoCallback);
+
         mStatusViewManager.onResume();
         postDelayed(mOnResumePing, ON_RESUME_PING_DELAY);
     }
 
     /** {@inheritDoc} */
     public void cleanUp() {
-        mUpdateMonitor.removeCallback(this); // this must be first
+        mUpdateMonitor.removeCallback(mInfoCallback); // this must be first
+        mUpdateMonitor.removeCallback(mSimStateCallback);
         mLockPatternUtils = null;
         mUpdateMonitor = null;
         mCallback = null;
     }
-
-    /** {@inheritDoc} */
-    public void onRingerModeChanged(int state) {
-        boolean silent = AudioManager.RINGER_MODE_NORMAL != state;
-        if (silent != mSilentMode) {
-            mSilentMode = silent;
-            mUnlockWidgetMethods.updateResources();
-        }
-    }
-
-    public void onPhoneStateChanged(String newState) {
-    }
 }
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 1652cae..257f62c 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -15,6 +15,7 @@
     $(call include-path-for, audio-effects) \
     $(call include-path-for, audio-utils)
 
+# FIXME keep libmedia_native but remove libmedia after split
 LOCAL_SHARED_LIBRARIES := \
     libaudioutils \
     libcommon_time_client \
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index caee1ab..d21212f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2258,7 +2258,7 @@
         for (int i=0; i<N; i++) {
             PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
             mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
-                    pal.startFlags, doResume && i == (N-1));
+                    pal.startFlags, doResume && i == (N-1), null);
         }
         mPendingActivityLaunches.clear();
     }
@@ -4252,7 +4252,8 @@
 
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+            int requestCode, Intent[] intents, String[] resolvedTypes,
+            int flags, Bundle options) {
         enforceNotIsolatedCaller("getIntentSender");
         // Refuse possible leaked file descriptors
         if (intents != null) {
@@ -4278,6 +4279,11 @@
                         "Intent array length does not match resolvedTypes length");
             }
         }
+        if (options != null) {
+            if (options.hasFileDescriptors()) {
+                throw new IllegalArgumentException("File descriptors passed in options");
+            }
+        }
         
         synchronized(this) {
             int callingUid = Binder.getCallingUid();
@@ -4300,7 +4306,7 @@
                     Slog.i(TAG_MU, "Getting intent sender for origCallingUid="
                             + Binder.getOrigCallingUid());
                 return getIntentSenderLocked(type, packageName, Binder.getOrigCallingUid(),
-                        token, resultWho, requestCode, intents, resolvedTypes, flags);
+                        token, resultWho, requestCode, intents, resolvedTypes, flags, options);
                 
             } catch (RemoteException e) {
                 throw new SecurityException(e);
@@ -4310,7 +4316,8 @@
     
     IIntentSender getIntentSenderLocked(int type,
             String packageName, int callingUid, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+            Bundle options) {
         if (DEBUG_MU)
             Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
         ActivityRecord activity = null;
@@ -4332,7 +4339,7 @@
 
         PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                 type, packageName, activity, resultWho,
-                requestCode, intents, resolvedTypes, flags);
+                requestCode, intents, resolvedTypes, flags, options);
         WeakReference<PendingIntentRecord> ref;
         ref = mIntentSenderRecords.get(key);
         PendingIntentRecord rec = ref != null ? ref.get() : null;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index b42d98ea..53cb2b0 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -20,6 +20,7 @@
 import com.android.server.am.ActivityStack.ActivityState;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -95,6 +96,7 @@
     ArrayList results;      // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
     ArrayList newIntents;   // any pending new intents for single-top mode
+    ActivityOptions pendingOptions; // most recently given options
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
     ProcessRecord app;      // if non-null, hosting application
@@ -538,6 +540,28 @@
         }
     }
 
+    void updateOptionsLocked(Bundle options) {
+        if (options != null) {
+            pendingOptions = new ActivityOptions(options);
+        }
+    }
+
+    void applyOptionsLocked() {
+        if (pendingOptions != null) {
+            if (pendingOptions.isCustomAnimation()) {
+                service.mWindowManager.overridePendingAppTransition(
+                        pendingOptions.getPackageName(),
+                        pendingOptions.getCustomEnterResId(),
+                        pendingOptions.getCustomExitResId());
+            }
+            pendingOptions = null;
+        }
+    }
+
+    void clearOptionsLocked() {
+        pendingOptions = null;
+    }
+
     void removeUriPermissionsLocked() {
         if (uriPermissions != null) {
             uriPermissions.removeUriPermissionsLocked();
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 13ee008..7e8df35 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -22,6 +22,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.IThumbnailRetriever;
@@ -1456,6 +1457,7 @@
         // We are starting up the next activity, so tell the window manager
         // that the previous one will be hidden soon.  This way it can know
         // to ignore it when computing the desired screen orientation.
+        boolean noAnim = false;
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -1474,6 +1476,7 @@
                 if (DEBUG_TRANSITION) Slog.v(TAG,
                         "Prepare open transition: prev=" + prev);
                 if (mNoAnimActivities.contains(next)) {
+                    noAnim = true;
                     mService.mWindowManager.prepareAppTransition(
                             WindowManagerPolicy.TRANSIT_NONE, false);
                 } else {
@@ -1490,6 +1493,7 @@
             if (DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
+                noAnim = true;
                 mService.mWindowManager.prepareAppTransition(
                         WindowManagerPolicy.TRANSIT_NONE, false);
             } else {
@@ -1497,6 +1501,11 @@
                         WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false);
             }
         }
+        if (!noAnim) {
+            next.applyOptionsLocked();
+        } else {
+            next.clearOptionsLocked();
+        }
 
         if (next.app != null && next.app.thread != null) {
             if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
@@ -1655,7 +1664,7 @@
     }
 
     private final void startActivityLocked(ActivityRecord r, boolean newTask,
-            boolean doResume, boolean keepCurTransition) {
+            boolean doResume, boolean keepCurTransition, Bundle options) {
         final int NH = mHistory.size();
 
         int addPos = -1;
@@ -1748,6 +1757,7 @@
                         : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
+            r.updateOptionsLocked(options);
             mService.mWindowManager.addAppToken(
                     addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
             boolean doShow = true;
@@ -2457,7 +2467,7 @@
         }
         
         err = startActivityUncheckedLocked(r, sourceRecord,
-                startFlags, true);
+                startFlags, true, options);
         if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
             // Someone asked to have the keyguard dismissed on the next
             // activity start, but we are not actually doing an activity
@@ -2480,7 +2490,8 @@
     }
 
     final int startActivityUncheckedLocked(ActivityRecord r,
-            ActivityRecord sourceRecord, int startFlags, boolean doResume) {
+            ActivityRecord sourceRecord, int startFlags, boolean doResume,
+            Bundle options) {
         final Intent intent = r.intent;
         final int callingUid = r.launchedFromUid;
         final int userId = r.userId;
@@ -2591,6 +2602,7 @@
                             // We really do want to push this one into the
                             // user's face, right now.
                             moveHomeToFrontFromLaunchLocked(launchFlags);
+                            r.updateOptionsLocked(options);
                             moveTaskToFrontLocked(taskTop.task, r);
                         }
                     }
@@ -2794,6 +2806,7 @@
                 if (where >= 0) {
                     ActivityRecord top = moveActivityToFrontLocked(where);
                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
+                    top.updateOptionsLocked(options);
                     top.deliverNewIntentLocked(callingUid, r.intent);
                     if (doResume) {
                         resumeTopActivityLocked(null);
@@ -2829,7 +2842,7 @@
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
         }
         logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
-        startActivityLocked(r, newTask, doResume, keepCurTransition);
+        startActivityLocked(r, newTask, doResume, keepCurTransition, options);
         return ActivityManager.START_SUCCESS;
     }
 
@@ -2944,7 +2957,7 @@
                                 ActivityManager.INTENT_SENDER_ACTIVITY, "android",
                                 realCallingUid, null, null, 0, new Intent[] { intent },
                                 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
-                                | PendingIntent.FLAG_ONE_SHOT);
+                                | PendingIntent.FLAG_ONE_SHOT, null);
                         
                         Intent newIntent = new Intent();
                         if (requestCode >= 0) {
@@ -3095,9 +3108,15 @@
                                 "FLAG_CANT_SAVE_STATE not supported here");
                     }
 
+                    Bundle theseOptions;
+                    if (options != null && i == intents.length-1) {
+                        theseOptions = options;
+                    } else {
+                        theseOptions = null;
+                    }
                     int res = startActivityLocked(caller, intent, resolvedTypes[i],
                             aInfo, resultTo, null, -1, callingPid, callingUid,
-                            0, options, componentSpecified, outActivity);
+                            0, theseOptions, componentSpecified, outActivity);
                     if (res < 0) {
                         return res;
                     }
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 9676084..ad15da1 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -49,6 +49,7 @@
         final int requestCode;
         final Intent requestIntent;
         final String requestResolvedType;
+        final Bundle options;
         Intent[] allIntents;
         String[] allResolvedTypes;
         final int flags;
@@ -57,7 +58,7 @@
         private static final int ODD_PRIME_NUMBER = 37;
         
         Key(int _t, String _p, ActivityRecord _a, String _w,
-                int _r, Intent[] _i, String[] _it, int _f) {
+                int _r, Intent[] _i, String[] _it, int _f, Bundle _o) {
             type = _t;
             packageName = _p;
             activity = _a;
@@ -68,6 +69,7 @@
             allIntents = _i;
             allResolvedTypes = _it;
             flags = _f;
+            options = _o;
             
             int hash = 23;
             hash = (ODD_PRIME_NUMBER*hash) + _f;
@@ -215,6 +217,13 @@
                 boolean sendFinish = finishedReceiver != null;
                 switch (key.type) {
                     case ActivityManager.INTENT_SENDER_ACTIVITY:
+                        if (options == null) {
+                            options = key.options;
+                        } else if (key.options != null) {
+                            Bundle opts = new Bundle(key.options);
+                            opts.putAll(options);
+                            options = opts;
+                        }
                         try {
                             if (key.allIntents != null && key.allIntents.length > 1) {
                                 Intent[] allIntents = new Intent[key.allIntents.length];
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 9f45eff..bc98f86 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -20,6 +20,10 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.ENFORCEMENT_DEFAULT;
+import static android.content.pm.PackageManager.ENFORCEMENT_YES;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
 import static libcore.io.OsConstants.S_ISLNK;
 
 import com.android.internal.app.IMediaContainerService;
@@ -1872,6 +1876,9 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
+            if (!isPermissionEnforcedLocked(permName)) {
+                return PackageManager.PERMISSION_GRANTED;
+            }
         }
         return PackageManager.PERMISSION_DENIED;
     }
@@ -1890,6 +1897,9 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
+            if (!isPermissionEnforcedLocked(permName)) {
+                return PackageManager.PERMISSION_GRANTED;
+            }
         }
         return PackageManager.PERMISSION_DENIED;
     }
@@ -8835,4 +8845,44 @@
     public List<UserInfo> getUsers() {
         return mUserManager.getUsers();
     }
+
+    @Override
+    public void setPermissionEnforcement(String permission, int enforcement) {
+        mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null);
+        if (READ_EXTERNAL_STORAGE.equals(permission)) {
+            synchronized (mPackages) {
+                if (mSettings.mReadExternalStorageEnforcement != enforcement) {
+                    mSettings.mReadExternalStorageEnforcement = enforcement;
+                    mSettings.writeLPr();
+                }
+            }
+        } else {
+            throw new IllegalArgumentException("No selective enforcement for " + permission);
+        }
+    }
+
+    @Override
+    public int getPermissionEnforcement(String permission) {
+        mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null);
+        if (READ_EXTERNAL_STORAGE.equals(permission)) {
+            synchronized (mPackages) {
+                return mSettings.mReadExternalStorageEnforcement;
+            }
+        } else {
+            throw new IllegalArgumentException("No selective enforcement for " + permission);
+        }
+    }
+
+    private boolean isPermissionEnforcedLocked(String permission) {
+        if (READ_EXTERNAL_STORAGE.equals(permission)) {
+            switch (mSettings.mReadExternalStorageEnforcement) {
+                case ENFORCEMENT_DEFAULT:
+                    return false;
+                case ENFORCEMENT_YES:
+                    return true;
+            }
+        }
+
+        return true;
+    }
 }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 5da6ac9..363d020 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -20,6 +20,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.ENFORCEMENT_DEFAULT;
 
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
@@ -74,6 +75,9 @@
 
     private static final boolean DEBUG_STOPPED = false;
 
+    private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
+    private static final String ATTR_ENFORCEMENT = "enforcement";
+
     private final File mSettingsFilename;
     private final File mBackupSettingsFilename;
     private final File mPackageListFilename;
@@ -91,6 +95,8 @@
     int mInternalSdkPlatform;
     int mExternalSdkPlatform;
 
+    int mReadExternalStorageEnforcement = ENFORCEMENT_DEFAULT;
+
     /** Device identity for the purpose of package verification. */
     private VerifierDeviceIdentity mVerifierDeviceIdentity;
 
@@ -864,13 +870,20 @@
             serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
             serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
             serializer.endTag(null, "last-platform-version");
-            
+
             if (mVerifierDeviceIdentity != null) {
                 serializer.startTag(null, "verifier");
                 serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
                 serializer.endTag(null, "verifier");
             }
 
+            if (mReadExternalStorageEnforcement != ENFORCEMENT_DEFAULT) {
+                serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
+                serializer.attribute(
+                        null, ATTR_ENFORCEMENT, Integer.toString(mReadExternalStorageEnforcement));
+                serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
+            }
+
             serializer.startTag(null, "permission-trees");
             for (BasePermission bp : mPermissionTrees.values()) {
                 writePermissionLPr(serializer, bp);
@@ -1291,6 +1304,12 @@
                         Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
                                 + e.getMessage());
                     }
+                } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
+                    final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
+                    try {
+                        mReadExternalStorageEnforcement = Integer.parseInt(enforcement);
+                    } catch (NumberFormatException e) {
+                    }
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                             + parser.getName());
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 67b667a..3ae9f24 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -135,6 +135,10 @@
             animLayerAdjustment = adj;
             updateLayers();
         }
+        // Start out animation gone if window is gone, or visible if window is visible.
+        transformation.clear();
+        transformation.setAlpha(reportedVisible ? 1 : 0);
+        hasTransformation = true;
     }
 
     public void setDummyAnimation() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 6993657..407b732 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -8675,7 +8675,6 @@
                     } else {
                         mDimAnimator.show(innerDw, innerDh);
                     }
-                    mDimAnimator.show(innerDw, innerDh);
                     mDimAnimator.updateParameters(mContext.getResources(),
                             w, currentTime);
                 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 57d0374..9fc7049 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -640,6 +640,10 @@
         mAnimation = anim;
         mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
         mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
+        // Start out animation gone if window is gone, or visible if window is visible.
+        mTransformation.clear();
+        mTransformation.setAlpha(mLastHidden ? 0 : 1);
+        mHasLocalTransformation = true;
     }
 
     public void clearAnimation() {
@@ -933,13 +937,15 @@
             if (!mService.showSurfaceRobustlyLocked(this)) {
                 return false;
             }
+            
+            mService.enableScreenIfNeededLocked();
+
+            mService.applyEnterAnimationLocked(this);
+
             mLastAlpha = -1;
             mHasDrawn = true;
             mLastHidden = false;
             mReadyToShow = false;
-            mService.enableScreenIfNeededLocked();
-
-            mService.applyEnterAnimationLocked(this);
 
             int i = mChildWindows.size();
             while (i > 0) {
diff --git a/test-runner/src/android/test/BandwidthTestRunner.java b/test-runner/src/android/test/BandwidthTestRunner.java
deleted file mode 100644
index 9c5478d..0000000
--- a/test-runner/src/android/test/BandwidthTestRunner.java
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-
-package android.test;
-
-import android.net.NetworkStats;
-import android.net.NetworkStats.Entry;
-import android.net.TrafficStats;
-import android.os.Bundle;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestListener;
-
-import java.lang.reflect.Method;
-
-/**
- * A specialized {@link android.app.Instrumentation} that can collect Bandwidth statistics during
- * the execution of the test.
- * This is used in place of {@link InstrumentationTestRunner}.
- * i.e. adb shell am instrumentation -w -e class com.android.foo.FooTest \
- *          com.android.foo/android.test.BandwidthTestRunner
- *
- * @see NetworkStats and @see TrafficStats for details of the collected statistics
- * @hide
- */
-public class BandwidthTestRunner extends InstrumentationTestRunner implements TestListener {
-    private static final String REPORT_KEY_PACKETS_SENT = "txPackets";
-    private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets";
-    private static final String REPORT_KEY_BYTES_SENT = "txBytes";
-    private static final String REPORT_KEY_BYTES_RECEIVED = "rxBytes";
-    private static final String REPORT_KEY_OPERATIONS = "operations";
-
-    private boolean mHasClassAnnotation;
-    private boolean mIsBandwidthTest;
-    private Bundle mTestResult;
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        super.onCreate(arguments);
-        addTestListener(this);
-    }
-
-    public void addError(Test test, Throwable t) {
-    }
-
-    public void addFailure(Test test, AssertionFailedError t) {
-    }
-
-    public void startTest(Test test) {
-        String testClass = test.getClass().getName();
-        String testName = ((TestCase)test).getName();
-        Method testMethod = null;
-        try {
-            testMethod = test.getClass().getMethod(testName);
-        } catch (NoSuchMethodException e) {
-            // ignore- the test with given name does not exist. Will be handled during test
-            // execution
-        }
-        try {
-            // Look for BandwdthTest annotation on both test class and test method
-            if (testMethod != null ) {
-                if (testMethod.isAnnotationPresent(BandwidthTest.class) ){
-                    mIsBandwidthTest = true;
-                    TrafficStats.startDataProfiling(null);
-                } else if (test.getClass().isAnnotationPresent(BandwidthTest.class)){
-                    mIsBandwidthTest = true;
-                    TrafficStats.startDataProfiling(null);
-                }
-            }
-        } catch (SecurityException e) {
-            // ignore - the test with given name cannot be accessed. Will be handled during
-            // test execution
-        }
-    }
-
-    public void endTest(Test test) {
-        if (mIsBandwidthTest){
-            mTestResult = new Bundle();
-            mIsBandwidthTest=false;
-            NetworkStats stats = TrafficStats.stopDataProfiling(null);
-            Entry entry = stats.getTotal(null);
-            mTestResult.putLong(REPORT_KEY_BYTES_RECEIVED, entry.rxBytes);
-            mTestResult.putLong(REPORT_KEY_BYTES_SENT, entry.txBytes);
-            mTestResult.putLong(REPORT_KEY_PACKETS_RECEIVED, entry.rxPackets);
-            mTestResult.putLong(REPORT_KEY_PACKETS_SENT, entry.txPackets);
-            mTestResult.putLong(REPORT_KEY_OPERATIONS, entry.operations);
-            System.out.println(mTestResult.toString());
-            sendStatus(0, mTestResult);
-        }
-    }
-}