Merge change I5975651f into eclair

* changes:
  Don't feed the timezone to RenderScript time functions, let the library figure it out.
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index fbe3548..3716274 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -135,8 +135,10 @@
         public void onCreate(SQLiteDatabase db) {
             bootstrapDatabase(db);
             mSyncState.createDatabase(db);
-            ContentResolver.requestSync(null /* all accounts */,
+            if (!isTemporary()) {
+		ContentResolver.requestSync(null /* all accounts */,
                     mContentUri.getAuthority(), new Bundle());
+	    }
         }
 
         @Override
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 142dffb..a8d9f1d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1525,7 +1525,7 @@
         }
         nativeClearCursor(); // start next trackball movement from page edge
         if (bottom) {
-            return pinScrollTo(mScrollX, mContentHeight, true, 0);
+            return pinScrollTo(mScrollX, computeVerticalScrollRange(), true, 0);
         }
         // Page down.
         int h = getHeight();
@@ -2730,7 +2730,7 @@
     */
     @Deprecated
     public static synchronized PluginList getPluginList() {
-        return null;
+        return new PluginList();
     }
 
    /**
@@ -4297,7 +4297,7 @@
 
     private int computeMaxScrollY() {
         int maxContentH = computeVerticalScrollRange() + getTitleHeight();
-        return Math.max(maxContentH - getHeight(), getTitleHeight());
+        return Math.max(maxContentH - getViewHeightWithTitle(), getTitleHeight());
     }
 
     public void flingScroll(int vx, int vy) {
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
new file mode 100644
index 0000000..6bcecc3
--- /dev/null
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2009 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.internal.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.ImageView.ScaleType;
+import com.android.internal.R;
+
+/**
+ * A special widget containing two Sliders and a threshold for each.  Moving either slider beyond
+ * the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
+ * {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE} to be called.
+ *
+ */
+public class SlidingTab extends ViewGroup {
+    private static final String LOG_TAG = "SlidingTab";
+    private static final boolean DBG = false;
+    private static final int HORIZONTAL = 0; // as defined in attrs.xml
+    private static final int VERTICAL = 1;
+    private static final int MSG_ANIMATE = 100;
+
+    // TODO: Make these configurable
+    private static final float TARGET_ZONE = 2.0f / 3.0f;
+    private static final long VIBRATE_SHORT = 30;
+    private static final long VIBRATE_LONG = 40;
+
+    private OnTriggerListener mOnTriggerListener;
+    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
+    private boolean mTriggered = false;
+    private Vibrator mVibrator;
+    private float mDensity; // used to scale dimensions for bitmaps.
+
+    private final SlidingTabHandler mHandler = new SlidingTabHandler();
+
+    /**
+     * Either {@link #HORIZONTAL} or {@link #VERTICAL}.
+     */
+    private int mOrientation;
+
+    private Slider mLeftSlider;
+    private Slider mRightSlider;
+    private Slider mCurrentSlider;
+    private boolean mTracking;
+    private float mTargetZone;
+    private Slider mOtherSlider;
+    private boolean mAnimating;
+
+    /**
+     * Interface definition for a callback to be invoked when a tab is triggered
+     * by moving it beyond a target zone.
+     */
+    public interface OnTriggerListener {
+        /**
+         * The interface was triggered because the user let go of the handle without reaching the
+         * target zone.
+         */
+        public static final int NO_HANDLE = 0;
+
+        /**
+         * The interface was triggered because the user grabbed the left handle and moved it past
+         * the target zone.
+         */
+        public static final int LEFT_HANDLE = 1;
+
+        /**
+         * The interface was triggered because the user grabbed the right handle and moved it past
+         * the target zone.
+         */
+        public static final int RIGHT_HANDLE = 2;
+
+        /**
+         * Called when the user moves a handle beyond the target zone.
+         *
+         * @param v The view that was triggered.
+         * @param whichHandle  Which "dial handle" the user grabbed,
+         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
+         */
+        void onTrigger(View v, int whichHandle);
+
+        /**
+         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
+         * one of the handles.)
+         *
+         * @param v the view that was triggered
+         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #LEFT_HANDLE},
+         * or {@link #RIGHT_HANDLE}.
+         */
+        void onGrabbedStateChange(View v, int grabbedState);
+    }
+
+    /**
+     * Simple container class for all things pertinent to a slider.  
+     * A slider consists of 3 Views:
+     * 
+     * {@link #tab} is the tab shown on the screen in the default state.
+     * {@link #text} is the view revealed as the user slides the tab out.
+     * {@link #target} is the target the user must drag the slider past to trigger the slider.
+     *
+     */
+    private static class Slider {
+        /**
+         * Tab alignment - determines which side the tab should be drawn on
+         */
+        public static final int ALIGN_LEFT = 0;
+        public static final int ALIGN_RIGHT = 1;
+        public static final int ALIGN_TOP = 2;
+        public static final int ALIGN_BOTTOM = 3;
+
+        /**
+         * States for the view.
+         */
+        private static final int STATE_NORMAL = 0;
+        private static final int STATE_PRESSED = 1;
+        private static final int STATE_ACTIVE = 2;
+
+        private final ImageView tab;
+        private final TextView text;
+        private final ImageView target;
+
+        /**
+         * Constructor
+         * 
+         * @param parent the container view of this one
+         * @param tabId drawable for the tab
+         * @param barId drawable for the bar
+         * @param targetId drawable for the target
+         */
+        Slider(ViewGroup parent, int tabId, int barId, int targetId) {
+            // Create tab
+            tab = new ImageView(parent.getContext());
+            tab.setBackgroundResource(tabId);
+            tab.setScaleType(ScaleType.CENTER);
+            tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.WRAP_CONTENT));
+
+            // Create hint TextView
+            text = new TextView(parent.getContext());
+            text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.FILL_PARENT));
+            text.setBackgroundResource(barId);
+            text.setTextAppearance(parent.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            // hint.setSingleLine();  // Hmm.. this causes the text to disappear off-screen
+
+            // Create target
+            target = new ImageView(parent.getContext());
+            target.setImageResource(targetId);
+            target.setScaleType(ScaleType.CENTER);
+            target.setLayoutParams(
+                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+            target.setVisibility(View.INVISIBLE);
+
+            parent.addView(target); // this needs to be first - relies on painter's algorithm
+            parent.addView(tab);
+            parent.addView(text);
+        }
+
+        void setIcon(int iconId) {
+            tab.setImageResource(iconId);
+        }
+        
+        void setTabBackgroundResource(int tabId) {
+            tab.setBackgroundResource(tabId);
+        }
+        
+        void setBarBackgroundResource(int barId) {
+            text.setBackgroundResource(barId);
+        }
+        
+        void setHintText(int resId) {
+            // TODO: Text should be blank if widget is vertical
+            text.setText(resId); 
+        }
+
+        void hide() {
+            // TODO: Animate off the screen
+            text.setVisibility(View.INVISIBLE);
+            tab.setVisibility(View.INVISIBLE);
+            target.setVisibility(View.INVISIBLE);
+        }
+
+        void setState(int state) {
+            text.setPressed(state == STATE_PRESSED);
+            tab.setPressed(state == STATE_PRESSED);
+            if (state == STATE_ACTIVE) {
+                final int[] activeState = new int[] {com.android.internal.R.attr.state_active};
+                if (text.getBackground().isStateful()) {
+                    text.getBackground().setState(activeState);
+                }
+                if (tab.getBackground().isStateful()) {
+                    tab.getBackground().setState(activeState);
+                }
+                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabActive);
+            } else {
+                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            }
+        }
+
+        void showTarget() {
+            target.setVisibility(View.VISIBLE);
+        }
+
+        void reset() {
+            setState(STATE_NORMAL);
+            text.setVisibility(View.VISIBLE);
+            text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
+            tab.setVisibility(View.VISIBLE);
+            target.setVisibility(View.INVISIBLE);
+        }
+
+        void setTarget(int targetId) {
+            target.setImageResource(targetId);
+        }
+
+        /**
+         * Layout the given widgets within the parent.
+         *
+         * @param l the parent's left border
+         * @param t the parent's top border
+         * @param r the parent's right border
+         * @param b the parent's bottom border
+         * @param alignment which side to align the widget to
+         */
+        void layout(int l, int t, int r, int b, int alignment) {
+            final int handleWidth = tab.getBackground().getIntrinsicWidth();
+            final int handleHeight = tab.getBackground().getIntrinsicHeight();
+            final int targetWidth = target.getDrawable().getIntrinsicWidth();
+            final int targetHeight = target.getDrawable().getIntrinsicHeight();
+            final int parentWidth = r - l;
+            final int parentHeight = b - t;
+
+            final int leftTarget = (int) (TARGET_ZONE * parentWidth) - targetWidth + handleWidth / 2;
+            final int rightTarget = (int) ((1.0f - TARGET_ZONE) * parentWidth) - handleWidth / 2;
+            final int left = (parentWidth - handleWidth) / 2;
+            final int right = left + handleWidth;
+
+            if (alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT) {
+                // horizontal
+                final int targetTop = (parentHeight - targetHeight) / 2;
+                final int targetBottom = targetTop + targetHeight;
+                final int top = (parentHeight - handleHeight) / 2;
+                final int bottom = (parentHeight + handleHeight) / 2;
+                if (alignment == ALIGN_LEFT) {
+                    tab.layout(0, top, handleWidth, bottom);
+                    text.layout(0 - parentWidth, top, 0, bottom);
+                    text.setGravity(Gravity.RIGHT);
+                    target.layout(leftTarget, targetTop, leftTarget + targetWidth, targetBottom);
+                } else {
+                    tab.layout(parentWidth - handleWidth, top, parentWidth, bottom);
+                    text.layout(parentWidth, top, parentWidth + parentWidth, bottom);
+                    target.layout(rightTarget, targetTop, rightTarget + targetWidth, targetBottom);
+                    text.setGravity(Gravity.TOP);
+                }
+            } else {
+                // vertical
+                final int targetLeft = (parentWidth - targetWidth) / 2;
+                final int targetRight = (parentWidth + targetWidth) / 2;
+                final int top = (int) (TARGET_ZONE * parentHeight) + handleHeight / 2 - targetHeight;
+                final int bottom = (int) ((1.0f - TARGET_ZONE) * parentHeight) - handleHeight / 2;
+                if (alignment == ALIGN_TOP) {
+                    tab.layout(left, 0, right, handleHeight);
+                    text.layout(left, 0 - parentHeight, right, 0);
+                    target.layout(targetLeft, top, targetRight, top + targetHeight);
+                } else {
+                    tab.layout(left, parentHeight - handleHeight, right, parentHeight);
+                    text.layout(left, parentHeight, right, parentHeight + parentHeight);
+                    target.layout(targetLeft, bottom, targetRight, bottom + targetHeight);
+                }
+            }
+        }
+
+        public int getTabWidth() {
+            return tab.getDrawable().getIntrinsicWidth();
+        }
+
+        public int getTabHeight() {
+            return tab.getDrawable().getIntrinsicHeight();
+        }
+    }
+
+    public SlidingTab(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Constructor used when this widget is created from a layout file.
+     */
+    public SlidingTab(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTab);
+        mOrientation = a.getInt(R.styleable.SlidingTab_orientation, HORIZONTAL);
+        a.recycle();
+
+        Resources r = getResources();
+        mDensity = r.getDisplayMetrics().density;
+        if (DBG) log("- Density: " + mDensity);
+
+        mLeftSlider = new Slider(this, 
+                R.drawable.jog_tab_left_generic, 
+                R.drawable.jog_tab_bar_left_generic,
+                R.drawable.jog_tab_target_gray);
+        mRightSlider = new Slider(this, 
+                R.drawable.jog_tab_right_generic, 
+                R.drawable.jog_tab_bar_right_generic,
+                R.drawable.jog_tab_target_gray);
+
+        // setBackgroundColor(0x80808080);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
+
+        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
+            throw new RuntimeException(LOG_TAG + " cannot have UNSPECIFIED dimensions");
+        }
+
+        final int leftTabWidth = (int) (mDensity * mLeftSlider.getTabWidth() + 0.5f);
+        final int rightTabWidth = (int) (mDensity * mRightSlider.getTabWidth() + 0.5f);
+        final int leftTabHeight = (int) (mDensity * mLeftSlider.getTabHeight() + 0.5f);
+        final int rightTabHeight = (int) (mDensity * mRightSlider.getTabHeight() + 0.5f);
+        final int width;
+        final int height;
+        if (isHorizontal()) {
+            width = Math.max(widthSpecSize, leftTabWidth + rightTabWidth);
+            height = Math.max(leftTabHeight, rightTabHeight);
+        } else {
+            width = Math.max(leftTabWidth, rightTabHeight);
+            height = Math.max(heightSpecSize, leftTabHeight + rightTabHeight);
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        final int action = event.getAction();
+        final float x = event.getX();
+        final float y = event.getY();
+
+        final Rect frame = new Rect();
+
+        if (mAnimating) {
+            return false;
+        }
+
+        View leftHandle = mLeftSlider.tab;
+        leftHandle.getHitRect(frame);
+        boolean leftHit = frame.contains((int) x, (int) y);
+
+        View rightHandle = mRightSlider.tab;
+        rightHandle.getHitRect(frame);
+        boolean rightHit = frame.contains((int)x, (int) y);
+
+        if (!mTracking && !(leftHit || rightHit)) {
+            return false;
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                mTracking = true;
+                mTriggered = false;
+                vibrate(VIBRATE_SHORT);
+                if (leftHit) {
+                    mCurrentSlider = mLeftSlider;
+                    mOtherSlider = mRightSlider;
+                    mTargetZone = isHorizontal() ? TARGET_ZONE : 1.0f - TARGET_ZONE;
+                    setGrabbedState(OnTriggerListener.LEFT_HANDLE);
+                } else {
+                    mCurrentSlider = mRightSlider;
+                    mOtherSlider = mLeftSlider;
+                    mTargetZone = isHorizontal() ? 1.0f - TARGET_ZONE : TARGET_ZONE;
+                    setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
+                }
+                mCurrentSlider.setState(Slider.STATE_PRESSED);
+                mCurrentSlider.showTarget();
+                mOtherSlider.hide();
+                break;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mTracking) {
+            final int action = event.getAction();
+            final float x = event.getX();
+            final float y = event.getY();
+            final View handle = mCurrentSlider.tab;
+            switch (action) {
+                case MotionEvent.ACTION_MOVE:
+                    moveHandle(x, y);
+                    float position = isHorizontal() ? x : y;
+                    float target = mTargetZone * (isHorizontal() ? getWidth() : getHeight());
+                    boolean targetZoneReached;
+                    if (isHorizontal()) {
+                        targetZoneReached = mCurrentSlider == mLeftSlider ?
+                                position > target : position < target;
+                    } else {
+                        targetZoneReached = mCurrentSlider == mLeftSlider ?
+                                position < target : position > target;
+                    }
+                    if (!mTriggered && targetZoneReached) {
+                        mTriggered = true;
+                        mTracking = false;
+                        mCurrentSlider.setState(Slider.STATE_ACTIVE);
+                        dispatchTriggerEvent(mCurrentSlider == mLeftSlider ?
+                            OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
+
+                        // TODO: This is a place holder for the real animation. It just holds
+                        // the screen for 500ms.
+                        mAnimating = true;
+                        mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                resetView();
+                                mAnimating = false;
+                            }
+                        }, 500);
+                    }
+
+                    if (isHorizontal() && (y <= handle.getBottom() && y >= handle.getTop()) ||
+                            !isHorizontal() && (x >= handle.getLeft() && x <= handle.getRight()) ) {
+                        break;
+                    }
+                    // Intentionally fall through - we're outside tracking rectangle
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mTracking = false;
+                    mTriggered = false;
+                    resetView();
+                    setGrabbedState(OnTriggerListener.NO_HANDLE);
+                    break;
+            }
+        }
+
+        return mTracking || super.onTouchEvent(event);
+    }
+
+    private boolean isHorizontal() {
+        return mOrientation == HORIZONTAL;
+    }
+
+    private void resetView() {
+        mLeftSlider.reset();
+        mRightSlider.reset();
+        onLayout(true, getLeft(), getTop(), getLeft() + getWidth(), getTop() + getHeight());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        if (!changed) return;
+
+        // Center the widgets in the view
+        mLeftSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_LEFT : Slider.ALIGN_BOTTOM);
+        mRightSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_RIGHT : Slider.ALIGN_TOP);
+
+        invalidate(); // TODO: be more conservative about what we're invalidating
+    }
+
+    private void moveHandle(float x, float y) {
+        final View handle = mCurrentSlider.tab;
+        final View content = mCurrentSlider.text;
+        if (isHorizontal()) {
+            int deltaX = (int) x - handle.getLeft() - (handle.getWidth() / 2);
+            handle.offsetLeftAndRight(deltaX);
+            content.offsetLeftAndRight(deltaX);
+        } else {
+            int deltaY = (int) y - handle.getTop() - (handle.getHeight() / 2);
+            handle.offsetTopAndBottom(deltaY);
+            content.offsetTopAndBottom(deltaY);
+        }
+        invalidate(); // TODO: be more conservative about what we're invalidating
+    }
+
+    /**
+     * Sets the left handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param iconId the resource ID of the icon drawable
+     * @param targetId the resource of the target drawable
+     * @param barId the resource of the bar drawable (stateful)
+     * @param tabId the resource of the 
+     */
+    public void setLeftTabResources(int iconId, int targetId, int barId, int tabId) {
+        mLeftSlider.setIcon(iconId);
+        mLeftSlider.setTarget(targetId); 
+        mLeftSlider.setBarBackgroundResource(barId);
+        mLeftSlider.setTabBackgroundResource(tabId);
+    }
+
+    /**
+     * Sets the left handle hint text to a given resource string.
+     *
+     * @param resId
+     */
+    public void setLeftHintText(int resId) {
+        mLeftSlider.setHintText(resId);
+    }
+
+    /**
+     * Sets the right handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param iconId the resource ID of the icon drawable
+     * @param targetId the resource of the target drawable
+     * @param barId the resource of the bar drawable (stateful)
+     * @param tabId the resource of the 
+     */
+    public void setRightTabResources(int iconId, int targetId, int barId, int tabId) {
+        mRightSlider.setIcon(iconId);
+        mRightSlider.setTarget(targetId); 
+        mRightSlider.setBarBackgroundResource(barId);
+        mRightSlider.setTabBackgroundResource(tabId);
+    }
+
+    /**
+     * Sets the left handle hint text to a given resource string.
+     *
+     * @param resId
+     */
+    public void setRightHintText(int resId) {
+        mRightSlider.setHintText(resId);
+    }
+
+    /**
+     * Triggers haptic feedback.
+     */
+    private synchronized void vibrate(long duration) {
+        if (mVibrator == null) {
+            mVibrator = (android.os.Vibrator)
+                    getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        }
+        mVibrator.vibrate(duration);
+    }
+
+    /**
+     * Registers a callback to be invoked when the user triggers an event.
+     *
+     * @param listener the OnDialTriggerListener to attach to this view
+     */
+    public void setOnTriggerListener(OnTriggerListener listener) {
+        mOnTriggerListener = listener;
+    }
+
+    /**
+     * Dispatches a trigger event to listener. Ignored if a listener is not set.
+     * @param whichHandle the handle that triggered the event.
+     */
+    private void dispatchTriggerEvent(int whichHandle) {
+        vibrate(VIBRATE_LONG);
+        if (mOnTriggerListener != null) {
+            mOnTriggerListener.onTrigger(this, whichHandle);
+        }
+    }
+
+    /**
+     * Sets the current grabbed state, and dispatches a grabbed state change
+     * event to our listener.
+     */
+    private void setGrabbedState(int newState) {
+        if (newState != mGrabbedState) {
+            mGrabbedState = newState;
+            if (mOnTriggerListener != null) {
+                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
+            }
+        }
+    }
+
+    private class SlidingTabHandler extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+            }
+        }
+    }
+
+    private void doAnimation() {
+        if (mAnimating) {
+
+        }
+    }
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, msg);
+    }
+}
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png
new file mode 100644
index 0000000..92db44f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png
new file mode 100644
index 0000000..0bed1a0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png
new file mode 100644
index 0000000..81fbe5a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png
new file mode 100644
index 0000000..d9c33fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png
new file mode 100644
index 0000000..1cf7f1c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png
new file mode 100644
index 0000000..c7b367e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_bar_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png
new file mode 100644
index 0000000..3499208
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png
new file mode 100644
index 0000000..91eaec8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png
new file mode 100644
index 0000000..8818b9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png
new file mode 100644
index 0000000..e5bc5f6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-hdpi/jog_tab_left_normal.png
new file mode 100644
index 0000000..5326c7c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png
new file mode 100644
index 0000000..7b906df
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png
new file mode 100644
index 0000000..ea8c315
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png
new file mode 100644
index 0000000..aa0ceb9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png
new file mode 100644
index 0000000..d772fb6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png
new file mode 100644
index 0000000..3cfeb67
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-hdpi/jog_tab_right_normal.png
new file mode 100644
index 0000000..da7726b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png
new file mode 100644
index 0000000..450a325
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_gray.png b/core/res/res/drawable-hdpi/jog_tab_target_gray.png
new file mode 100644
index 0000000..e7ef129
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_gray.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_green.png b/core/res/res/drawable-hdpi/jog_tab_target_green.png
new file mode 100644
index 0000000..17f6b10
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_red.png b/core/res/res/drawable-hdpi/jog_tab_target_red.png
new file mode 100644
index 0000000..8db20bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/jog_tab_target_yellow.png b/core/res/res/drawable-hdpi/jog_tab_target_yellow.png
new file mode 100644
index 0000000..15045b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/jog_tab_target_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png b/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png
new file mode 100644
index 0000000..f1dac62
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/btn_lock_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png
new file mode 100755
index 0000000..d73db48
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_off.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png
new file mode 100755
index 0000000..90da6e3
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_sound_on.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png b/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png
new file mode 100755
index 0000000..a9af1af
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/ic_jog_dial_unlock.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png
new file mode 100644
index 0000000..c0f7706
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_gray.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png
new file mode 100644
index 0000000..0f2ce13
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png
new file mode 100644
index 0000000..a34eb7d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_red.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png
new file mode 100644
index 0000000..e143356
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_confirm_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png
new file mode 100644
index 0000000..b5837f7
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png b/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png
new file mode 100644
index 0000000..79ad83d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_bar_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png
new file mode 100644
index 0000000..9c63b22
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png
new file mode 100644
index 0000000..4f9877c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png
new file mode 100644
index 0000000..bdce97d
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png
new file mode 100644
index 0000000..327fc2c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png
new file mode 100644
index 0000000..e69d91c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_normal.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png
new file mode 100644
index 0000000..b6153d8
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_left_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png
new file mode 100644
index 0000000..6e3e00b
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png
new file mode 100644
index 0000000..dae9efc
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png
new file mode 100644
index 0000000..9de3158
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png
new file mode 100644
index 0000000..8c9f180
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_confirm_yellow.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png
new file mode 100644
index 0000000..0c4faf2
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_normal.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png
new file mode 100644
index 0000000..4ec7b56
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_right_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png b/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png
new file mode 100644
index 0000000..4150007
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_gray.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_green.png b/core/res/res/drawable-land-hdpi/jog_tab_target_green.png
new file mode 100644
index 0000000..ef18b6c
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_green.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_red.png b/core/res/res/drawable-land-hdpi/jog_tab_target_red.png
new file mode 100644
index 0000000..5dfaa5f
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_red.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png b/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png
new file mode 100644
index 0000000..d0509fa
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/jog_tab_target_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_tab_bar_left_generic.xml b/core/res/res/drawable/jog_tab_bar_left_generic.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_left_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_left_unlock.xml b/core/res/res/drawable/jog_tab_bar_left_unlock.xml
new file mode 100644
index 0000000..b1d7c31
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_left_unlock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_generic.xml b/core/res/res/drawable/jog_tab_bar_right_generic.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_sound_off.xml b/core/res/res/drawable/jog_tab_bar_right_sound_off.xml
new file mode 100644
index 0000000..de1a42f
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_sound_off.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_bar_right_sound_on.xml b/core/res/res/drawable/jog_tab_bar_right_sound_on.xml
new file mode 100644
index 0000000..febe32a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_bar_right_sound_on.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_bar_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_bar_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_bar_confirm_yellow" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_left_generic.xml b/core/res/res/drawable/jog_tab_left_generic.xml
new file mode 100644
index 0000000..ed6d98b
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_left_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_left_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_left_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_left_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_left_unlock.xml b/core/res/res/drawable/jog_tab_left_unlock.xml
new file mode 100644
index 0000000..18ec7fa
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_left_unlock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_left_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_left_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_left_confirm_green" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_generic.xml b/core/res/res/drawable/jog_tab_right_generic.xml
new file mode 100644
index 0000000..e173f2a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_generic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_sound_off.xml b/core/res/res/drawable/jog_tab_right_sound_off.xml
new file mode 100644
index 0000000..e173f2a
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_sound_off.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_gray" />
+        
+</selector>
diff --git a/core/res/res/drawable/jog_tab_right_sound_on.xml b/core/res/res/drawable/jog_tab_right_sound_on.xml
new file mode 100644
index 0000000..61f677c
--- /dev/null
+++ b/core/res/res/drawable/jog_tab_right_sound_on.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- StateListDrawable used for buttons in the in-call onscreen touch UI. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/jog_tab_right_pressed" />
+
+    <item android:state_enabled="true"
+        android:drawable="@drawable/jog_tab_right_normal" />
+
+    <item android:state_active="true"
+        android:drawable="@drawable/jog_tab_right_confirm_yellow" />
+        
+</selector>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
new file mode 100644
index 0000000..84b5751
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.  It is the same for landscape
+  and portrait.-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:id="@+id/root">
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:background="#70000000"
+        android:gravity="center_horizontal">
+    
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="20dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+    
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/carrier"
+            android:layout_marginTop="25dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="55sp"
+            />
+    
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/time"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+    
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_marginTop="10dip"
+            android:layout_below="@id/date"
+            android:background="@android:drawable/divider_horizontal_dark"
+            />
+    
+        <TextView
+            android:id="@+id/status1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/divider"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+    
+        <TextView
+            android:id="@+id/status2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status1"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+    
+        <TextView
+            android:id="@+id/screenLocked"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status2"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:gravity="center"
+            android:layout_marginTop="12dip"
+            />
+    
+        <com.android.internal.widget.SlidingTab
+            android:id="@+id/tab_selector"
+            android:orientation="horizontal"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_marginBottom="50dip" 
+            />
+    
+        <!-- emergency call button shown when sim is missing or PUKd -->
+        <Button
+            android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/screenLocked"
+            android:layout_marginTop="24dip"
+            android:drawableLeft="@drawable/ic_emergency"
+            android:drawablePadding="8dip"
+           />
+    
+    </RelativeLayout>
+
+</FrameLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
new file mode 100644
index 0000000..6aed301
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="horizontal"
+    android:background="#70000000"
+    android:id="@+id/root">
+     
+    <!-- left side -->
+    <RelativeLayout
+            android:layout_width="0dip"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_horizontal">
+
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="20dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/carrier"
+            android:layout_marginTop="25dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="55sp"
+            />
+
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/time"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_marginTop="10dip"
+            android:layout_below="@id/date"
+            android:background="@android:drawable/divider_horizontal_dark"
+            />
+
+        <TextView
+            android:id="@+id/status1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/divider"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+
+        <TextView
+            android:id="@+id/status2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status1"
+            android:layout_marginTop="6dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:drawablePadding="4dip"
+            />
+
+        <TextView
+            android:id="@+id/screenLocked"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status2"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:gravity="center"
+            android:layout_marginTop="12dip"
+            />
+
+        <!-- emergency call button shown when sim is missing or PUKd -->
+        <Button
+            android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/screenLocked"
+            android:layout_marginTop="24dip"
+            android:drawableLeft="@drawable/ic_emergency"
+            android:drawablePadding="8dip"
+           />
+    </RelativeLayout>
+
+    <!-- right side -->
+    <com.android.internal.widget.SlidingTab
+        android:id="@+id/tab_selector"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_marginBottom="50dip"
+        />
+
+</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 81da739..50382b3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3559,4 +3559,14 @@
         <attr name="detailSocialSummary" format="boolean" />
     </declare-styleable>
 
