Merge change 25394 into eclair

* changes:
  Add StateListDrawable's dither flag to the constant state.
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 238792b..60b406d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -221,26 +221,30 @@
         } else if (mType == TYPE_UPDATE) {
             numRows = provider.update(mUri, values, mSelection, selectionArgs);
         } else if (mType == TYPE_ASSERT) {
-            // Build projection map from expected values
-            final ArrayList<String> projectionList = new ArrayList<String>();
-            for (Map.Entry<String, Object> entry : values.valueSet()) {
-                projectionList.add(entry.getKey());
-            }
-
             // Assert that all rows match expected values
-            final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+            String[] projection =  null;
+            if (values != null) {
+                // Build projection map from expected values
+                final ArrayList<String> projectionList = new ArrayList<String>();
+                for (Map.Entry<String, Object> entry : values.valueSet()) {
+                    projectionList.add(entry.getKey());
+                }
+                projection = projectionList.toArray(new String[projectionList.size()]);
+            }
             final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
-            numRows = cursor.getCount();
             try {
-                while (cursor.moveToNext()) {
-                    for (int i = 0; i < projection.length; i++) {
-                        final String cursorValue = cursor.getString(i);
-                        final String expectedValue = values.getAsString(projection[i]);
-                        if (!TextUtils.equals(cursorValue, expectedValue)) {
-                            // Throw exception when expected values don't match
-                            throw new OperationApplicationException("Found value " + cursorValue
-                                    + " when expected " + expectedValue + " for column "
-                                    + projection[i]);
+                numRows = cursor.getCount();
+                if (projection != null) {
+                    while (cursor.moveToNext()) {
+                        for (int i = 0; i < projection.length; i++) {
+                            final String cursorValue = cursor.getString(i);
+                            final String expectedValue = values.getAsString(projection[i]);
+                            if (!TextUtils.equals(cursorValue, expectedValue)) {
+                                // Throw exception when expected values don't match
+                                throw new OperationApplicationException("Found value " + cursorValue
+                                        + " when expected " + expectedValue + " for column "
+                                        + projection[i]);
+                            }
                         }
                     }
                 }
@@ -395,12 +399,19 @@
 
         /** Create a ContentProviderOperation from this {@link Builder}. */
         public ContentProviderOperation build() {
-            if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
+            if (mType == TYPE_UPDATE) {
                 if ((mValues == null || mValues.size() == 0)
                         && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
                     throw new IllegalArgumentException("Empty values");
                 }
             }
+            if (mType == TYPE_ASSERT) {
+                if ((mValues == null || mValues.size() == 0)
+                        && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)
+                        && (mExpectedCount == null)) {
+                    throw new IllegalArgumentException("Empty values");
+                }
+            }
             return new ContentProviderOperation(this);
         }
 
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 38881d3..f736f85 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -431,6 +431,7 @@
         PICKER_SETS.put('z', "\u017A\u017C\u017E");
         PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
                              "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
+        PICKER_SETS.put('/', "\\");
 
         // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml
 
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 94acd3f..e5985c1 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -458,11 +458,12 @@
     public final View createView(String name, String prefix, AttributeSet attrs)
             throws ClassNotFoundException, InflateException {
         Constructor constructor = sConstructorMap.get(name);
+        Class clazz = null;
 
         try {
             if (constructor == null) {
                 // Class not found in the cache, see if it's real, and try to add it
-                Class clazz = mContext.getClassLoader().loadClass(
+                clazz = mContext.getClassLoader().loadClass(
                         prefix != null ? (prefix + name) : name);
                 
                 if (mFilter != null && clazz != null) {
@@ -480,7 +481,7 @@
                     Boolean allowedState = mFilterMap.get(name);
                     if (allowedState == null) {
                         // New class -- remember whether it is allowed
-                        Class clazz = mContext.getClassLoader().loadClass(
+                        clazz = mContext.getClassLoader().loadClass(
                                 prefix != null ? (prefix + name) : name);
                         
                         boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
@@ -511,7 +512,7 @@
         } catch (Exception e) {
             InflateException ie = new InflateException(attrs.getPositionDescription()
                     + ": Error inflating class "
-                    + (constructor == null ? "<unknown>" : constructor.getClass().getName()));
+                    + (clazz == null ? "<unknown>" : clazz.getName()));
             ie.initCause(e);
             throw ie;
         }
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 95b3a12..39a2470 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import com.android.internal.widget.EditableInputConnection;
+
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -38,6 +40,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -346,6 +349,16 @@
 
     @Override
     protected void onSelectionChanged(int selStart, int selEnd) {
+        // This code is copied from TextView.onDraw().  That code does not get
+        // executed, however, because the WebTextView does not draw, allowing
+        // webkit's drawing to show through.
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null && imm.isActive(this)) {
+            Spannable sp = (Spannable) getText();
+            int candStart = EditableInputConnection.getComposingSpanStart(sp);
+            int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+            imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
+        }
         if (!mFromWebKit && mWebView != null) {
             if (DebugFlags.WEB_TEXT_VIEW) {
                 Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
@@ -430,18 +443,26 @@
             mGotTouchDown = true;
             break;
         case MotionEvent.ACTION_MOVE:
+            int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
             Spannable buffer = getText();
             int initialScrollX = Touch.getInitialScrollX(this, buffer);
             int initialScrollY = Touch.getInitialScrollY(this, buffer);
             super.onTouchEvent(event);
-            if (mScrollX != initialScrollX
-                    || mScrollY != initialScrollY) {
+            if (Math.abs(mScrollX - initialScrollX) > slop
+                    || Math.abs(mScrollY - initialScrollY) > slop) {
                 if (mWebView != null) {
                     mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
                 }
                 mScrolled = true;
                 return true;
             }
+            if (Math.abs((int) event.getX() - mDragStartX) < slop
+                    && Math.abs((int) event.getY() - mDragStartY) < slop) {
+                // If the user has not scrolled further than slop, we should not
+                // send the drag.  Instead, do nothing, and when the user lifts
+                // their finger, we will change the selection.
+                return true;
+            }
             if (mWebView != null) {
                 // Only want to set the initial state once.
                 if (!mDragSent) {
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index fe01866..4ec597c 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -42,6 +42,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CheckBox;
+import android.widget.FasttrackBadgeWidget;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -64,15 +65,13 @@
     private TextView mDisplayNameView;
     private TextView mPhoneticNameView;
     private CheckBox mStarredView;
-    private ImageView mPhotoView;
+    private FasttrackBadgeWidget mPhotoView;
     private ImageView mPresenceView;
     private TextView mStatusView;
     private int mNoPhotoResource;
     private QueryHandler mQueryHandler;
 
-    protected long mContactId;
     protected Uri mContactUri;
-    protected Uri mStatusUri;
 
     protected String[] mExcludeMimes = null;
 
@@ -94,6 +93,8 @@
         Contacts.STARRED,
         Contacts.PHOTO_ID,
         Contacts.PRESENCE_STATUS,
+        Contacts._ID,
+        Contacts.LOOKUP_KEY,
     };
     protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0;
     //TODO: We need to figure out how we're going to get the phonetic name.
@@ -101,6 +102,8 @@
     protected static final int HEADER_STARRED_COLUMN_INDEX = 1;
     protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2;
     protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3;
+    protected static final int HEADER_CONTACT_ID_COLUMN_INDEX = 4;
+    protected static final int HEADER_LOOKUP_KEY_COLUMN_INDEX = 5;
 
     //Projection used for finding the most recent social status.
     protected static final String[] SOCIAL_PROJECTION = new String[] {
@@ -113,18 +116,29 @@
     //Projection used for looking up contact id from phone number
     protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
         PhoneLookup._ID,
+        PhoneLookup.LOOKUP_KEY,
     };
     protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+    protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
 
     //Projection used for looking up contact id from email address
     protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
         RawContacts.CONTACT_ID,
+        Contacts.LOOKUP_KEY,
     };
     protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+    protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
 
+    protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] {
+        Contacts._ID,
+    };
+    protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0;
 
     private static final int TOKEN_CONTACT_INFO = 0;
     private static final int TOKEN_SOCIAL = 1;
+    private static final int TOKEN_PHONE_LOOKUP = 2;
+    private static final int TOKEN_EMAIL_LOOKUP = 3;
+    private static final int TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY = 4;
 
     public ContactHeaderWidget(Context context) {
         this(context, null);
@@ -151,8 +165,7 @@
         mStarredView = (CheckBox)findViewById(R.id.star);
         mStarredView.setOnClickListener(this);
 
-        mPhotoView = (ImageView)findViewById(R.id.photo);
-        mPhotoView.setOnClickListener(this);
+        mPhotoView = (FasttrackBadgeWidget) findViewById(R.id.photo);
         mPhotoView.setOnLongClickListener(this);
 
         mPresenceView = (ImageView) findViewById(R.id.presence);
@@ -217,12 +230,46 @@
         @Override
         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
             try{
-                if (token == TOKEN_CONTACT_INFO) {
-                    bindContactInfo(cursor);
-                    invalidate();
-                } else if (token == TOKEN_SOCIAL) {
-                    bindSocial(cursor);
-                    invalidate();
+                switch (token) {
+                    case TOKEN_CONTACT_INFO: {
+                        bindContactInfo(cursor);
+                        invalidate();
+                        break;
+                    }
+                    case TOKEN_SOCIAL: {
+                        bindSocial(cursor);
+                        invalidate();
+                        break;
+                    }
+                    case TOKEN_PHONE_LOOKUP: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+                            String lookupKey = cursor.getString(
+                                    PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+                            bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+                        } else {
+                            setDisplayName((String) cookie, null);
+                        }
+                        break;
+                    }
+                    case TOKEN_EMAIL_LOOKUP: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+                            String lookupKey = cursor.getString(
+                                    EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+                            bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+                        } else {
+                            setDisplayName((String) cookie, null);
+                        }
+                        break;
+                    }
+                    case TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(CONTACT_LOOKUP_ID_COLUMN_INDEX);
+                            startSocialQuery(ContentUris.withAppendedId(
+                                    Activities.CONTENT_CONTACT_STATUS_URI, contactId));
+                        }
+                    }
                 }
             } finally {
                 if (cursor != null) {
@@ -300,33 +347,31 @@
      * Convenience method for binding all available data from an existing
      * contact.
      *
-     * @param contactId the contact id of the contact whose info should be displayed.
+     * @param conatctUri a {Contacts.CONTENT_LOOKUP_URI} style URI.
      */
-    public void bindFromContactId(long contactId) {
-        mContactId = contactId;
-        mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId);
+    public void bindFromContactLookupUri(Uri contactLookupUri) {
+        mContactUri = contactLookupUri;
 
-        bindContactUri(mContactUri);
-        bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId));
+        // Query for the contactId so we can do the social query.
+        mQueryHandler.startQuery(TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY, null, contactLookupUri,
+                CONTACT_LOOKUP_PROJECTION, null, null, null);
+
+        startContactQuery(contactLookupUri);
     }
 
     /**
-     * Convenience method for binding {@link Contacts} header details from a
-     * {@link Contacts#CONTENT_URI} reference.
+     * Convenience method for binding all available data from an existing
+     * contact.
+     *
+     * @param conatctUri a {Contacts.CONTENT_URI} style URI.
      */
-    public void bindContactUri(Uri contactUri) {
-        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
-                null, null, null);
-    }
+    public void bindFromContactUri(Uri contactUri) {
+        mContactUri = contactUri;
+        long contactId = ContentUris.parseId(contactUri);
 
-    /**
-     * Convenience method for binding {@link Activities} header details from a
-     * {@link Activities#CONTENT_CONTACT_STATUS_URI}.
-     */
-    public void bindSocialUri(Uri contactSocial) {
-        mStatusUri = contactSocial;
-        mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null,
-                null);
+        startContactQuery(contactUri);
+        startSocialQuery(ContentUris.withAppendedId(
+                Activities.CONTENT_CONTACT_STATUS_URI, contactId));
     }
 
     /**
@@ -338,21 +383,9 @@
      * address, one of them will be chosen to bind to.
      */
     public void bindFromEmail(String emailAddress) {
-        Cursor c = null;
-        try {
-            c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri
-                    .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.moveToFirst()) {
-                long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
-                bindFromContactId(contactId);
-            } else {
-                setDisplayName(emailAddress, null);
-            }
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
+        mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress,
+                Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)),
+                EMAIL_LOOKUP_PROJECTION, null, null, null);
     }
 
     /**
@@ -364,22 +397,19 @@
      * number, one of them will be chosen to bind to.
      */
     public void bindFromPhoneNumber(String number) {
-        Cursor c = null;
-        try {
-            c = mContentResolver.query(
-                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
-                    PHONE_LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.moveToFirst()) {
-                long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
-                bindFromContactId(contactId);
-            } else {
-                setDisplayName(number, null);
-            }
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
+        mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
+                Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+                PHONE_LOOKUP_PROJECTION, null, null, null);
+    }
+
+    private void startSocialQuery(Uri contactSocial) {
+        mQueryHandler.startQuery(TOKEN_SOCIAL, null, contactSocial, SOCIAL_PROJECTION, null, null,
+                null);
+    }
+
+    private void startContactQuery(Uri contactUri) {
+        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
+                null, null, null);
     }
 
     /**
@@ -390,6 +420,8 @@
 
         // TODO: Bring back phonetic name
         final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX);
+        final long contactId = c.getLong(HEADER_CONTACT_ID_COLUMN_INDEX);
+        final String lookupKey = c.getString(HEADER_LOOKUP_KEY_COLUMN_INDEX);
         final String phoneticName = null;
         this.setDisplayName(displayName, null);
 
@@ -402,6 +434,7 @@
             photoBitmap = loadPlaceholderPhoto(null);
         }
         mPhotoView.setImageBitmap(photoBitmap);
+        mPhotoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
 
         //Set the presence status
         int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX);
@@ -423,27 +456,11 @@
             return;
         }
 
-        switch (view.getId()) {
-            case R.id.star: {
-                // Toggle "starred" state
-                final ContentValues values = new ContentValues(1);
-                values.put(Contacts.STARRED, mStarredView.isChecked());
-                mContentResolver.update(mContactUri, values, null, null);
-                break;
-            }
-            case R.id.photo: {
-                // Photo launches contact detail action
-                final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
-                final Rect target = getTargetRect(view);
-                intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
-                intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
-                if (mExcludeMimes != null) {
-                    // Exclude specific MIME-types when requested
-                    intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes);
-                }
-                mContext.startActivity(intent);
-                break;
-            }
+        if (view.getId() == R.id.star) {
+            // Toggle "starred" state
+            final ContentValues values = new ContentValues(1);
+            values.put(Contacts.STARRED, mStarredView.isChecked());
+            mContentResolver.update(mContactUri, values, null, null);
         }
     }
 
diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png
new file mode 100644
index 0000000..c13dd26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png
new file mode 100644
index 0000000..9d01f79
--- /dev/null
+++ b/core/res/res/drawable-mdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index 8d7e470..e800dfa 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -19,17 +19,17 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
-    android:background="@drawable/title_bar_tall"
+    android:background="@drawable/title_bar_medium"
     android:paddingRight="5dip"
     android:gravity="center_vertical">
     
-    <ImageView android:id="@+id/photo"
-        android:layout_width="56dip"
-        android:layout_height="62dip"
+    <android.widget.FasttrackBadgeWidget android:id="@+id/photo"
+        android:layout_alignParentLeft="true"
+        android:layout_centerVertical="true"
         android:layout_marginRight="10dip"
         android:layout_marginLeft="10dip"
-        android:scaleType="fitCenter"
-        android:background="@drawable/fasttrack_badge_middle_large"/>
+        style="@*android:style/Widget.FasttrackBadgeWidget.WindowSmall" />
+    />
     
     <LinearLayout
         android:layout_width="0dip"
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 62a230c..c967c4c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -18,7 +18,7 @@
 */
 -->
 <resources>
-	<drawable name="screen_background_light">#fff9f9f9</drawable>
+	<drawable name="screen_background_light">#ffffffff</drawable>
 	<drawable name="screen_background_dark">#ff202020</drawable>
     <drawable name="status_bar_closed_default_background">#ff000000</drawable>
     <drawable name="status_bar_opened_default_background">#ff000000</drawable>
@@ -45,7 +45,7 @@
     <color name="dim_foreground_dark_inverse">#323232</color>
     <color name="dim_foreground_dark_inverse_disabled">#80323232</color>
     <color name="hint_foreground_dark">#808080</color>
-    <color name="background_light">#fff9f9f9</color>
+    <color name="background_light">#ffffffff</color>
     <color name="bright_foreground_light">#ff000000</color>
     <color name="bright_foreground_light_inverse">#ffffffff</color>
     <color name="bright_foreground_light_disabled">#80000000</color>
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index a32d8ea..041c5d3 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -32,3 +32,20 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 
 include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := required_hardware.xml
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/data/etc/android.hardware.camera.flash-autofocus.xml b/data/etc/android.hardware.camera.flash-autofocus.xml
new file mode 100644
index 0000000..55f1900
--- /dev/null
+++ b/data/etc/android.hardware.camera.flash-autofocus.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a camera with a flash.  Note
+     that this currently requires having auto-focus as well. -->
+<permissions>
+    <feature name="android.hardware.camera" />
+    <feature name="android.hardware.camera.autofocus" />
+    <feature name="android.hardware.camera.flash" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.light.xml b/data/etc/android.hardware.sensor.light.xml
new file mode 100644
index 0000000..78b0fec
--- /dev/null
+++ b/data/etc/android.hardware.sensor.light.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<!-- Feature for devices with an ambient light sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.light" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.proximity.xml b/data/etc/android.hardware.sensor.proximity.xml
new file mode 100644
index 0000000..d1948de
--- /dev/null
+++ b/data/etc/android.hardware.sensor.proximity.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<!-- Feature for devices with a proximity sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.proximity" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
new file mode 100644
index 0000000..72e0485
--- /dev/null
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a CDMA phone. -->
+<permissions>
+    <feature name="android.hardware.telephony" />
+    <feature name="android.hardware.telephony.cdma" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
new file mode 100644
index 0000000..ffde433
--- /dev/null
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a GSM phone. -->
+<permissions>
+    <feature name="android.hardware.telephony" />
+    <feature name="android.hardware.telephony.gsm" />
+</permissions>
diff --git a/data/etc/required_hardware.xml b/data/etc/required_hardware.xml
new file mode 100644
index 0000000..896a148
--- /dev/null
+++ b/data/etc/required_hardware.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<!-- These are the hardware features that all devices must possess.
+     These are always added for you by the build system, you do not need
+     to add them yourself. -->
+<permissions>
+    <feature name="android.hardware.sensor.compass" />
+    <feature name="android.hardware.sensor.accelerometer" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.wifi" />
+</permissions>
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 89db4fa..d35c5e3 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -140,6 +140,8 @@
     native void nScriptSetTimeZone(int script, byte[] timeZone);
     native void nScriptSetType(int type, boolean writable, String name, int slot);
     native void nScriptSetRoot(boolean isRoot);
+    native void nScriptSetInvokable(String name, int slot);
+    native void nScriptInvoke(int id, int slot);
 
     native void nScriptCBegin();
     native void nScriptCSetScript(byte[] script, int offset, int length);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index a402471..35791a3 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -25,6 +25,22 @@
     boolean mIsRoot;
     Type[] mTypes;
     boolean[] mWritable;
+    Invokable[] mInvokables;
+
+    public static class Invokable {
+        RenderScript mRS;
+        Script mScript;
+        int mSlot;
+        String mName;
+
+        Invokable() {
+            mSlot = -1;
+        }
+
+        public void execute() {
+            mRS.nScriptInvoke(mScript.mID, mSlot);
+        }
+    }
 
     Script(int id, RenderScript rs) {
         super(rs);
@@ -61,12 +77,15 @@
         Type[] mTypes;
         String[] mNames;
         boolean[] mWritable;
+        int mInvokableCount = 0;
+        Invokable[] mInvokables;
 
         Builder(RenderScript rs) {
             mRS = rs;
             mTypes = new Type[MAX_SLOT];
             mNames = new String[MAX_SLOT];
             mWritable = new boolean[MAX_SLOT];
+            mInvokables = new Invokable[MAX_SLOT];
         }
 
         public void setType(Type t, int slot) {
@@ -79,6 +98,15 @@
             mNames[slot] = name;
         }
 
+        public Invokable addInvokable(String func) {
+            Invokable i = new Invokable();
+            i.mName = func;
+            i.mRS = mRS;
+            i.mSlot = mInvokableCount;
+            mInvokables[mInvokableCount++] = i;
+            return i;
+        }
+
         public void setType(boolean writable, int slot) {
             mWritable[slot] = writable;
         }
@@ -90,11 +118,20 @@
                     mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
                 }
             }
+            for(int ct=0; ct < mInvokableCount; ct++) {
+                mRS.nScriptSetInvokable(mInvokables[ct].mName, ct);
+            }
         }
 
         void transferObject(Script s) {
             s.mIsRoot = mIsRoot;
             s.mTypes = mTypes;
+            s.mInvokables = new Invokable[mInvokableCount];
+            for(int ct=0; ct < mInvokableCount; ct++) {
+                s.mInvokables[ct] = mInvokables[ct];
+                s.mInvokables[ct].mScript = s;
+            }
+            s.mInvokables = null;
         }
 
         public void setRoot(boolean r) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 90b5958..eae6f24 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -891,6 +891,29 @@
 }
 
 static void
+nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nScriptSetInvoke, con(%p)", con);
+    const char* n = NULL;
+    if (_str) {
+        n = _env->GetStringUTFChars(_str, NULL);
+    }
+    rsScriptSetInvoke(con, n, slot);
+    if (n) {
+        _env->ReleaseStringUTFChars(_str, n);
+    }
+}
+
+static void
+nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nScriptInvoke, con(%p), script(%p)", con, (void *)obj);
+    rsScriptInvoke(con, (RsScript)obj, slot);
+}
+
+static void
 nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -1366,6 +1389,8 @@
 {"nScriptSetTimeZone",             "(I[B)V",                               (void*)nScriptSetTimeZone },
 {"nScriptSetType",                 "(IZLjava/lang/String;I)V",             (void*)nScriptSetType },
 {"nScriptSetRoot",                 "(Z)V",                                 (void*)nScriptSetRoot },
