Merge "Auto-show IME for dialogs on large screens."
diff --git a/Android.mk b/Android.mk
index efa7d69..4e286dbb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -395,6 +395,8 @@
 		            resources/samples/AccessibilityService "Accessibility Service" \
 		-samplecode $(sample_dir)/ApiDemos \
 		            resources/samples/ApiDemos "API Demos" \
+		-samplecode $(sample_dir)/AccelerometerPlay \
+		            resources/samples/AccelerometerPlay "Accelerometer Play" \
 		-samplecode $(sample_dir)/BackupRestore \
 		            resources/samples/BackupRestore "Backup and Restore" \
 		-samplecode $(sample_dir)/BluetoothChat \
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 0925940..39a0c19 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -49,19 +49,23 @@
     InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue) {
         mSubtypeNameResId = nameId;
         mSubtypeIconResId = iconId;
-        mSubtypeLocale = locale;
-        mSubtypeMode = mode;
-        mSubtypeExtraValue = extraValue;
+        mSubtypeLocale = locale != null ? locale : "";
+        mSubtypeMode = mode != null ? mode : "";
+        mSubtypeExtraValue = extraValue != null ? extraValue : "";
         mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
                 mSubtypeMode, mSubtypeExtraValue);
     }
 
     InputMethodSubtype(Parcel source) {
+        String s;
         mSubtypeNameResId = source.readInt();
         mSubtypeIconResId = source.readInt();
-        mSubtypeLocale = source.readString();
-        mSubtypeMode = source.readString();
-        mSubtypeExtraValue = source.readString();
+        s = source.readString();
+        mSubtypeLocale = s != null ? s : "";
+        s = source.readString();
+        mSubtypeMode = s != null ? s : "";
+        s = source.readString();
+        mSubtypeExtraValue = s != null ? s : "";
         mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
                 mSubtypeMode, mSubtypeExtraValue);
     }