+    <!-- =============================== -->
+    <!-- TabSelector class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <declare-styleable name="SlidingTab">
+        <!-- Use "horizontal" for a row, "vertical" for a column.  The default is horizontal. -->
+        <attr name="orientation" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 5d3069b..3c0f0a4 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -84,6 +84,10 @@
     <color name="search_url_text_selected">@android:color/black</color>
     <color name="search_url_text_pressed">@android:color/black</color>
     <color name="search_widget_corpus_item_background">@android:color/lighter_gray</color>
+    
+    <!-- SlidingTab -->
+    <color name="sliding_tab_text_color_active">@android:color/black</color>
+    <color name="sliding_tab_text_color_shadow">@android:color/black</color>
 
 </resources>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aaa1d8b..822a59a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -207,4 +207,11 @@
 
     <!-- Enables swipe versus poly-finger touch disambiguation in the KeyboardView -->
     <bool name="config_swipeDisambiguation">true</bool>
+
+    <!-- Enables special filtering code in the framework for raw touch events
+         from the touch driver.  This code exists for one particular device,
+         and should not be enabled for any others.  Hopefully in the future
+         it will be removed when the lower-level touch driver generates better
+         data. -->
+    <bool name="config_filterTouchEvents">false</bool>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index de30fe7..d1ae571 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1434,6 +1434,10 @@
 
     <!-- Displayed in a progress dialog while a username and password are being checked. -->
     <string name="lockscreen_glogin_checking_password">Checking...</string>