+{"nScriptSetInvokable",            "(Ljava/lang/String;I)V",               (void*)nScriptSetInvoke },
+{"nScriptInvoke",                  "(II)V",                                (void*)nScriptInvoke },
 
 {"nScriptCBegin",                  "()V",                                  (void*)nScriptCBegin },
 {"nScriptCSetScript",              "([BII)V",                              (void*)nScriptCSetScript },
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ac2e738..87ad97c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -297,6 +297,16 @@
 	param const char * name
 	}
 
+ScriptSetInvoke {
+	param const char * name
+	param uint32_t slot
+	}
+
+ScriptInvoke {
+	param RsScript s
+	param uint32_t slot
+	}
+
 ScriptSetRoot {
 	param bool isRoot
 	}
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index fde31a1..99a085d 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -27,6 +27,8 @@
     mEnviroment.mClearColor[2] = 0;
     mEnviroment.mClearColor[3] = 1;
     mEnviroment.mClearDepth = 1;
+    mEnviroment.mClearStencil = 0;
+    mEnviroment.mIsRoot = false;
 }
 
 Script::~Script()
@@ -83,10 +85,23 @@
     }
 }
 
+void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mInvokableNames[slot] = name;
+}
+
+void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
+{
+    Script *s = static_cast<Script *>(vs);
+    s->mEnviroment.mInvokables[slot]();
+}
+
+
 void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
 {
     ScriptCState *ss = &rsc->mScriptC;
-    ss->mEnviroment.mIsRoot = isRoot;
+    ss->mScript->mEnviroment.mIsRoot = isRoot;
 }
 
 
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 60f83a6..e40531e 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -34,6 +34,7 @@
 class Script : public ObjectBase
 {
 public:
+    typedef void (* InvokeFunc_t)(void);
 
     Script();
     virtual ~Script();
@@ -52,17 +53,22 @@
         ObjectBaseRef<ProgramFragment> mFragment;
         //ObjectBaseRef<ProgramRaster> mRaster;
         ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
-
+        InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS];
+        const char * mScriptText;
+        uint32_t mScriptTextLength;
     };
     Enviroment_t mEnviroment;
 
     uint32_t mCounstantBufferCount;
 
