Merge "Hiding the AsyncTaskLoader.waitForLoader method" into honeycomb
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0670c4e..2f96782 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1629,6 +1629,11 @@
     /* package */ synchronized void setPrivateBrowsingEnabled(boolean flag) {
         if (mPrivateBrowsingEnabled != flag) {
             mPrivateBrowsingEnabled = flag;
+
+            // AutoFill is dependant on private browsing being enabled so
+            // reset it to take account of the new value of mPrivateBrowsingEnabled.
+            setAutoFillEnabled(mAutoFillEnabled);
+
             postSync();
         }
     }
@@ -1644,8 +1649,10 @@
      * @hide
      */
     public synchronized void setAutoFillEnabled(boolean enabled) {
-        if (mAutoFillEnabled != enabled) {
-            mAutoFillEnabled = enabled;
+        // AutoFill is always disabled in private browsing mode.
+        boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled;
+        if (mAutoFillEnabled != autoFillEnabled) {
+            mAutoFillEnabled = autoFillEnabled;
             postSync();
         }
     }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eddfffe..78d4cd2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1037,7 +1037,7 @@
         String host = proxyProperties.getHost();
         int port = proxyProperties.getPort();
         if (port != 0)
-            host += ": " + port;
+            host += ":" + port;
 
         // TODO: Handle exclusion list
         // The plan is to make an AndroidProxyResolver, and handle the blacklist
@@ -6723,43 +6723,60 @@
         }
     }
 
-    /*
-     * Return true if the view (Plugin) is fully visible and maximized inside
-     * the WebView.
+    /**
+     * Returns plugin bounds if x/y in content coordinates corresponds to a
+     * plugin. Otherwise a NULL rectangle is returned.
      */