+    <!-- Displayed on lock screen's left tab - unlock -->
+    <string name="lockscreen_unlock_label">Unlock</string>
+    <!-- Displayed on lock screen's right tab - mute/unmute -->
+    <string name="lockscreen_mute_unmute_label">Sound</string>
 
     <!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
     <string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6e38138..a629bb2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -676,6 +676,25 @@
     <style name="TextAppearance.Widget.TextView.SpinnerItem">
         <item name="android:textColor">@android:color/primary_text_light_disable_only</item>
     </style>
+    
+    <!-- @hide -->
+    <style name="TextAppearance.SlidingTabNormal" 
+        parent="@android:attr/textAppearanceMedium">
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
+        <item name="android:textSize">28sp</item>
+        <item name="android:shadowColor">@android:color/sliding_tab_text_color_shadow</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">1.0</item>
+        <item name="android:shadowRadius">5.0</item>
+    </style>
+
+    <!-- @hide -->
+    <style name="TextAppearance.SlidingTabActive" 
+        parent="@android:attr/textAppearanceMedium">
+        <item name="android:textColor">@android:color/sliding_tab_text_color_active</item>
+        <item name="android:textSize">28sp</item>
+    </style>
+    
 
     <!-- @hide -->	
      <style name="TextAppearance.SearchResult">	
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index f089de1..c2b1b96 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -111,8 +111,17 @@
             try {
                 int newState = Integer.parseInt(event.get("SWITCH_STATE"));
                 if (newState != mDockState) {
+                    int oldState = mDockState;
                     mDockState = newState;
                     if (mSystemReady) {
+                        // Don't force screen on when undocking from the desk dock.
+                        // The change in power state will do this anyway.
+                        // FIXME - we should be configurable.
+                        if (oldState != Intent.EXTRA_DOCK_STATE_DESK ||
+                                newState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                            mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
+                                    false, true);
+                        }
                         update();
                     }
                 }