@@ -110,8 +114,9 @@
     public boolean equals(Object o) {
         if (o instanceof InputMethodSubtype) {
             InputMethodSubtype subtype = (InputMethodSubtype) o;
-            return (subtype.getNameResId() == getNameResId())
-                && (subtype.getMode() == getMode())
+            return (subtype.hashCode() == hashCode())
+                && (subtype.getNameResId() == getNameResId())
+                && (subtype.getMode().equals(getMode()))
                 && (subtype.getIconResId() == getIconResId())
                 && (subtype.getLocale().equals(getLocale()))
                 && (subtype.getExtraValue().equals(getExtraValue()));
@@ -146,4 +151,4 @@
             String mode, String extraValue) {
         return Arrays.hashCode(new Object[] {nameResId, iconResId, locale, mode, extraValue});
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
new file mode 100644
index 0000000..73a8c66
--- /dev/null
+++ b/core/java/android/widget/Switch.java
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ */
+
+package android.widget;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+/**
+ * A Switch is a two-state toggle switch widget that can select between two
+ * options. The user may drag the "thumb" back and forth to choose the selected option,
+ * or simply tap to toggle as if it were a checkbox.
+ *
+ * @hide
+ */
+public class Switch extends CompoundButton {
+    private static final int TOUCH_MODE_IDLE = 0;
+    private static final int TOUCH_MODE_DOWN = 1;
+    private static final int TOUCH_MODE_DRAGGING = 2;
+
+    // Enum for the "typeface" XML parameter.
+    private static final int SANS = 1;
+    private static final int SERIF = 2;
+    private static final int MONOSPACE = 3;
+
+    private Drawable mThumbDrawable;
+    private Drawable mTrackDrawable;
+    private int mThumbTextPadding;
+    private int mSwitchMinWidth;
+    private int mSwitchPadding;
+    private CharSequence mTextOn;
+    private CharSequence mTextOff;
+
+    private int mTouchMode;
+    private int mTouchSlop;
+    private float mTouchX;
+    private float mTouchY;
+    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+    private int mMinFlingVelocity;
+
+    private float mThumbPosition;
+    private int mSwitchWidth;
+    private int mSwitchHeight;
+    private int mThumbWidth; // Does not include padding
+
+    private int mSwitchLeft;
+    private int mSwitchTop;
+    private int mSwitchRight;
+    private int mSwitchBottom;
+
+    private TextPaint mTextPaint;
+    private ColorStateList mTextColors;
+    private Layout mOnLayout;
+    private Layout mOffLayout;
+
+    private final Rect mTempRect = new Rect();
+
+    private static final int[] CHECKED_STATE_SET = {
+        R.attr.state_checked
+    };
+
+    /**
+     * Construct a new Switch with default styling.
+     *
+     * @param context The Context that will determine this widget's theming.
+     */
+    public Switch(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Construct a new Switch with default styling, overriding specific style
+     * attributes as requested.
+     *
+     * @param context The Context that will determine this widget's theming.
+     * @param attrs Specification of attributes that should deviate from default styling.
+     */
+    public Switch(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.switchStyle);
+    }
+
+    /**
+     * Construct a new Switch with a default style determined by the given theme attribute,
+     * overriding specific style attributes as requested.
+     *
+     * @param context The Context that will determine this widget's theming.
+     * @param attrs Specification of attributes that should deviate from the default styling.
+     * @param defStyle An attribute ID within the active theme containing a reference to the
+     *                 default style for this widget. e.g. android.R.attr.switchStyle.
+     */
+    public Switch(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+        Resources res = getResources();
+        mTextPaint.density = res.getDisplayMetrics().density;
+        mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.Switch, defStyle, 0);
+
+        mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_switchThumb);
+        mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_switchTrack);
+        mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
+        mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
+        mThumbTextPadding = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
+        mSwitchMinWidth = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.Switch_switchMinWidth, 0);
+        mSwitchPadding = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.Switch_switchPadding, 0);
+
+        int appearance = a.getResourceId(
+                com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
+        if (appearance != 0) {
+            setSwitchTextAppearance(appearance);
+        }
+        a.recycle();
+
+        ViewConfiguration config = ViewConfiguration.get(context);
+        mTouchSlop = config.getScaledTouchSlop();
+        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
+
+        // Refresh display with current params
+        setChecked(isChecked());
+    }
+
+    /**
+     * Sets the switch text color, size, style, hint color, and highlight color
+     * from the specified TextAppearance resource.
+     */
+    public void setSwitchTextAppearance(int resid) {
+        TypedArray appearance =
+                getContext().obtainStyledAttributes(resid,
+                        com.android.internal.R.styleable.TextAppearance);
+
+        ColorStateList colors;
+        int ts;
+
+        colors = appearance.getColorStateList(com.android.internal.R.styleable.
+                TextAppearance_textColor);
+        if (colors != null) {
+            mTextColors = colors;
+        }
+
+        ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
+                TextAppearance_textSize, 0);
+        if (ts != 0) {
+            if (ts != mTextPaint.getTextSize()) {
+                mTextPaint.setTextSize(ts);
+                requestLayout();
+            }
+        }
+
+        int typefaceIndex, styleIndex;
+
+        typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
+                TextAppearance_typeface, -1);
+        styleIndex = appearance.getInt(com.android.internal.R.styleable.
+                TextAppearance_textStyle, -1);
+
+        setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
+
+        int lineHeight = appearance.getDimensionPixelSize(
+                com.android.internal.R.styleable.TextAppearance_textLineHeight, 0);
+        if (lineHeight != 0) {
+            setLineHeight(lineHeight);
+        }
+
+        appearance.recycle();
+    }
+
+    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
+        Typeface tf = null;
+        switch (typefaceIndex) {
+            case SANS:
+                tf = Typeface.SANS_SERIF;
+                break;
+
+            case SERIF:
+                tf = Typeface.SERIF;
+                break;
+
+            case MONOSPACE:
+                tf = Typeface.MONOSPACE;
+                break;
+        }
+
+        setSwitchTypeface(tf, styleIndex);
+    }
+
+    /**
+     * Sets the typeface and style in which the text should be displayed on the
+     * switch, and turns on the fake bold and italic bits in the Paint if the
+     * Typeface that you provided does not have all the bits in the
+     * style that you specified.
+     */
+    public void setSwitchTypeface(Typeface tf, int style) {
+        if (style > 0) {
+            if (tf == null) {
+                tf = Typeface.defaultFromStyle(style);
+            } else {
+                tf = Typeface.create(tf, style);
+            }
+
+            setSwitchTypeface(tf);
+            // now compute what (if any) algorithmic styling is needed
+            int typefaceStyle = tf != null ? tf.getStyle() : 0;
+            int need = style & ~typefaceStyle;
+            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
+            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
+        } else {
+            mTextPaint.setFakeBoldText(false);
+            mTextPaint.setTextSkewX(0);
+            setSwitchTypeface(tf);
+        }
+    }
+
+    /**
+     * Sets the typeface and style in which the text should be displayed on the switch.
+     * Note that not all Typeface families actually have bold and italic
+     * variants, so you may need to use
+     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
+     * that you actually want.
+     *
+     * @attr ref android.R.styleable#TextView_typeface
+     * @attr ref android.R.styleable#TextView_textStyle
+     */
+    public void setSwitchTypeface(Typeface tf) {
+        if (mTextPaint.getTypeface() != tf) {
+            mTextPaint.setTypeface(tf);
+
+            requestLayout();
+            invalidate();
+        }
+    }
+
+    /**
+     * Returns the text for when the button is in the checked state.
+     *
+     * @return The text.
+     */
+    public CharSequence getTextOn() {
+        return mTextOn;
+    }
+
+    /**
+     * Sets the text for when the button is in the checked state.
+     *
+     * @param textOn The text.
+     */
+    public void setTextOn(CharSequence textOn) {
+        mTextOn = textOn;
+        requestLayout();
+    }
+
+    /**
+     * Returns the text for when the button is not in the checked state.
+     *
+     * @return The text.
+     */
+    public CharSequence getTextOff() {
+        return mTextOff;
+    }
+
+    /**
+     * Sets the text for when the button is not in the checked state.
+     *
+     * @param textOff The text.
+     */
+    public void setTextOff(CharSequence textOff) {
+        mTextOff = textOff;
+        requestLayout();
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+
+        if (mOnLayout == null) {
+            mOnLayout = makeLayout(mTextOn);
+        }
+        if (mOffLayout == null) {
+            mOffLayout = makeLayout(mTextOff);
+        }
+
+        mTrackDrawable.getPadding(mTempRect);
+        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
+        final int switchWidth = Math.max(mSwitchMinWidth,
+                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
+        final int switchHeight = mTrackDrawable.getIntrinsicHeight();
+
+        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
+
+        switch (widthMode) {
+            case MeasureSpec.AT_MOST:
+                widthSize = Math.min(widthSize, switchWidth);
+                break;
+
+            case MeasureSpec.UNSPECIFIED:
+                widthSize = switchWidth;
+                break;
+
+            case MeasureSpec.EXACTLY:
+                // Just use what we were given
+                break;
+        }
+
+        switch (heightMode) {
+            case MeasureSpec.AT_MOST:
+                heightSize = Math.min(heightSize, switchHeight);
+                break;
+
+            case MeasureSpec.UNSPECIFIED:
+                heightSize = switchHeight;
+                break;
+
+            case MeasureSpec.EXACTLY:
+                // Just use what we were given
+                break;
+        }
+
+        mSwitchWidth = switchWidth;
+        mSwitchHeight = switchHeight;
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        final int measuredWidth = getMeasuredWidth();
+        final int measuredHeight = getMeasuredHeight();
+        if (measuredHeight < switchHeight) {
+            setMeasuredDimension(measuredWidth, switchHeight);
+        }
+    }
+
+    private Layout makeLayout(CharSequence text) {
+        return new StaticLayout(text, mTextPaint,
+                (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)),
+                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
+    }
+
+    /**
+     * @return true if (x, y) is within the target area of the switch thumb
+     */
+    private boolean hitThumb(float x, float y) {
+        mThumbDrawable.getPadding(mTempRect);
+        final int thumbTop = mSwitchTop - mTouchSlop;
+        final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f) - mTouchSlop;
+        final int thumbRight = thumbLeft + mThumbWidth +
+                mTempRect.left + mTempRect.right + mTouchSlop;
+        final int thumbBottom = mSwitchBottom + mTouchSlop;
+        return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        mVelocityTracker.addMovement(ev);
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                if (hitThumb(x, y)) {
+                    mTouchMode = TOUCH_MODE_DOWN;
+                    mTouchX = x;
+                    mTouchY = y;
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                switch (mTouchMode) {
+                    case TOUCH_MODE_IDLE:
+                        // Didn't target the thumb, treat normally.
+                        break;
+
+                    case TOUCH_MODE_DOWN: {
+                        final float x = ev.getX();
+                        final float y = ev.getY();
+                        if (Math.abs(x - mTouchX) > mTouchSlop ||
+                                Math.abs(y - mTouchY) > mTouchSlop) {
+                            mTouchMode = TOUCH_MODE_DRAGGING;
+                            getParent().requestDisallowInterceptTouchEvent(true);
+                            mTouchX = x;
+                            mTouchY = y;
+                            return true;
+                        }
+                        break;
+                    }
+
+                    case TOUCH_MODE_DRAGGING: {
+                        final float x = ev.getX();
+                        final float dx = x - mTouchX;
+                        float newPos = Math.max(0,
+                                Math.min(mThumbPosition + dx, getThumbScrollRange()));
+                        if (newPos != mThumbPosition) {
+                            mThumbPosition = newPos;
+                            mTouchX = x;
+                            invalidate();
+                        }
+                        return true;
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL: {
+                if (mTouchMode == TOUCH_MODE_DRAGGING) {
+                    stopDrag(ev);
+                    return true;
+                }
+                mTouchMode = TOUCH_MODE_IDLE;
+                mVelocityTracker.clear();
+                break;
+            }
+        }
+
+        return super.onTouchEvent(ev);
+    }
+
+    private void cancelSuperTouch(MotionEvent ev) {
+        MotionEvent cancel = MotionEvent.obtain(ev);
+        cancel.setAction(MotionEvent.ACTION_CANCEL);
+        super.onTouchEvent(cancel);
+        cancel.recycle();
+    }
+
+    /**
+     * Called from onTouchEvent to end a drag operation.
+     *
+     * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
+     */
+    private void stopDrag(MotionEvent ev) {
+        mTouchMode = TOUCH_MODE_IDLE;
+        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP;
+
+        cancelSuperTouch(ev);
+
+        if (commitChange) {
+            boolean newState;
+            mVelocityTracker.computeCurrentVelocity(1000);
+            float xvel = mVelocityTracker.getXVelocity();
+            if (Math.abs(xvel) > mMinFlingVelocity) {
+                newState = xvel < 0;
+            } else {
+                newState = getTargetCheckedState();
+            }
+            animateThumbToCheckedState(newState);
+        } else {
+            animateThumbToCheckedState(isChecked());
+        }
+    }
+
+    private void animateThumbToCheckedState(boolean newCheckedState) {
+        float targetPos = newCheckedState ? 0 : getThumbScrollRange();
+        // TODO animate!
+        mThumbPosition = targetPos;
+        setChecked(newCheckedState);
+    }
+
+    private boolean getTargetCheckedState() {
+        return mThumbPosition <= getThumbScrollRange() / 2;
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        super.setChecked(checked);
+        mThumbPosition = checked ? 0 : getThumbScrollRange();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        int switchRight = getWidth() - getPaddingRight();
+        int switchLeft = switchRight - mSwitchWidth;
+        int switchTop = 0;
+        int switchBottom = 0;
+        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
+            default:
+            case Gravity.TOP:
+                switchTop = getPaddingTop();
+                switchBottom = switchTop + mSwitchHeight;
+                break;
+
+            case Gravity.CENTER_VERTICAL:
+                switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
+                        mSwitchHeight / 2;
+                switchBottom = switchTop + mSwitchHeight;
+                break;
+
+            case Gravity.BOTTOM:
+                switchBottom = getHeight() - getPaddingBottom();
+                switchTop = switchBottom - mSwitchHeight;
+                break;
+        }
+
+        mSwitchLeft = switchLeft;
+        mSwitchTop = switchTop;
+        mSwitchBottom = switchBottom;
+        mSwitchRight = switchRight;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Draw the switch
+        int switchLeft = mSwitchLeft;
+        int switchTop = mSwitchTop;
+        int switchRight = mSwitchRight;
+        int switchBottom = mSwitchBottom;
+
+        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
+        mTrackDrawable.draw(canvas);
+
+        canvas.save();
+
+        mTrackDrawable.getPadding(mTempRect);
+        int switchInnerLeft = switchLeft + mTempRect.left;
+        int switchInnerTop = switchTop + mTempRect.top;
+        int switchInnerRight = switchRight - mTempRect.right;
+        int switchInnerBottom = switchBottom - mTempRect.bottom;
+        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
+
+        mThumbDrawable.getPadding(mTempRect);
+        final int thumbPos = (int) (mThumbPosition + 0.5f);
+        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
+        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
+
+        mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+        mThumbDrawable.draw(canvas);
+
+        mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
+                mTextColors.getDefaultColor()));
+        mTextPaint.drawableState = getDrawableState();
+
+        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
+
+        canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
+                (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
+        switchText.draw(canvas);
+
+        canvas.restore();
+    }
+
+    @Override
+    public int getCompoundPaddingRight() {
+        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
+        if (!TextUtils.isEmpty(getText())) {
+            padding += mSwitchPadding;
+        }
+        return padding;
+    }
+
+    private int getThumbScrollRange() {
+        if (mTrackDrawable == null) {
+            return 0;
+        }
+        mTrackDrawable.getPadding(mTempRect);
+        return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
+    }
+
+    @Override
+    protected int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+        if (isChecked()) {
+            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+        }
+        return drawableState;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+
+        int[] myDrawableState = getDrawableState();
+
+        // Set the state of the Drawable
+        mThumbDrawable.setState(myDrawableState);
+        mTrackDrawable.setState(myDrawableState);
+
+        invalidate();
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+        mThumbDrawable.jumpToCurrentState();
+        mTrackDrawable.jumpToCurrentState();
+    }
+}
diff --git a/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..df435e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png
new file mode 100644
index 0000000..4c8cc86
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..a4ec766
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png
new file mode 100644
index 0000000..a571aa8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png
new file mode 100644
index 0000000..f86e7e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png
new file mode 100644
index 0000000..b4584a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c01ad87
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
new file mode 100644
index 0000000..b3e428d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
new file mode 100644
index 0000000..4d3d5b7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
new file mode 100644
index 0000000..16e11b6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
new file mode 100644
index 0000000..3900997
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
new file mode 100644
index 0000000..ab4fd8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c75612c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png
new file mode 100644
index 0000000..67adadc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..9a05f84
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png
new file mode 100644
index 0000000..58d65ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png
new file mode 100644
index 0000000..172030d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png
new file mode 100644
index 0000000..4ae089b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
new file mode 100644
index 0000000..7e205ac
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
new file mode 100644
index 0000000..b4e7cf5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
new file mode 100644
index 0000000..7003318a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
new file mode 100644
index 0000000..97afcbf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
new file mode 100644
index 0000000..1adc9ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
new file mode 100644
index 0000000..29c6328
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/switch_inner_holo_dark.xml b/core/res/res/drawable/switch_inner_holo_dark.xml
new file mode 100644
index 0000000..3eb55ee
--- /dev/null
+++ b/core/res/res/drawable/switch_inner_holo_dark.xml
@@ -0,0 +1,21 @@
+<?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_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_dark" />
+    <item android:state_pressed="true"  android:drawable="@drawable/switch_thumb_pressed_holo_dark" />
+    <item                               android:drawable="@drawable/switch_thumb_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/switch_inner_holo_light.xml b/core/res/res/drawable/switch_inner_holo_light.xml
new file mode 100644
index 0000000..9b287cf
--- /dev/null
+++ b/core/res/res/drawable/switch_inner_holo_light.xml
@@ -0,0 +1,21 @@
+<?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_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_light" />
+    <item android:state_pressed="true"  android:drawable="@drawable/switch_thumb_pressed_holo_light" />
+    <item                               android:drawable="@drawable/switch_thumb_holo_light" />
+</selector>
diff --git a/core/res/res/drawable/switch_track_holo_dark.xml b/core/res/res/drawable/switch_track_holo_dark.xml
new file mode 100644
index 0000000..c9a940d
--- /dev/null
+++ b/core/res/res/drawable/switch_track_holo_dark.xml
@@ -0,0 +1,21 @@
+<?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_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_dark" />
+    <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_dark" />
+    <item                               android:drawable="@drawable/switch_bg_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/switch_track_holo_light.xml b/core/res/res/drawable/switch_track_holo_light.xml
new file mode 100644
index 0000000..98e53b5
--- /dev/null
+++ b/core/res/res/drawable/switch_track_holo_light.xml
@@ -0,0 +1,21 @@
+<?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_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_light" />
+    <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_light" />
+    <item                               android:drawable="@drawable/switch_bg_holo_light" />
+</selector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5d4fd4e..dfbcafc0a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -634,6 +634,10 @@
 
         <!-- Preference frame layout styles. -->
         <attr name="preferenceFrameLayoutStyle" format="reference" />