-    boolean isPluginFitOnScreen(ViewManager.ChildView view) {
+    Rect getPluginBounds(int x, int y) {
+        if (nativePointInNavCache(x, y, mNavSlop) && nativeCacheHitIsPlugin()) {
+            return nativeCacheHitNodeBounds();
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     * Return true if the rect (e.g. plugin) is fully visible and maximized
+     * inside the WebView.
+     */
+    boolean isRectFitOnScreen(Rect rect) {
+        final int rectWidth = rect.width();
+        final int rectHeight = rect.height();
         final int viewWidth = getViewWidth();
         final int viewHeight = getViewHeightWithTitle();
-        float scale = Math.min((float) viewWidth / view.width, (float) viewHeight / view.height);
+        float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight / rectHeight);
         scale = mZoomManager.computeScaleWithLimits(scale);
         return !mZoomManager.willScaleTriggerZoom(scale)
-                && contentToViewX(view.x) >= mScrollX
-                && contentToViewX(view.x + view.width) <= mScrollX + viewWidth
-                && contentToViewY(view.y) >= mScrollY
-                && contentToViewY(view.y + view.height) <= mScrollY + viewHeight;
+                && contentToViewX(rect.left) >= mScrollX
+                && contentToViewX(rect.right) <= mScrollX + viewWidth
+                && contentToViewY(rect.top) >= mScrollY
+                && contentToViewY(rect.bottom) <= mScrollY + viewHeight;
     }
 
     /*
      * Maximize and center the rectangle, specified in the document coordinate
      * space, inside the WebView. If the zoom doesn't need to be changed, do an
      * animated scroll to center it. If the zoom needs to be changed, find the
-     * zoom center and do a smooth zoom transition.
+     * zoom center and do a smooth zoom transition. The rect is in document
+     * coordinates
      */
-    void centerFitRect(int docX, int docY, int docWidth, int docHeight) {
-        int viewWidth = getViewWidth();
-        int viewHeight = getViewHeightWithTitle();
-        float scale = Math.min((float) viewWidth / docWidth, (float) viewHeight
-                / docHeight);
+    void centerFitRect(Rect rect) {
+        final int rectWidth = rect.width();
+        final int rectHeight = rect.height();
+        final int viewWidth = getViewWidth();
+        final int viewHeight = getViewHeightWithTitle();
+        float scale = Math.min((float) viewWidth / rectWidth, (float) viewHeight
+                / rectHeight);
         scale = mZoomManager.computeScaleWithLimits(scale);
         if (!mZoomManager.willScaleTriggerZoom(scale)) {
-            pinScrollTo(contentToViewX(docX + docWidth / 2) - viewWidth / 2,
-                    contentToViewY(docY + docHeight / 2) - viewHeight / 2,
+            pinScrollTo(contentToViewX(rect.left + rectWidth / 2) - viewWidth / 2,
+                    contentToViewY(rect.top + rectHeight / 2) - viewHeight / 2,
                     true, 0);
         } else {
             float actualScale = mZoomManager.getScale();
-            float oldScreenX = docX * actualScale - mScrollX;
-            float rectViewX = docX * scale;
-            float rectViewWidth = docWidth * scale;
+            float oldScreenX = rect.left * actualScale - mScrollX;
+            float rectViewX = rect.left * scale;
+            float rectViewWidth = rectWidth * scale;
             float newMaxWidth = mContentWidth * scale;
             float newScreenX = (viewWidth - rectViewWidth) / 2;
             // pin the newX to the WebView
@@ -6770,10 +6787,10 @@
             }
             float zoomCenterX = (oldScreenX * scale - newScreenX * actualScale)
                     / (scale - actualScale);
-            float oldScreenY = docY * actualScale + getTitleHeight()
+            float oldScreenY = rect.top * actualScale + getTitleHeight()
                     - mScrollY;
-            float rectViewY = docY * scale + getTitleHeight();
-            float rectViewHeight = docHeight * scale;
+            float rectViewY = rect.top * scale + getTitleHeight();
+            float rectViewHeight = rectHeight * scale;
             float newMaxHeight = mContentHeight * scale + getTitleHeight();
             float newScreenY = (viewHeight - rectViewHeight) / 2;
             // pin the newY to the WebView
@@ -7506,8 +7523,7 @@
                     break;
 
                 case CENTER_FIT_RECT:
-                    Rect r = (Rect)msg.obj;
-                    centerFitRect(r.left, r.top, r.width(), r.height());
+                    centerFitRect((Rect)msg.obj);
                     break;
 
                 case SET_SCROLLBAR_MODES:
@@ -8150,6 +8166,7 @@
     }
 
     private native int nativeCacheHitFramePointer();
+    private native boolean  nativeCacheHitIsPlugin();
     private native Rect nativeCacheHitNodeBounds();
     private native int nativeCacheHitNodePointer();
     /* package */ native void nativeClearCursor();
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index b4a33de..88a54ea 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.Canvas;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.Log;
@@ -551,12 +552,12 @@
          * If the double tap was on a plugin then either zoom to maximize the
          * plugin on the screen or scale to overview mode.
          */
-        ViewManager.ChildView plugin = mWebView.mViewManager.hitTest(mAnchorX, mAnchorY);
-        if (plugin != null) {
-            if (mWebView.isPluginFitOnScreen(plugin)) {
+        Rect pluginBounds = mWebView.getPluginBounds(mAnchorX, mAnchorY);
+        if (pluginBounds != null) {
+            if (mWebView.isRectFitOnScreen(pluginBounds)) {
                 zoomToOverview();
             } else {
-                mWebView.centerFitRect(plugin.x, plugin.y, plugin.width, plugin.height);
+                mWebView.centerFitRect(pluginBounds);
             }
             return;
         }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7631df4..d8f5972 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2642,6 +2642,7 @@
                         setPressed(true);
                         layoutChildren();
                         positionSelector(mMotionPosition, child);
+                        refreshDrawableState();
 
                         final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
                         final boolean longClickable = isLongClickable();
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 4d63cf4..2c53005 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -46,8 +46,8 @@
  * displayed. Also the minimal and maximal date from which dates to be selected
  * can be customized.
  * <p>
- * See the <a href="{@docRoot}
- * resources/tutorials/views/hello-datepicker.html">Date Picker tutorial</a>.
+ * See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date
+ * Picker tutorial</a>.
  * </p>
  * <p>
  * For a dialog using this view, see {@link android.app.DatePickerDialog}.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index de886d8..1895d79 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7931,9 +7931,6 @@
             max = Math.max(0, Math.max(selStart, selEnd));
         }
 
-        ClipboardManager clipboard = (ClipboardManager)getContext()
-                .getSystemService(Context.CLIPBOARD_SERVICE);
-
         switch (id) {
             case ID_COPY_URL:
                 URLSpan[] urls = ((Spanned) mText).getSpans(min, max, URLSpan.class);
@@ -8402,8 +8399,12 @@
          */
         public void updatePosition(HandleView handle, int x, int y);
 
+        public void updateOffset(HandleView handle, int offset);
+
         public void updatePosition();
 
+        public int getCurrentOffset(HandleView handle);
+
         /**
          * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
          * a chance to become active and/or visible.
@@ -8420,7 +8421,7 @@
     }
 
     private class PastePopupMenu implements OnClickListener {
-        private PopupWindow mContainer;
+        private final PopupWindow mContainer;
         private int mPositionX;
         private int mPositionY;
         private View mPasteView, mNoPasteView;
@@ -8519,12 +8520,11 @@
     }
 
     private class HandleView extends View {
-        private boolean mPositionOnTop = false;
         private Drawable mDrawable;
-        private PopupWindow mContainer;
+        private final PopupWindow mContainer;
         private int mPositionX;
         private int mPositionY;
-        private CursorController mController;
+        private final CursorController mController;
         private boolean mIsDragging;
         private float mTouchToWindowOffsetX;
         private float mTouchToWindowOffsetY;
@@ -8541,6 +8541,46 @@
         private PastePopupMenu mPastePopupWindow;
         private Runnable mLongPressCallback;
 
+        // Touch-up filter: number of previous positions remembered
+        private static final int HISTORY_SIZE = 5;
+        private static final int TOUCH_UP_FILTER_DELAY = 150;
+        private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
+        private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
+        private int mPreviousOffsetIndex = 0;
+        private int mNumberPreviousOffsets = 0;
+
+        public void startTouchUpFilter(int offset) {
+            mNumberPreviousOffsets = 0;
+            addPositionToTouchUpFilter(offset);
+        }
+
+        public void addPositionToTouchUpFilter(int offset) {
+            if (mNumberPreviousOffsets > 0 &&
+                    mPreviousOffsets[mPreviousOffsetIndex] == offset) {
+                // Make sure only actual changes of position are recorded.
+                return;
+            }
+
+            mPreviousOffsetIndex = (mPreviousOffsetIndex + 1) % HISTORY_SIZE;
+            mPreviousOffsets[mPreviousOffsetIndex] = offset;
+            mPreviousOffsetsTimes[mPreviousOffsetIndex] = SystemClock.uptimeMillis();
+            mNumberPreviousOffsets++;
+        }
+
+        public void filterOnTouchUp() {
+            final long now = SystemClock.uptimeMillis();
+            int i = 0;
+            int index = 0;
+            final int iMax = Math.min(mNumberPreviousOffsets, HISTORY_SIZE);
+            while (i < iMax) {
+                index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
+                if ((now - mPreviousOffsetsTimes[index]) >= TOUCH_UP_FILTER_DELAY) break;
+                i++;
+            }
+
+            mController.updateOffset(this, mPreviousOffsets[index]);
+        }
+
         public static final int LEFT = 0;
         public static final int CENTER = 1;
         public static final int RIGHT = 2;
@@ -8736,20 +8776,14 @@
         @Override
         protected void onDraw(Canvas c) {
             mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
-            if (mPositionOnTop) {
-                c.save();
-                c.rotate(180, (mRight - mLeft) / 2, (mBottom - mTop) / 2);
-                mDrawable.draw(c);
-                c.restore();
-            } else {
-                mDrawable.draw(c);
-            }
+            mDrawable.draw(c);
         }
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
             switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
+                startTouchUpFilter(mController.getCurrentOffset(this));
                 mDownPositionX = ev.getRawX();
                 mDownPositionY = ev.getRawY();
                 mTouchToWindowOffsetX = mDownPositionX - mPositionX;
@@ -8806,6 +8840,7 @@
                         }
                     }
                 }
+                filterOnTouchUp();
                 mIsDragging = false;
                 break;
 
@@ -8823,6 +8858,7 @@
         }
 
         void positionAtCursor(final int offset, boolean bottom) {
+            addPositionToTouchUpFilter(offset);
             final int width = mDrawable.getIntrinsicWidth();
             final int height = mDrawable.getIntrinsicHeight();
             final int line = mLayout.getLineForOffset(offset);
@@ -8938,12 +8974,16 @@
             int offset = getHysteresisOffset(x, y, previousOffset);
 
             if (offset != previousOffset) {
-                Selection.setSelection((Spannable) mText, offset);
-                updatePosition();
+                updateOffset(handle, offset);
             }
             hideDelayed();
         }
 
+        public void updateOffset(HandleView handle, int offset) {
+            Selection.setSelection((Spannable) mText, offset);
+            updatePosition();
+        }
+
         public void updatePosition() {
             final int offset = getSelectionStart();
 
@@ -8957,6 +8997,10 @@
             getHandle().positionAtCursor(offset, true);
         }
 
+        public int getCurrentOffset(HandleView handle) {
+            return getSelectionStart();
+        }
+
         public boolean onTouchEvent(MotionEvent ev) {
             return false;
         }
@@ -9067,6 +9111,20 @@
             updatePosition();
         }
 
+        public void updateOffset(HandleView handle, int offset) {
+            int start = getSelectionStart();
+            int end = getSelectionEnd();
+
+            if (mStartHandle == handle) {
+                start = offset;
+            } else {
+                end = offset;
+            }
+
+            Selection.setSelection((Spannable) mText, start, end);
+            updatePosition();
+        }
+
         public void updatePosition() {
             if (!isShowing()) {
                 return;
@@ -9087,6 +9145,10 @@
             mEndHandle.positionAtCursor(selectionEnd, true);
         }
 
+        public int getCurrentOffset(HandleView handle) {
+            return mStartHandle == handle ? getSelectionStart() : getSelectionEnd();
+        }
+
         public boolean onTouchEvent(MotionEvent event) {
             // This is done even when the View does not have focus, so that long presses can start
             // selection and tap can move cursor from this tap position.
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index e47d91c..491a388 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -517,6 +517,11 @@
     }
 }
 
+static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
+    jint descriptor = env->GetIntField(fileDescriptor, gFileDescriptor_descriptor);
+    return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gMethods[] = {
@@ -546,6 +551,11 @@
     },
 
     {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
+
+    {   "nativeIsSeekable",
+        "(Ljava/io/FileDescriptor;)Z",
+        (void*)nativeIsSeekable
+    },
 };
 
 static JNINativeMethod gOptionsMethods[] = {
diff --git a/core/res/res/color/secondary_text_holo_dark.xml b/core/res/res/color/secondary_text_holo_dark.xml
index 881a1de3..7c564f7 100644
--- a/core/res/res/color/secondary_text_holo_dark.xml
+++ b/core/res/res/color/secondary_text_holo_dark.xml
@@ -17,11 +17,11 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
     <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_dark"/>
-    <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/>
-    <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_inverse_disabled_holo_dark"/>
-    <item android:state_selected="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/>
-    <item android:state_activated="true" android:color="@android:color/bright_foreground_inverse_holo_dark"/>
-    <item android:state_pressed="true" android:color="@android:color/dim_foreground_inverse_holo_dark"/>
+    <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+    <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+    <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_dark"/>
+    <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_dark"/>
+    <item android:state_pressed="true" android:color="@android:color/dim_foreground_holo_dark"/>
     <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
     <item android:color="@android:color/dim_foreground_holo_dark"/> <!-- not selected -->
 </selector>
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_0.png b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
index 3ed0105..82f2509 100644
--- a/core/res/res/drawable-hdpi/stat_sys_battery_0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_10.png b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
old mode 100644
new mode 100755
index c81616b..4486553
--- a/core/res/res/drawable-hdpi/stat_sys_battery_10.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_20.png b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
old mode 100644
new mode 100755
index eb5ef09..c8f9c92
--- a/core/res/res/drawable-hdpi/stat_sys_battery_20.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_40.png b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_60.png b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_80.png b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
old mode 100644
new mode 100755
index 9a6c683..c7464f7
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
old mode 100644
new mode 100755
index c40c622..997feb3
--- a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
old mode 100644
new mode 100755
index 1a9abaf..dadfe8d
--- a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
new file mode 100644
index 0000000..719eb89
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
new file mode 100644
index 0000000..719eb89
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png
new file mode 100644
index 0000000..c605607
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
new file mode 100644
index 0000000..a798863
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
new file mode 100644
index 0000000..07e6165
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
new file mode 100644
index 0000000..ec17841
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
new file mode 100644
index 0000000..a0cb1ec
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
index eb4e0be..45cc20d 100644
--- a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
index e56ae5b..45cc20d 100644
--- a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
index 8c3e363..0bc86c3 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
index 7b3e41b..2ab4547 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
index f163742..fe72d00 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
index 37abb2f..be666c6 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
index c6f6fc2..9627197 100644
--- a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index dd6bf19..cffee5f 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -564,11 +564,22 @@
      * @return the decoded bitmap, or null
      */
     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
-        Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
-        if (bm == null && opts != null && opts.inBitmap != null) {
-            throw new IllegalArgumentException("Problem decoding into existing bitmap");
+        if (nativeIsSeekable(fd)) {
+            Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+            if (bm == null && opts != null && opts.inBitmap != null) {
+                throw new IllegalArgumentException("Problem decoding into existing bitmap");
+            }
+            return finishDecode(bm, outPadding, opts);
+        } else {
+            FileInputStream fis = new FileInputStream(fd);
+            try {
+                return decodeStream(fis, outPadding, opts);
+            } finally {
+                try {
+                    fis.close();
+                } catch (Throwable t) {/* ignore */}
+            }
         }
-        return finishDecode(bm, outPadding, opts);
     }
 
     /**
@@ -615,4 +626,5 @@
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
             int length, Options opts);
     private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
+    private static native boolean nativeIsSeekable(FileDescriptor fd);
 }
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 1ab2109..042f6c7 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -471,45 +471,42 @@
                                ScriptC *s,
                                const char *resName,
                                const char *cacheDir) {
-    {
-        s->mBccScript = bccCreateScript();
+    s->mBccScript = bccCreateScript();
 
-        s->mEnviroment.mIsThreadable = true;
+    s->mEnviroment.mIsThreadable = true;
 
-        bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s);
+    bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s);
 
-        if (bccReadBC(s->mBccScript,
-                      resName,
-                      s->mEnviroment.mScriptText,
-                      s->mEnviroment.mScriptTextLength, 0) != 0) {
-            LOGE("bcc: FAILS to read bitcode");
-            // Handle Fatal Error
-        }
+    if (bccReadBC(s->mBccScript,
+                  resName,
+                  s->mEnviroment.mScriptText,
+                  s->mEnviroment.mScriptTextLength, 0) != 0) {
+        LOGE("bcc: FAILS to read bitcode");
+        // Handle Fatal Error
+    }
 
 #if 1
-        if (bccLinkBC(s->mBccScript,
-                      resName,
-                      NULL /*rs_runtime_lib_bc*/,
-                      1 /*rs_runtime_lib_bc_size*/
-                        /*"1" means skip buffer here, and let libbcc decide*/,
-                      0) != 0) {
-            LOGE("bcc: FAILS to link bitcode");
-            // Handle Fatal Error
-        }
-#endif
-        char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
-
-        if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
-            LOGE("bcc: FAILS to prepare executable");
-            // Handle Fatal Error
-        }
-
-        free(cachePath);
-
-        s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root"));
-        s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init"));
+    if (bccLinkBC(s->mBccScript,
+                  resName,
+                  NULL /*rs_runtime_lib_bc*/,
+                  1 /*rs_runtime_lib_bc_size*/
+                    /*"1" means skip buffer here, and let libbcc decide*/,
+                  0) != 0) {
+        LOGE("bcc: FAILS to link bitcode");
+        // Handle Fatal Error
     }
-    LOGV("%p ScriptCState::runCompiler root %p,  init %p", rsc, s->mProgram.mRoot, s->mProgram.mInit);
+#endif
+    char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC");
+
+    if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) {
+        LOGE("bcc: FAILS to prepare executable");
+        // Handle Fatal Error
+    }
+
+    free(cachePath);
+
+    s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root"));
+    s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init"));
 
     if (s->mProgram.mInit) {
         s->mProgram.mInit();
@@ -537,66 +534,62 @@
     s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore());
     s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster());
 
-    if (s->mProgram.mRoot) {
-        const static int pragmaMax = 16;
-        size_t pragmaCount = bccGetPragmaCount(s->mBccScript);
-        char const *keys[pragmaMax];
-        char const *values[pragmaMax];
-        bccGetPragmaList(s->mBccScript, pragmaMax, keys, values);
+    const static int pragmaMax = 16;
+    size_t pragmaCount = bccGetPragmaCount(s->mBccScript);
+    char const *keys[pragmaMax];
+    char const *values[pragmaMax];
+    bccGetPragmaList(s->mBccScript, pragmaMax, keys, values);
 
-        for (size_t i=0; i < pragmaCount; ++i) {
-            //LOGE("pragma %s %s", keys[i], values[i]);
-            if (!strcmp(keys[i], "version")) {
+    for (size_t i=0; i < pragmaCount; ++i) {
+        //LOGE("pragma %s %s", keys[i], values[i]);
+        if (!strcmp(keys[i], "version")) {
+            // TODO: Verify that version is correct
+            continue;
+        }
+
+        if (!strcmp(keys[i], "stateVertex")) {
+            if (!strcmp(values[i], "default")) {
                 continue;
             }
-
-            if (!strcmp(keys[i], "stateVertex")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mVertex.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateVertex", values[i]);
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mVertex.clear();
+                continue;
             }
-
-            if (!strcmp(keys[i], "stateRaster")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mRaster.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateRaster", values[i]);
-            }
-
-            if (!strcmp(keys[i], "stateFragment")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mFragment.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateFragment", values[i]);
-            }
-
-            if (!strcmp(keys[i], "stateStore")) {
-                if (!strcmp(values[i], "default")) {
-                    continue;
-                }
-                if (!strcmp(values[i], "parent")) {
-                    s->mEnviroment.mFragmentStore.clear();
-                    continue;
-                }
-                LOGE("Unreconized value %s passed to stateStore", values[i]);
-            }
+            LOGE("Unreconized value %s passed to stateVertex", values[i]);
         }
-    } else {
-        LOGE("bcc: FAILS to prepare executable");
-        // Handle Fatal Error
+
+        if (!strcmp(keys[i], "stateRaster")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mRaster.clear();
+                continue;
+            }
+            LOGE("Unreconized value %s passed to stateRaster", values[i]);
+        }
+
+        if (!strcmp(keys[i], "stateFragment")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mFragment.clear();
+                continue;
+            }
+            LOGE("Unreconized value %s passed to stateFragment", values[i]);
+        }
+
+        if (!strcmp(keys[i], "stateStore")) {
+            if (!strcmp(values[i], "default")) {
+                continue;
+            }
+            if (!strcmp(values[i], "parent")) {
+                s->mEnviroment.mFragmentStore.clear();
+                continue;
+            }
+            LOGE("Unreconized value %s passed to stateStore", values[i]);
+        }
     }
 }
 
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
index 993ea55..3359602 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_pressed.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index 69bc161..7012ddc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -188,6 +188,12 @@
                 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, ID_IME_BUTTON_VISIBILITY_AUTO);
     }
 