+
     ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
     ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
     String8 mSlotNames[MAX_SCRIPT_BANKS];
     bool mSlotWritable[MAX_SCRIPT_BANKS];
 
+
+
     virtual bool run(Context *, uint32_t launchID) = 0;
 };
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 8230cbc..108ae5a 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -82,36 +82,27 @@
 
 ScriptCState::ScriptCState()
 {
+    mScript = NULL;
     clear();
 }
 
 ScriptCState::~ScriptCState()
 {
-    if (mAccScript) {
-        accDeleteScript(mAccScript);
-    }
+    delete mScript;
+    mScript = NULL;
 }
 
 void ScriptCState::clear()
 {
-    memset(&mProgram, 0, sizeof(mProgram));
-
     for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         mConstantBufferTypes[ct].clear();
         mSlotNames[ct].setTo("");
+        mInvokableNames[ct].setTo("");
         mSlotWritable[ct] = false;
     }
 
-    memset(&mEnviroment, 0, sizeof(mEnviroment));
-    mEnviroment.mClearColor[0] = 0;
-    mEnviroment.mClearColor[1] = 0;
-    mEnviroment.mClearColor[2] = 0;
-    mEnviroment.mClearColor[3] = 1;
-    mEnviroment.mClearDepth = 1;
-    mEnviroment.mClearStencil = 0;
-    mEnviroment.mIsRoot = false;
-
-    mAccScript = NULL;
+    delete mScript;
+    mScript = new ScriptC();
 
     mInt32Defines.clear();
     mFloatDefines.clear();