+
+        <!-- Default style for the Switch widget. -->
+        <attr name="switchStyle" format="reference" />
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -4512,4 +4516,23 @@
     <declare-styleable name="ActionBar_LayoutParams">
         <attr name="layout_gravity" />
     </declare-styleable>
+
+    <declare-styleable name="Switch">
+        <!-- Drawable to use as the "thumb" that switches back and forth. -->
+        <attr name="switchThumb" format="reference" />
+        <!-- Drawable to use as the "track" that the switch thumb slides within. -->
+        <attr name="switchTrack" format="reference" />
+        <!-- Text to use when the switch is in the checked/"on" state. -->
+        <attr name="textOn" />
+        <!-- Text to use when the switch is in the unchecked/"off" state. -->
+        <attr name="textOff" />
+        <!-- Amount of padding on either side of text within the switch thumb. -->
+        <attr name="thumbTextPadding" format="dimension" />
+        <!-- TextAppearance style for text displayed on the switch thumb. -->
+        <attr name="switchTextAppearance" format="reference" />
+        <!-- Minimum width for the switch component -->
+        <attr name="switchMinWidth" format="dimension" />
+        <!-- Minimum space between the switch and caption text -->
+        <attr name="switchPadding" format="dimension" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 60150a1..b3c3e0d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1177,6 +1177,9 @@
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
+    <style name="TextAppearance.Holo.Widget.Switch" parent="TextAppearance.Holo.Small">
+    </style>
+
     <style name="TextAppearance.Holo.WindowTitle">
         <item name="android:textColor">#fff</item>
         <item name="android:textSize">14sp</item>