+    public void setIconImage(int resId) {
+        if (mIcon != null) {
+            mIcon.setImageResource(resId);
+        }
+    }
+
     public void setIMEButtonVisible(IBinder token, boolean keyboardVisible) {
         mToken = token;
         mKeyboardVisible = keyboardVisible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index add67b1..cc200e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.provider.Settings;
@@ -53,11 +52,12 @@
                     new HashMap<InputMethodInfo, List<InputMethodSubtype>>();
     private final HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>> mRadioViewAndImiMap =
             new HashMap<View, Pair<InputMethodInfo, InputMethodSubtype>>();
-    private final PackageManager mPackageManager;
 
     private Context mContext;
     private IBinder mToken;
+    private InputMethodButton mInputMethodSwitchButton;
     private LinearLayout mInputMethodMenuList;
+    private PackageManager mPackageManager;
     private String mEnabledInputMethodAndSubtypesCacheStr;
     private View mConfigureImeShortcut;
 
@@ -69,7 +69,6 @@
         super(context, attrs, defStyle);
         mContext = context;
         mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
-        mPackageManager = context.getPackageManager();
     }
 
     @Override
@@ -90,8 +89,17 @@
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
-        if (visibility == View.VISIBLE && changedView == this) {
-            updateUiElements();
+        if (changedView == this) {
+            if (visibility == View.VISIBLE) {
+                updateUiElements();
+                if (mInputMethodSwitchButton != null) {
+                    mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime_pressed);
+                }
+            } else {
+                if (mInputMethodSwitchButton != null) {
+                    mInputMethodSwitchButton.setIconImage(R.drawable.ic_sysbar_ime);
+                }
+            }
         }
     }
 