@@ -127,9 +118,9 @@
     return NULL;
 }
 
-void ScriptCState::runCompiler(Context *rsc)
+void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
 {
-    mAccScript = accCreateScript();
+    s->mAccScript = accCreateScript();
     String8 tmp;
 
     rsc->appendNameDefines(&tmp);
@@ -139,44 +130,51 @@
     appendTypes(&tmp);
     tmp.append("#line 1\n");
 
-    const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
-    int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
-    accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
-    accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
-    accCompileScript(mAccScript);
-    accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
-    accGetScriptLabel(mAccScript, "init", (ACCvoid**) &mProgram.mInit);
-    rsAssert(mProgram.mScript);
+    const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText};
+    int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ;
+    accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+    accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL);
+    accCompileScript(s->mAccScript);
+    accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript);
+    accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit);
+    rsAssert(s->mProgram.mScript);
 
-    if (!mProgram.mScript) {
+    if (!s->mProgram.mScript) {
         ACCchar buf[4096];
         ACCsizei len;
-        accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+        accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
         LOGE(buf);
     }
 
-    if (mProgram.mInit) {
-        mProgram.mInit();
+    if (s->mProgram.mInit) {
+        s->mProgram.mInit();
     }
 
     for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         if (mSlotNames[ct].length() > 0) {
-            accGetScriptLabel(mAccScript,
+            accGetScriptLabel(s->mAccScript,
                               mSlotNames[ct].string(),
-                              (ACCvoid**) &mProgram.mSlotPointers[ct]);
-            LOGE("var  %s  %p", mSlotNames[ct].string(), mProgram.mSlotPointers[ct]);
+                              (ACCvoid**) &s->mProgram.mSlotPointers[ct]);
         }
     }
 
-    mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
-    mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
-    mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+    for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+        if (mInvokableNames[ct].length() > 0) {
+            accGetScriptLabel(s->mAccScript,
+                              mInvokableNames[ct].string(),
+                              (ACCvoid**) &s->mEnviroment.mInvokables[ct]);
+        }
+    }
 