@@ -166,7 +175,6 @@
                     return;
                 }
                 // Pack up the values and broadcast them to everyone
-                mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                 
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index d68ccfa..a885df8 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -56,7 +56,7 @@
      * Turn on some hacks we have to improve the touch interaction with a
      * certain device whose screen currently is not all that good.
      */
-    static final boolean BAD_TOUCH_HACK = true;
+    static boolean BAD_TOUCH_HACK = false;
     
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
 
@@ -282,6 +282,9 @@
             lt = new LatencyTimer(100, 1000);
         }
 
+        BAD_TOUCH_HACK = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_filterTouchEvents);
+        
         mHapticFeedbackCallback = hapticFeedbackCallback;
         
         readExcludedDevices();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index c16b04d..aee45bff 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SMSDispatcher;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.telephony.cdma.SmsMessage;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.cdma.sms.UserData;
@@ -366,8 +367,19 @@
          */
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -389,6 +401,12 @@
             UserData uData = new UserData();
             uData.payloadStr = parts.get(i);
             uData.userDataHeader = smsHeader;
+            if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
+                uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+            } else { // assume UTF-16
+                uData.msgEncoding = UserData.ENCODING_UNICODE_16;
+            }
+            uData.msgEncodingSet = true;
 
             /* By setting the statusReportRequested bit only for the
              * last message fragment, this will result in only one
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 3051e2f..bb3f2a7 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -67,6 +67,15 @@
     CdmaCellLocation cellLoc;
     CdmaCellLocation newCellLoc;
 
+     /** if time between NTIZ updates is less than mNitzUpdateSpacing the update may be ignored. */
+    private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
+    private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
+            NITZ_UPDATE_SPACING_DEFAULT);
+
+    /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */
+    private static final int NITZ_UPDATE_DIFF_DEFAULT = 2000;
+    private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff",
+            NITZ_UPDATE_DIFF_DEFAULT);
     /**
      *  Values correspond to ServiceStateTracker.DATA_ACCESS_ definitions.
      */