@@ -180,6 +188,8 @@
         // TODO: Reuse subtype views.
         mInputMethodMenuList.removeAllViews();
         mRadioViewAndImiMap.clear();
+        mPackageManager = mContext.getPackageManager();
+
         HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledIMIs
                 = getEnabledInputMethodAndSubtypeList();
         // TODO: Sort by alphabet and mode.
@@ -198,10 +208,14 @@
         updateRadioButtons();
     }
 
-    public void setIMEToken(IBinder token) {
+    public void setImeToken(IBinder token) {
         mToken = token;
     }
 
+    public void setImeSwitchButton(InputMethodButton imb) {
+        mInputMethodSwitchButton = imb;
+    }
+
     private void setInputMethodAndSubtype(InputMethodInfo imi, InputMethodSubtype subtype) {
         if (mToken != null) {
             mImm.setInputMethodAndSubtype(mToken, imi.getId(), subtype);
@@ -308,6 +322,10 @@
 
     private CharSequence getSubtypeName(InputMethodInfo imi, InputMethodSubtype subtype) {
         if (imi == null || subtype == null) return null;
+        if (DEBUG) {
+            Log.d(TAG, "Get text from: " + imi.getPackageName() + subtype.getNameResId()
+                    + imi.getServiceInfo().applicationInfo);
+        }
         // TODO: Change the language of subtype name according to subtype's locale.
         return mPackageManager.getText(
                 imi.getPackageName(), subtype.getNameResId(), imi.getServiceInfo().applicationInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 825877a..6db74d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -272,6 +272,7 @@
         mInputMethodsPanel.setVisibility(View.GONE);
         mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener(
                 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel));
+        mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton);
         mStatusBarView.setIgnoreChildren(3, mInputMethodSwitchButton, mInputMethodsPanel);
         lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -853,7 +854,7 @@
         if (oldVisibility != mInputMethodSwitchButton.getVisibility()) {
             updateNotificationIcons();
         }
-        mInputMethodsPanel.setIMEToken(token);
+        mInputMethodsPanel.setImeToken(token);
         mBackButton.setImageResource(
                 visible ? R.drawable.ic_sysbar_back_ime : R.drawable.ic_sysbar_back);
         if (FAKE_SPACE_BAR) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 7b4f246..4d40620 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2049,8 +2049,9 @@
         for (int i = 0; i < N; ++i) {
             InputMethodSubtype subtype = subtypes.get(i);
             final String subtypeLocale = subtype.getLocale();
-            // An applicable subtype should match "mode".
-            if (subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
+            // An applicable subtype should match "mode". If mode is null, mode will be ignored,
+            // and all subtypes with all modes can be candidates.
+            if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
                 if (firstMatchedModeSubtype == null) {
                     firstMatchedModeSubtype = subtype;
                 }
@@ -2175,11 +2176,24 @@
                     InputMethodInfo imi = mMethodMap.get(lastInputMethodId);
                     if (imi != null) {
                         // If there are no selected subtypes, the framework will try to find
-                        // the most applicable subtype from all subtypes whose mode is
-                        // SUBTYPE_MODE_KEYBOARD. This is an exceptional case, so we will hardcode
-                        // the mode.
-                        mCurrentSubtype = findLastResortApplicableSubtypeLocked(
-                                mRes, imi.getSubtypes(), SUBTYPE_MODE_KEYBOARD, null, true);
+                        // the most applicable subtype from explicitly or implicitly enabled
+                        // subtypes.
+                        List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
+                                getEnabledInputMethodSubtypeList(imi, true);
+                        // If there is only one explicitly or implicitly enabled subtype,
+                        // just returns it.
+                        if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
+                            mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
+                        } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
+                            mCurrentSubtype = findLastResortApplicableSubtypeLocked(
+                                    mRes, explicitlyOrImplicitlyEnabledSubtypes,
+                                    SUBTYPE_MODE_KEYBOARD, null, true);
+                            if (mCurrentSubtype == null) {
+                                mCurrentSubtype = findLastResortApplicableSubtypeLocked(
+                                        mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
+                                        true);
+                            }
+                        }
                     }
                 } else {
                     mCurrentSubtype =
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 166dbc3..8d194925 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -80,6 +80,7 @@
     private final Object mProjectKey;
     private final DisplayMetrics mMetrics;
     private final RenderResources mRenderResources;
+    private final ApplicationInfo mApplicationInfo;
 
     private final Map<Object, Map<String, String>> mDefaultPropMaps =
         new IdentityHashMap<Object, Map<String,String>>();
@@ -112,10 +113,12 @@
      * value is the resource value.
      * @param styleInheritanceMap
      * @param projectCallback
+     * @param targetSdkVersion the targetSdkVersion of the application.
      */
     public BridgeContext(Object projectKey, DisplayMetrics metrics,
             RenderResources renderResources,
-            IProjectCallback projectCallback) {
+            IProjectCallback projectCallback,
+            int targetSdkVersion) {
         mProjectKey = projectKey;
         mMetrics = metrics;
         mProjectCallback = projectCallback;
@@ -124,6 +127,9 @@
 
         mFragments.mCurState = Fragment.CREATED;
         mFragments.mActivity = this;
+
+        mApplicationInfo = new ApplicationInfo();
+        mApplicationInfo.targetSdkVersion = targetSdkVersion;
     }
 
     /**
@@ -836,7 +842,7 @@
 
     @Override
     public ApplicationInfo getApplicationInfo() {
-        return new ApplicationInfo();
+        return mApplicationInfo;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index e5951f6..63d52e9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -67,8 +67,10 @@
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.TabHost;
 import android.widget.TabWidget;
+import android.widget.TabHost.TabSpec;
 
 import java.awt.Color;
 import java.awt.Graphics2D;
@@ -170,7 +172,7 @@
 
         // build the context
         mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
-                mParams.getProjectCallback());
+                mParams.getProjectCallback(), mParams.getTargetSdkVersion());
 
 
         setUp();
@@ -918,7 +920,7 @@
     /**
      * Returns the top screen offset. This depends on whether the current theme defines the user
      * of the title and status bars.
-     * @param resolver The {@link ResourceResolver}
+     * @param resolver The {@link RenderResources}
      * @param metrics The display metrics
      * @return the pixel height offset
      */
@@ -1047,28 +1049,36 @@
         // now process the content of the framelayout and dynamically create tabs for it.
         final int count = content.getChildCount();
 
-        if (count == 0) {
-            throw new PostInflateException(
-                    "The FrameLayout for the TabHost has no content. Rendering failed.\n");
-        }
-
         // this must be called before addTab() so that the TabHost searches its TabWidget
         // and FrameLayout.
         tabHost.setup();
 
-        // for each child of the framelayout, add a new TabSpec
-        for (int i = 0 ; i < count ; i++) {
-            View child = content.getChildAt(i);
-            String tabSpec = String.format("tab_spec%d", i+1);
-            int id = child.getId();
-            String[] resource = projectCallback.resolveResourceValue(id);
-            String name;
-            if (resource != null) {
-                name = resource[0]; // 0 is resource name, 1 is resource type.
-            } else {
-                name = String.format("Tab %d", i+1); // default name if id is unresolved.
+        if (count == 0) {
+            // Create a dummy child to get a single tab
+            TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
+                    tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
+                    .setContent(new TabHost.TabContentFactory() {
+                        public View createTabContent(String tag) {
+                            return new LinearLayout(mContext);
+                        }
+                    });
+            tabHost.addTab(spec);
+            return;
+        } else {
+            // for each child of the framelayout, add a new TabSpec
+            for (int i = 0 ; i < count ; i++) {
+                View child = content.getChildAt(i);
+                String tabSpec = String.format("tab_spec%d", i+1);
+                int id = child.getId();
+                String[] resource = projectCallback.resolveResourceValue(id);
+                String name;
+                if (resource != null) {
+                    name = resource[0]; // 0 is resource name, 1 is resource type.
+                } else {
+                    name = String.format("Tab %d", i+1); // default name if id is unresolved.
+                }
+                tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
             }
-            tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
         }
     }
 
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index 3af6e78..dc66989 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -105,7 +105,7 @@
         if (SipManager.isApiSupported(context)) {
             ServiceManager.addService("sip", new SipService(context));
             context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
-            if (DEBUG) Log.i(TAG, "SIP service started");
+            if (DEBUG) Log.d(TAG, "SIP service started");
         }
     }
 
@@ -113,10 +113,6 @@
         if (DEBUG) Log.d(TAG, " service started!");
         mContext = context;
         mConnectivityReceiver = new ConnectivityReceiver();
-        context.registerReceiver(mConnectivityReceiver,
-                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-        context.registerReceiver(mWifiStateReceiver,
-                new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
         mMyWakeLock = new SipWakeLock((PowerManager)
                 context.getSystemService(Context.POWER_SERVICE));
 
@@ -124,7 +120,7 @@
         mWifiOnly = SipManager.isSipWifiOnly(context);
     }
 
-    BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -147,6 +143,20 @@
         }
     };
 
+    private void registerReceivers() {
+        mContext.registerReceiver(mConnectivityReceiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+        mContext.registerReceiver(mWifiStateReceiver,
+                new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
+        if (DEBUG) Log.d(TAG, " +++ register receivers");
+    }
+
+    private void unregisterReceivers() {
+        mContext.unregisterReceiver(mConnectivityReceiver);
+        mContext.unregisterReceiver(mWifiStateReceiver);
+        if (DEBUG) Log.d(TAG, " --- unregister receivers");
+    }
+
     private MyExecutor getExecutor() {
         // create mExecutor lazily
         if (mExecutor == null) mExecutor = new MyExecutor();
@@ -166,12 +176,14 @@
         return profiles.toArray(new SipProfile[profiles.size()]);
     }
 
-    public void open(SipProfile localProfile) {
+    public synchronized void open(SipProfile localProfile) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.USE_SIP, null);
         localProfile.setCallingUid(Binder.getCallingUid());
         try {
+            boolean addingFirstProfile = mSipGroups.isEmpty();
             createGroup(localProfile);
+            if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers();
         } catch (SipException e) {
             Log.e(TAG, "openToMakeCalls()", e);
             // TODO: how to send the exception back
@@ -192,8 +204,10 @@
         if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": "
                 + incomingCallPendingIntent + ": " + listener);
         try {
+            boolean addingFirstProfile = mSipGroups.isEmpty();
             SipSessionGroupExt group = createGroup(localProfile,
                     incomingCallPendingIntent, listener);
+            if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers();
             if (localProfile.getAutoRegistration()) {
                 group.openToReceiveCalls();
                 if (mWifiEnabled) grabWifiLock();
@@ -235,6 +249,7 @@
             releaseWifiLock();
             mMyWakeLock.reset(); // in case there's leak
         }
+        if (mSipGroups.isEmpty()) unregisterReceivers();
     }
 
     public synchronized boolean isOpened(String localProfileUri) {
@@ -1055,7 +1070,10 @@
                 // we want to skip the interim ones) but deliver bad news
                 // immediately
                 if (connected) {
-                    if (mTask != null) mTask.cancel();
+                    if (mTask != null) {
+                        mTask.cancel();
+                        mMyWakeLock.release(mTask);
+                    }
                     mTask = new MyTimerTask(type, connected);
                     mTimer.schedule(mTask, 2 * 1000L);
                     // hold wakup lock so that we can finish changes before the
@@ -1096,6 +1114,7 @@
                     if (mTask != this) {
                         Log.w(TAG, "  unexpected task: " + mNetworkType
                                 + (mConnected ? " CONNECTED" : "DISCONNECTED"));
+                        mMyWakeLock.release(this);
                         return;
                     }
                     mTask = null;