-    if (mProgram.mScript) {
+    s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+    s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+    s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+    if (s->mProgram.mScript) {
         const static int pragmaMax = 16;
         ACCsizei pragmaCount;
         ACCchar * str[pragmaMax];
-        accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+        accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]);
 
         for (int ct=0; ct < pragmaCount; ct+=2) {
             if (!strcmp(str[ct], "version")) {
@@ -188,12 +186,12 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mVertex.clear();
+                    s->mEnviroment.mVertex.clear();
                     continue;
                 }
                 ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
                 if (pv != NULL) {
-                    mEnviroment.mVertex.set(pv);
+                    s->mEnviroment.mVertex.set(pv);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
@@ -208,12 +206,12 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mFragment.clear();
+                    s->mEnviroment.mFragment.clear();
                     continue;
                 }
                 ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
                 if (pf != NULL) {
-                    mEnviroment.mFragment.set(pf);
+                    s->mEnviroment.mFragment.set(pf);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
@@ -224,13 +222,13 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mFragmentStore.clear();
+                    s->mEnviroment.mFragmentStore.clear();
                     continue;
                 }
                 ProgramFragmentStore * pfs =
                     (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
                 if (pfs != NULL) {
-                    mEnviroment.mFragmentStore.set(pfs);
+                    s->mEnviroment.mFragmentStore.set(pfs);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
@@ -351,33 +349,6 @@
             s.append(";\n");
             LOGD(s);
             str->append(s);
-#if 0
-            for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
-                const Component *c = e->getComponent(ct2);
-                tmp.setTo("#define ");
-                tmp.append(mSlotNames[ct]);
-                tmp.append("_");
-                tmp.append(c->getComponentName());
-                switch (c->getType()) {
-                case Component::FLOAT:
-                    tmp.append(" loadF(");
-                    break;
-                case Component::SIGNED:
-                    sprintf(buf, " loadI%i(", c->getBits());
-                    tmp.append(buf);
-                    break;
-                case Component::UNSIGNED:
-                    sprintf(buf, " loadU%i(", c->getBits());
-                    tmp.append(buf);
-                    break;
-                }
-                sprintf(buf, "%i, %i)\n", ct, ct2);
-                tmp.append(buf);
-
-                LOGD(tmp);
-                str->append(tmp);
-            }
-#endif
         }
     }
 }
@@ -394,15 +365,16 @@
 
 void rsi_ScriptCSetScript(Context * rsc, void *vp)
 {
-    ScriptCState *ss = &rsc->mScriptC;
-    ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+    rsAssert(0);
+    //ScriptCState *ss = &rsc->mScriptC;
+    //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
 }
 
 void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
 {
     ScriptCState *ss = &rsc->mScriptC;
-    ss->mProgram.mScriptText = text;
-    ss->mProgram.mScriptTextLength = len;
+    ss->mScript->mEnviroment.mScriptText = text;
+    ss->mScript->mEnviroment.mScriptTextLength = len;
 }
 
 