@@ -1353,6 +1356,9 @@
         <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
     </style>
 
+    <style name="Widget.Holo.CompoundButton" parent="Widget.CompoundButton">
+    </style>
+
     <style name="Widget.Holo.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
     </style>
 
@@ -1610,6 +1616,17 @@
         <item name="android:progressBarPadding">32dip</item>
     </style>
 
+    <style name="Widget.Holo.CompoundButton.Switch">
+        <item name="android:switchTrack">@android:drawable/switch_track_holo_dark</item>
+        <item name="android:switchThumb">@android:drawable/switch_inner_holo_dark</item>
+        <item name="android:switchTextAppearance">@android:style/TextAppearance.Holo.Widget.Switch</item>
+        <item name="android:textOn">@android:string/capital_on</item>
+        <item name="android:textOff">@android:string/capital_off</item>
+        <item name="android:thumbTextPadding">12dip</item>
+        <item name="android:switchMinWidth">96dip</item>
+        <item name="android:switchPadding">16dip</item>
+    </style>
+
     <!-- Light widget styles -->
 
     <style name="Widget.Holo.Light">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 97df48a..e1040d9 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -719,6 +719,7 @@
         <item name="buttonStyleInset">@android:style/Widget.Holo.Button.Inset</item>
 
         <item name="buttonStyleToggle">@android:style/Widget.Holo.Button.Toggle</item>
+        <item name="switchStyle">@android:style/Widget.Holo.CompoundButton.Switch</item>
 
         <item name="groupButtonBackground">@android:drawable/group_button_background_holo_dark</item>
         <item name="selectableItemBackground">@android:drawable/item_background_holo_dark</item>