@@ -1420,45 +1429,62 @@
             try {
                 mWakeLock.acquire();
 
+                /**
+                 * Correct the NITZ time by how long its taken to get here.
+                 */
+                long millisSinceNitzReceived
+                        = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+                if (millisSinceNitzReceived < 0) {
+                    // Sanity check: something is wrong
+                    Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+                                        + "backwards since NITZ time was received, "
+                                        + nitz);
+                    return;
+                }
+
+                if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+                    // If the time is this far off, something is wrong > 24 days!
+                    Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+                                    + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+                                    + " days");
+                    return;
+                }
+
+                // Note: with range checks above, cast to int is safe
+                c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
                 if (getAutoTime()) {
-                    long millisSinceNitzReceived
-                            = SystemClock.elapsedRealtime() - nitzReceiveTime;
+                    /**
+                     * Update system time automatically
+                     */
+                    long gained = c.getTimeInMillis() - System.currentTimeMillis();
+                    long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime;
 
-                    if (millisSinceNitzReceived < 0) {
-                        // Sanity check: something is wrong
-                        Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
-                                            + "backwards since NITZ time was received, "
-                                            + nitz);
+                    if ((timeSinceLastUpdate > mNitzUpdateSpacing)
+                            || (Math.abs(gained) > mNitzUpdateDiff)) {
+                        Log.i(LOG_TAG, "NITZ: Auto updating time of day to " + c.getTime()
+                                + " NITZ receive delay=" + millisSinceNitzReceived
+                                + "ms gained=" + gained + "ms from " + nitz);
+
+                        setAndBroadcastNetworkSetTime(c.getTimeInMillis());
+                    } else {
+                        Log.i(LOG_TAG, "NITZ: ignore, a previous update was "
+                                + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms");
                         return;
                     }
-
-                    if (millisSinceNitzReceived > Integer.MAX_VALUE) {
-                        // If the time is this far off, something is wrong > 24 days!
-                        Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
-                                        + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
-                                        + " days");
-                        return;
-                    }
-
-                    // Note: with range checks above, cast to int is safe
-                    c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
-
-                    Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
-                            + " NITZ receive delay(ms): " + millisSinceNitzReceived
-                        + " gained(ms): "
-                        + (c.getTimeInMillis() - System.currentTimeMillis())
-                            + " from " + nitz);
-
-                    setAndBroadcastNetworkSetTime(c.getTimeInMillis());
-                    Log.i(LOG_TAG, "NITZ: after Setting time of day");
                 }