@@ -410,14 +382,11 @@
 {
     ScriptCState *ss = &rsc->mScriptC;
 
-    ss->runCompiler(rsc);
+    ScriptC *s = ss->mScript;
+    ss->mScript = NULL;
 
-    ScriptC *s = new ScriptC();
+    ss->runCompiler(rsc, s);
     s->incUserRef();
-    s->mAccScript = ss->mAccScript;
-    ss->mAccScript = NULL;
-    s->mEnviroment = ss->mEnviroment;
-    s->mProgram = ss->mProgram;
     for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
         s->mSlotNames[ct] = ss->mSlotNames[ct];
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 8aa99ef..355f0c3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -67,17 +67,15 @@
     ScriptCState();
     ~ScriptCState();
 
-    ACCscript* mAccScript;
-
-    ScriptC::Program_t mProgram;
-    Script::Enviroment_t mEnviroment;
+    ScriptC *mScript;
 
     ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
     String8 mSlotNames[MAX_SCRIPT_BANKS];
     bool mSlotWritable[MAX_SCRIPT_BANKS];
+    String8 mInvokableNames[MAX_SCRIPT_BANKS];
 
     void clear();
-    void runCompiler(Context *rsc);
+    void runCompiler(Context *rsc, ScriptC *s);
     void appendVarDefines(String8 *str);
     void appendTypes(String8 *str);
 
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
index 5dc0ba0..1ffbd5b 100644
--- a/libs/surfaceflinger/BlurFilter.cpp
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -111,6 +111,50 @@
     }
 };
 
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+    typedef uint32_t type;
+    int r, g, b;    
+    inline BlurColor888X() { }
+    inline BlurColor888X(uint32_t v) {
+        v = BLUR_RGBA_TO_HOST(v);
+        r = v & 0xFF;
+        g = (v >>  8) & 0xFF;
+        b = (v >> 16) & 0xFF;
+    }
+    inline void clear() { r=g=b=0; }
+    inline uint32_t to(int shift, int last, int dither) const {
+        int R = r;
+        int G = g;
+        int B = b;
+        if  (UNLIKELY(last)) {
+            if (FACTOR>0) {
+                int L = (R+G+G+B)>>2;
+                R += ((L - R) * FACTOR) >> 8;
+                G += ((L - G) * FACTOR) >> 8;
+                B += ((L - B) * FACTOR) >> 8;
+            }
+        }
+        R >>= shift;
+        G >>= shift;
+        B >>= shift;
+        return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+    }    
+    inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+        r += rhs.r;
+        g += rhs.g;
+        b += rhs.b;
+        return *this;
+    }
+    inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+        r -= rhs.r;
+        g -= rhs.g;
+        b -= rhs.b;
+        return *this;
+    }
+};
+
 struct BlurGray565
 {
     typedef uint16_t type;
@@ -316,7 +360,13 @@
         int kernelSizeUser,
         int repeat)
 {
-    return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    status_t err = BAD_VALUE;
+    if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+        err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+        err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+    }
+    return err;
 }
 
 } // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index e14f35b..0ef663f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -40,9 +40,9 @@
 
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-     : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
-     mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
-     mWidthScale(1.0f), mHeightScale(1.0f)
+: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
+mWidthScale(1.0f), mHeightScale(1.0f)
 {
 }
 
@@ -136,6 +136,13 @@
         // create the texture name the first time
         // can't do that in the ctor, because it runs in another thread.
         glGenTextures(1, &mTextureName);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+        if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+            mReadFormat = GL_RGBA;
+            mReadType = GL_UNSIGNED_BYTE;
+            mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+        }
     }
 
     Region::const_iterator it = clip.begin();
@@ -143,33 +150,39 @@
     if (it != end) {
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
-    
+
         if (mRefreshCache) {
             mRefreshCache = false;
             mAutoRefreshPending = false;
-            
-            // allocate enough memory for 4-bytes (2 pixels) aligned data
-            const int32_t s = (w + 1) & ~1;
-            uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+            int32_t pixelSize = 4;
+            int32_t s = w;
+            if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+                // allocate enough memory for 4-bytes (2 pixels) aligned data
+                s = (w + 1) & ~1;
+                pixelSize = 2;
+            }
+
+            uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
 
             // This reads the frame-buffer, so a h/w GL would have to
             // finish() its rendering first. we don't want to do that
             // too often. Read data is 4-bytes aligned.
-            glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
-            
+            glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
             // blur that texture.
             GGLSurface bl;
             bl.version = sizeof(GGLSurface);
             bl.width = w;
             bl.height = h;
             bl.stride = s;
-            bl.format = GGL_PIXEL_FORMAT_RGB_565;
+            bl.format = mBlurFormat;
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
 
             if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / w;
                 mHeightScale =-1.0f / h;
                 mYOffset = 0;
@@ -178,10 +191,10 @@
                 GLuint th = 1 << (31 - clz(h));
                 if (tw < w) tw <<= 1;
                 if (th < h) th <<= 1;
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+                        mReadFormat, mReadType, NULL);
                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, 
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / tw;
                 mHeightScale =-1.0f / th;
                 mYOffset = th-h;
@@ -189,7 +202,7 @@
 
             free((void*)pixels);
         }