+
+                /**
+                 * Update properties and save the time we did the update
+                 */
+                Log.i(LOG_TAG, "NITZ: update nitz time property");
                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
-                saveNitzTime(c.getTimeInMillis());
-                if (Config.LOGV) {
-                    long end = SystemClock.elapsedRealtime();
-                    Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
-                }
+                mSavedTime = c.getTimeInMillis();
+                mSavedAtTime = SystemClock.elapsedRealtime();
             } finally {
+                long end = SystemClock.elapsedRealtime();
+                Log.i(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
                 mWakeLock.release();
             }
         } catch (RuntimeException ex) {
@@ -1479,11 +1505,6 @@
         mSavedTimeZone = zoneId;
     }
 
-    private void saveNitzTime(long time) {
-        mSavedTime = time;
-        mSavedAtTime = SystemClock.elapsedRealtime();
-    }
-
     /**
      * Set the timezone and send out a sticky broadcast so the system can
      * determine if the timezone was set by the carrier.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 0ca3148..6ae316d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.telephony.gsm.SmsMessage;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.SMSDispatcher;
@@ -165,8 +166,19 @@
             ArrayList<PendingIntent> deliveryIntents) {
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -192,7 +204,8 @@
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
+                    encoding);
 
             sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
         }
@@ -242,8 +255,19 @@
         }
 
         int refNumber = getNextConcatenatedRef() & 0x00FF;
+        int msgCount = parts.size();
+        int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
 
-        for (int i = 0, msgCount = parts.size(); i < msgCount; i++) {
+        for (int i = 0; i < msgCount; i++) {
+            TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
+            if (encoding != details.codeUnitSize
+                    && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
+                            || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
+                encoding = details.codeUnitSize;
+            }
+        }
+
+        for (int i = 0; i < msgCount; i++) {
             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
             concatRef.refNumber = refNumber;
             concatRef.seqNumber = i + 1;  // 1-based sequence
@@ -263,7 +287,8 @@
             }
 
             SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
-                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader));
+                    parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
+                    encoding);
 
             HashMap<String, Object> map = new HashMap<String, Object>();
             map.put("smsc", pdus.encodedScAddress);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 569cf25..ebd60a9 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -225,6 +225,25 @@
     public static SubmitPdu getSubmitPdu(String scAddress,
             String destinationAddress, String message,
             boolean statusReportRequested, byte[] header) {
+        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
+                ENCODING_UNKNOWN);
+    }
+
+
+    /**
+     * Get an SMS-SUBMIT PDU for a destination address and a message using the
+     * specified encoding.
+     *
+     * @param scAddress Service Centre address.  Null means use default.
+     * @param encoding Encoding defined by constants in android.telephony.SmsMessage.ENCODING_*
+     * @return a <code>SubmitPdu</code> containing the encoded SC
+     *         address, if applicable, and the encoded message.
+     *         Returns null on encode error.
+     * @hide
+     */
+    public static SubmitPdu getSubmitPdu(String scAddress,
+            String destinationAddress, String message,
+            boolean statusReportRequested, byte[] header, int encoding) {
 
         // Perform null parameter checks.
         if (message == null || destinationAddress == null) {
@@ -237,18 +256,43 @@
         ByteArrayOutputStream bo = getSubmitPduHead(
                 scAddress, destinationAddress, mtiByte,
                 statusReportRequested, ret);
-
-        try {
+        // User Data (and length)
+        byte[] userData;
+        if (encoding == ENCODING_UNKNOWN) {
             // First, try encoding it with the GSM alphabet
+            encoding = ENCODING_7BIT;
+        }
+        try {
+            if (encoding == ENCODING_7BIT) {
+                userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
+            } else { //assume UCS-2
+                try {
+                    userData = encodeUCS2(message, header);
+                } catch(UnsupportedEncodingException uex) {
+                    Log.e(LOG_TAG,
+                            "Implausible UnsupportedEncodingException ",
+                            uex);
+                    return null;
+                }
+            }
+        } catch (EncodeException ex) {
+            // Encoding to the 7-bit alphabet failed. Let's see if we can
+            // send it as a UCS-2 encoded message
+            try {
+                userData = encodeUCS2(message, header);
+            } catch(UnsupportedEncodingException uex) {
+                Log.e(LOG_TAG,
+                        "Implausible UnsupportedEncodingException ",
+                        uex);
+                return null;
+            }
+        }
 
-            // User Data (and length)
-            byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
-
+        if (encoding == ENCODING_7BIT) {
             if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
                 // Message too long
                 return null;
             }
-
             // TP-Data-Coding-Scheme
             // Default encoding, uncompressed
             // To test writing messages to the SIM card, change this value 0x00
@@ -258,58 +302,51 @@
             // the receiver's SIM card. You can then send messages to yourself
             // (on a phone with this change) and they'll end up on the SIM card.
             bo.write(0x00);
-
-            // (no TP-Validity-Period)
-
-            bo.write(userData, 0, userData.length);
-        } catch (EncodeException ex) {
-            byte[] userData, textPart;
-            // Encoding to the 7-bit alphabet failed. Let's see if we can
-            // send it as a UCS-2 encoded message
-
-            try {
-                textPart = message.getBytes("utf-16be");
-            } catch (UnsupportedEncodingException uex) {
-                Log.e(LOG_TAG,
-                      "Implausible UnsupportedEncodingException ",
-                      uex);
-                return null;
-            }
-
-            if (header != null) {
-                // Need 1 byte for UDHL
-                userData = new byte[header.length + textPart.length + 1];
-
-                userData[0] = (byte)header.length;
-                System.arraycopy(header, 0, userData, 1, header.length);
-                System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
-            }
-            else {
-                userData = textPart;
-            }
-
-            if (userData.length > MAX_USER_DATA_BYTES) {
+        } else { //assume UCS-2
+            if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
                 // Message too long
                 return null;
             }
-
             // TP-Data-Coding-Scheme
             // Class 3, UCS-2 encoding, uncompressed
             bo.write(0x0b);
-
-            // (no TP-Validity-Period)
-
-            // TP-UDL
-            bo.write(userData.length);
-
-            bo.write(userData, 0, userData.length);
         }
 
+        // (no TP-Validity-Period)
+        bo.write(userData, 0, userData.length);
         ret.encodedMessage = bo.toByteArray();
         return ret;
     }
 
     /**
+     * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary
+     *
+     * @return
+     * @throws UnsupportedEncodingException
+     */
+    private static byte[] encodeUCS2(String message, byte[] header)
+        throws UnsupportedEncodingException {
+        byte[] userData, textPart;
+        textPart = message.getBytes("utf-16be");
+
+        if (header != null) {
+            // Need 1 byte for UDHL
+            userData = new byte[header.length + textPart.length + 1];
+
+            userData[0] = (byte)header.length;
+            System.arraycopy(header, 0, userData, 1, header.length);
+            System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
+        }
+        else {
+            userData = textPart;
+        }
+        byte[] ret = new byte[userData.length+1];
+        ret[0] = (byte) (userData.length & 0xff );
+        System.arraycopy(userData, 0, ret, 1, userData.length);
+        return ret;
+    }
+
+    /**
      * Get an SMS-SUBMIT PDU for a destination address and a message
      *
      * @param scAddress Service Centre address.  Null means use default.