-        
+
         const State& s = drawingState();
         if (UNLIKELY(s.alpha < 0xFF)) {
             const GGLfixed alpha = (s.alpha << 16)/255;
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index bf36ae4..2e9d7c6 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -59,6 +59,9 @@
     mutable GLfloat mWidthScale;
     mutable GLfloat mHeightScale;
     mutable GLfloat mYOffset;
+    mutable GLint   mReadFormat;
+    mutable GLint   mReadType;
+    mutable uint32_t mBlurFormat;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 60496d6..d53f002 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7056,7 +7056,7 @@
                         + " attHidden=" + mAttachedHidden
                         + " tok.hiddenRequested="
                         + (mAppToken != null ? mAppToken.hiddenRequested : false)
-                        + " tok.idden="
+                        + " tok.hidden="
                         + (mAppToken != null ? mAppToken.hidden : false)
                         + " animating=" + mAnimating
                         + " tok animating="
@@ -7085,10 +7085,20 @@
                 if (mAttrs.type != TYPE_APPLICATION_STARTING
                         && mAppToken != null) {
                     mAppToken.firstWindowDrawn = true;
-                    if (mAnimation == null && mAppToken.startingData != null) {
+                    
+                    if (mAppToken.startingData != null) {
                         if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
                                 + mToken
                                 + ": first real window is shown, no animation");
+                        // If this initial window is animating, stop it -- we
+                        // will do an animation to reveal it from behind the
+                        // starting window, so there is no need for it to also
+                        // be doing its own stuff.
+                        if (mAnimation != null) {
+                            mAnimation = null;
+                            // Make sure we clean up the animation.
+                            mAnimating = true;
+                        }
                         mFinishedStarting.add(mAppToken);
                         mH.sendEmptyMessage(H.FINISHED_STARTING);
                     }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4368464..2672c6d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -129,6 +129,8 @@
             return uri.getSchemeSpecificPart();
         }
 
+        // TODO: We don't check for SecurityException here (requires
+        // READ_PHONE_STATE permission).
         if (scheme.equals("voicemail")) {
             return TelephonyManager.getDefault().getVoiceMailNumber();
         }
@@ -1179,6 +1181,35 @@
     }
 
     /**
+     * isVoiceMailNumber: checks a given number against the voicemail
+     *   number provided by the RIL and SIM card. The caller must have
+     *   the READ_PHONE_STATE credential.
+     *
+     * @param number the number to look up.
+     * @return true if the number is in the list of voicemail. False
+     * otherwise, including if the caller does not have the permission
+     * to read the VM number.
+     * @hide TODO: pending API Council approval
+     */
+    public static boolean isVoiceMailNumber(String number) {
+        String vmNumber;
+
+        try {
+            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+        } catch (SecurityException ex) {
+            return false;
+        }
+
+        // Strip the separators from the number before comparing it
+        // to the list.
+        number = extractNetworkPortion(number);
+
+        // compare tolerates null so we need to make sure that we
+        // don't return true when both are null.
+        return !TextUtils.isEmpty(number) && compare(number, vmNumber);
+    }
+
+    /**
      * Translates any alphabetic letters (i.e. [A-Za-z]) in the
      * specified phone number into the equivalent numeric digits,
      * according to the phone keypad letter mapping described in
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index c8490e9..01b1746 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -101,13 +101,12 @@
     public boolean isCachedPhotoCurrent;
 
     private boolean mIsEmergency;
-
-    // Don't keep checking VM if it's going to throw an exception for this proc.
-    private static boolean sSkipVmCheck = false;
+    private boolean mIsVoiceMail;
 
     public CallerInfo() {
         // TODO: Move all the basic initialization here?
         mIsEmergency = false;
+        mIsVoiceMail = false;
     }
 
     /**
@@ -220,32 +219,15 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (TextUtils.isEmpty(number)) {
             return null;
-        } else {
-            // Change the callerInfo number ONLY if it is an emergency number
-            // or if it is the voicemail number.  If it is either, take a
-            // shortcut and skip the query.
-            if (PhoneNumberUtils.isEmergencyNumber(number)) {
-                return new CallerInfo().markAsEmergency(context);
-            } else {
-                try {
-                    if (!sSkipVmCheck && PhoneNumberUtils.compare(number,
-                                TelephonyManager.getDefault().getVoiceMailNumber())) {
-                        CallerInfo ci = new CallerInfo();
+        }
 
-                        // Note we're setting the phone number here (refer to javadoc
-                        // comments at the top of CallerInfo class).
-                        ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag();
-                        // TODO: FIND ANOTHER ICON
-                        //info.photoResource = android.R.drawable.badge_voicemail;
-                        return ci;
-                    }
-                } catch (SecurityException ex) {
-                    // Don't crash if this process doesn't have permission to
-                    // retrieve VM number.  It's still allowed to look up caller info.
-                    // But don't try it again.
-                    sSkipVmCheck = true;
-                }
-            }
+        // Change the callerInfo number ONLY if it is an emergency number
+        // or if it is the voicemail number.  If it is either, take a
+        // shortcut and skip the query.
+        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+            return new CallerInfo().markAsEmergency(context);
+        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+            return new CallerInfo().markAsVoiceMail();
         }
 
         Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
@@ -304,6 +286,13 @@
     }
 
     /**
+     * @return true if the caller info is a voicemail number.
+     */
+    public boolean isVoiceMailNumber() {
+        return mIsVoiceMail;
+    }
+
+    /**
      * Mark this CallerInfo as an emergency call.
      * @param context To lookup the localized 'Emergency Number' string.
      * @return this instance.
@@ -323,6 +312,37 @@
         return this;
     }
 
+
+    /**
+     * Mark this CallerInfo as a voicemail call. The voicemail label
+     * is obtained from the telephony manager. Caller must hold the
+     * READ_PHONE_STATE permission otherwise the phoneNumber will be
+     * set to null.
+     * @return this instance.
+     */
+    // TODO: As in the emergency number handling, we end up writing a
+    // string in the phone number field.
+    /* package */ CallerInfo markAsVoiceMail() {
+        mIsVoiceMail = true;
+
+        try {
+            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+
+            phoneNumber = voiceMailLabel;
+        } catch (SecurityException se) {
+            // Should never happen: if this process does not have
+            // permission to retrieve VM tag, it should not have
+            // permission to retrieve VM number and would not call
+            // this method.
+            // Leave phoneNumber untouched.
+            Log.e(TAG, "Cannot access VoiceMail.", se);
+        }
+        // TODO: There is no voicemail picture?
+        // FIXME: FIND ANOTHER ICON
+        // photoResource = android.R.drawable.badge_voicemail;
+        return this;
+    }
+
     private static String normalize(String s) {
         if (s == null || s.length() > 0) {
             return s;
@@ -330,4 +350,31 @@
             return null;
         }
     }
+
+    /**
+     * @return a string debug representation of this instance.
+     */
+    public String toString() {
+        return new StringBuilder(384)
+                .append("\nname: " + name)
+                .append("\nphoneNumber: " + phoneNumber)
+                .append("\ncnapName: " + cnapName)
+                .append("\nnumberPresentation: " + numberPresentation)
+                .append("\nnamePresentation: " + namePresentation)
+                .append("\ncontactExits: " + contactExists)
+                .append("\nphoneLabel: " + phoneLabel)
+                .append("\nnumberType: " + numberType)
+                .append("\nnumberLabel: " + numberLabel)
+                .append("\nphotoResource: " + photoResource)
+                .append("\nperson_id: " + person_id)
+                .append("\nneedUpdate: " + needUpdate)
+                .append("\ncontactRefUri: " + contactRefUri)
+                .append("\ncontactRingtoneUri: " + contactRefUri)
+                .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+                .append("\ncachedPhoto: " + cachedPhoto)
+                .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+                .append("\nemergency: " + mIsEmergency)
+                .append("\nvoicemail " + mIsVoiceMail)
+                .toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 4227a84..802e79b 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -47,9 +47,6 @@
 
     private CallerInfoAsyncQueryHandler mHandler;
 
-    // Don't keep checking VM if it's going to throw an exception for this proc.
-    private static boolean sSkipVmCheck = false;
-
     /**
      * Interface for a CallerInfoAsyncQueryHandler result return.
      */
@@ -227,18 +224,7 @@
                     // comments at the top of CallerInfo class).
                     mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
                 } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
-                    mCallerInfo = new CallerInfo();
-                    try {
-                        // Note we're setting the phone number here (refer to javadoc
-                        // comments at the top of CallerInfo class).
-                        mCallerInfo.phoneNumber =
-                                TelephonyManager.getDefault().getVoiceMailAlphaTag();
-                    } catch (SecurityException ex) {
-                        // Should never happen: if this process does not have
-                        // permission to retrieve VM tag, it should not have
-                        // permission to retrieve VM number and would not generate
-                        // an EVENT_VOICEMAIL_NUMBER.  But if it happens, don't crash.
-                    }
+                    mCallerInfo = new CallerInfo().markAsVoiceMail();
                 } else {
                     mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
                     // Use the number entered by the user for display.
@@ -258,7 +244,7 @@
             //notify the listener that the query is complete.
             if (cw.listener != null) {
                 if (DBG) log("notifying listener: " + cw.listener.getClass().toString() +
-                        " for token: " + token);
+                             " for token: " + token + mCallerInfo);
                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
             }
         }
@@ -315,23 +301,10 @@
         // check to see if these are recognized numbers, and use shortcuts if we can.
         if (PhoneNumberUtils.isEmergencyNumber(number)) {
             cw.event = EVENT_EMERGENCY_NUMBER;
+        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+            cw.event = EVENT_VOICEMAIL_NUMBER;
         } else {
-            String vmNumber = null;
-            if (!sSkipVmCheck){
-                try {
-                    vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
-                } catch (SecurityException ex) {
-                    // Don't crash if this process doesn't have permission to
-                    // retrieve VM number.  It's still allowed to look up caller info.
-                    // But don't try it again.
-                    sSkipVmCheck = true;
-                }
-            }
-            if (PhoneNumberUtils.compare(number, vmNumber)) {
-                cw.event = EVENT_VOICEMAIL_NUMBER;
-            } else {
-                cw.event = EVENT_NEW_QUERY;
-            }
+            cw.event = EVENT_NEW_QUERY;
         }
 
         c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml
index c0cc0d5..b2a481b 100644
--- a/telephony/tests/TelephonyTest/AndroidManifest.xml
+++ b/telephony/tests/TelephonyTest/AndroidManifest.xml
@@ -28,8 +28,9 @@
             </intent-filter>
         </activity>
     </application>
-     <instrumentation android:name=".TelephonyUnitTestRunner"
-         android:targetPackage="com.android.telephonytest"
-         android:label="Telephony unit tests InstrumentationRunner">
-     </instrumentation>
+    <instrumentation android:name=".TelephonyUnitTestRunner"
+        android:targetPackage="com.android.telephonytest"
+        android:label="Telephony unit tests InstrumentationRunner">
+    </instrumentation>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 </manifest>
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
index 5da940d..9e1af31 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
@@ -37,6 +37,7 @@
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
         suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
+        suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class);
         return suite;
     }
 
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
index 4cd0266..0f24f15 100644
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
@@ -107,6 +107,16 @@
         assertIsValidEmergencyCallerInfo();
     }
 
+    // TODO: Add more tests:
+    /**
+     * Check if the voice mail number cannot be retrieved that the
+     * original phone number is preserved.
+     */
+    /**
+     * Check the markAs* methods work.
+     */
+
+
     //
     // Helpers
     //
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
new file mode 100644
index 0000000..2d3c548
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+
+/*
+ * Check the PhoneNumberUtils utility class works as expected.
+ *
+ */
+
+public class PhoneNumberUtilsUnitTest extends AndroidTestCase {
+    private String mVoiceMailNumber;
+    private static final String TAG = "PhoneNumberUtilsUnitTest";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // FIXME: Why are we getting a security exception here? The
+        // permission is declared in the manifest....
+        // mVoiceMailNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Basic checks for the VoiceMail number.
+     * Assumes READ_PHONE_STATE permission and we don't have it.
+     */
+    // TODO: Figure out why we don't have the permission declared in the manifest.
+    @SmallTest
+    public void testWithNumberNotEqualToVoiceMail() throws Exception {
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("911"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
+        // FIXME:
+        // assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+    }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
index c62f94f..f2025c6 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -36,8 +36,11 @@
     public void testHandlerThread() throws Exception {
         HandlerThread th1 =  new HandlerThread("HandlerThreadTest") {
             protected void onLooperPrepared() {
-                mDidSetup = true;
-                mLooperTid = Process.myTid();
+                synchronized (HandlerThreadTest.this) {
+                    mDidSetup = true;
+                    mLooperTid = Process.myTid();
+                    HandlerThreadTest.this.notify();
+                }
             }
         };
         
@@ -49,14 +52,23 @@
         assertTrue(th1.isAlive());
         assertNotNull(th1.getLooper());
        
-        /* 
-         * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
-         * that mDidSetup and mLooperTid will have been initalized. If they have not, then 
-         * this test should fail
-         */
+        // The call to getLooper() internally blocks until the looper is
+        // available, but will call onLooperPrepared() after that.  So we
+        // need to block here to wait for our onLooperPrepared() to complete
+        // and fill in the values we expect.
+        synchronized (this) {
+            while (!mDidSetup) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        
+        // Make sure that the process was set.
+        assertNotSame(-1, mLooperTid);
         // Make sure that the onLooperPrepared() was called on a different thread.
         assertNotSame(Process.myTid(), mLooperTid);
-        assertTrue(mDidSetup);
         
         final Handler h1 = new Handler(th1.getLooper()) {
             public void handleMessage(Message msg) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 8fea967..395e572 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -96,7 +96,9 @@
         // Android layout tests are stored in "layout_tests". The following two
         // tests expect "LayoutTests" in their output.
         "storage/domstorage/localstorage/iframe-events.html",
-        "storage/domstorage/sessionstorage/iframe-events.html"
+        "storage/domstorage/sessionstorage/iframe-events.html",
+        // below tests (failed or crashes) are filtered out temporarily due to prioritizing
+        "editing/selection/move-left-right.html",
     };
     
     static void fillIgnoreResultSet() {
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
index dc959f5..aea124b 100644
--- a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -29,7 +29,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Set;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -145,7 +144,7 @@
                 public Cursor query(Uri uri, String[] projection, String selection,
                         String[] selectionArgs, String sortOrder) {
                     // Return cursor over specific set of values
-                    return getCursor(sTestValues1);
+                    return getCursor(sTestValues1, 1);
                 }
             }, null, 0);
         } catch (OperationApplicationException e) {
@@ -153,11 +152,62 @@
         }
     }
 
+    public void testAssertNoValues() {
+        // Build an operation to assert values match provider
+        ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(1).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op1.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 1);
+                }
+            }, null, 0);
+        } catch (OperationApplicationException e) {
+            fail("newAssert() failed");
+        }
+
+        ContentProviderOperation op2 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(0).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op2.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 0);
+                }
+            }, null, 0);
+        } catch (OperationApplicationException e) {
+            fail("newAssert() failed");
+        }
+
+        ContentProviderOperation op3 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(2).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op3.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 5);
+                }
+            }, null, 0);
+            fail("we expect the exception to be thrown");
+        } catch (OperationApplicationException e) {
+        }
+    }
+
     /**
      * Build a {@link Cursor} with a single row that contains all values
      * provided through the given {@link ContentValues}.
      */
-    private Cursor getCursor(ContentValues contentValues) {
+    private Cursor getCursor(ContentValues contentValues, int numRows) {
         final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
         final String[] keys = new String[valueSet.size()];
         final Object[] values = new Object[valueSet.size()];
@@ -170,7 +220,9 @@
         }
 
         final MatrixCursor cursor = new MatrixCursor(keys);
-        cursor.addRow(values);
+        for (i = 0; i < numRows; i++) {
+            cursor.addRow(values);
+        }
         return cursor;
     }