Merge change 23300 into eclair

* changes:
  Add a synchronous stop method to TTS synth engine so that upon its destruction, if it was synthesing to a file, the latter can be deleted without still being written to. Clear the hashmap of SpeechItem to be stopped (mKillList) when the speech queue is empty.
diff --git a/Android.mk b/Android.mk
index d348a52..97f012c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -358,6 +358,8 @@
 		            guide/samples/LunarLander "Lunar Lander" \
 		-samplecode $(sample_dir)/NotePad \
 		            guide/samples/NotePad "Note Pad" \
+		-samplecode $(sample_dir)/SearchableDictionary \
+		            guide/samples/SearchableDictionary "Searchable Dictionary" \
 		-samplecode $(sample_dir)/Snake \
 		            guide/samples/Snake "Snake" \
 		-samplecode $(sample_dir)/SoftKeyboard \
diff --git a/api/current.xml b/api/current.xml
index 403a961..3e616a4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27066,6 +27066,17 @@
  visibility="public"
 >
 </method>
+<method name="isYieldAllowed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="newAssertQuery"
  return="android.content.ContentProviderOperation.Builder"
  abstract="false"
@@ -27292,6 +27303,19 @@
 <parameter name="values" type="android.content.ContentValues">
 </parameter>
 </method>
+<method name="withYieldAllowed"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="yieldAllowed" type="boolean">
+</parameter>
+</method>
 </class>
 <class name="ContentProviderResult"
  extends="java.lang.Object"
@@ -35833,6 +35857,39 @@
 <parameter name="cause" type="java.lang.Throwable">
 </parameter>
 </constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="numSuccessfulYieldPoints" type="int">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="numSuccessfulYieldPoints" type="int">
+</parameter>
+</constructor>
+<method name="getNumSuccessfulYieldPoints"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="ReceiverCallNotAllowedException"
  extends="android.util.AndroidRuntimeException"
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 7741668..4d1e254 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.app.IWallpaperManagerCallback;
 import android.content.ComponentName;
@@ -36,7 +37,8 @@
     /**
      * Get the wallpaper.
      */
-    ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb);
+    ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+            out Bundle outParams);
     
     /**
      * Clear the wallpaper.
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index b365d00..7e6efec 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -251,7 +251,7 @@
  * 
  * <p>Once an application is configured to provide search suggestions, those same suggestions can
  * easily be made available to the system-wide Quick Search Box, providing faster access to its
- * content from on central prominent place. See
+ * content from one central prominent place. See
  * <a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to Quick Search
  * Box</a> for more details.
  * 
@@ -505,7 +505,7 @@
  *
  *     <tr><th>{@link #SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</th>
  *         <td>This column is used to specify that a spinner should be shown in lieu of an icon2
- *             while the shortcut of this suggestion is being refreshed.</td>
+ *             while the shortcut of this suggestion is being refreshed in Quick Search Box.</td>
  *         <td align="center">No.  Only applicable to sources included in Quick Search Box.</td>
  *     </tr>
  * 
@@ -585,39 +585,45 @@
  * <a name="ExposingSearchSuggestionsToQuickSearchBox"></a>
  * <h3>Exposing Search Suggestions to Quick Search Box</h3>
  * 
- * <p>Once your application is setup to provide search suggestions, making them available to the
+ * <p>Once your application is set up to provide search suggestions, making them available to the
  * globally accessable Quick Search Box is as easy as setting android:includeInGlobalSearch to
  * "true" in your searchable metadata file.  Beyond that, here are some more details of how
  * suggestions interact with Quick Search Box, and optional ways that you may customize suggestions
  * for your application.
+ * 
+ * <p><b>Important Note:</b>  By default, your application will not be enabled as a suggestion
+ * provider (or "searchable item") in Quick Search Box. Once your app is installed, the user must
+ * enable it as a "searchable item" in the Search settings in order to receive your app's
+ * suggestions in Quick Search Box. You should consider how to message this to users of your app -
+ * perhaps with a note to the user the first time they launch the app about how to enable search
+ * suggestions. This gives your app a chance to be queried for suggestions as the user types into
+ * Quick Search Box, though exactly how or if your suggestions will be surfaced is decided by Quick
+ * Search Box.
  *
  * <p><b>Source Ranking:</b>  Once your application's search results are made available to Quick
- * Search Box, how they surface to the user for a particular query will depend on how many
- * other apps have results for that query, and how often the user has clicked on your results
- * compared to the other apps'.  The apps with the best track record within Quick Search
- * Box will get queried earlier and have a better chance of showing their results in the top few
- * slots.  If there are more results than can be displayed to the user within a screen or two, the
- * results may spill into a "more results" section that groups the remaining results by
- * source.  The newest apps with little usage information are given middle of the road positioning
- * until enough usage information is available to rank it as usual.  The exact formula for ranking
- * the results is not set in stone, but suffice it is to say that providing quality results will
- * increase the likelihood that your app's suggestions are provided in a prominent position, and
- * apps that provide lower quality suggestions will be more likely to be pushed into the spillover
- * area.
+ * Search Box, how they surface to the user for a particular query will be determined as appropriate
+ * by Quick Search Box ranking. This may depend on how many other apps have results for that query,
+ * and how often the user has clicked on your results compared to the other apps - but there is no
+ * guarantee about how ranking will occur, or whether your app's suggestions will show at all for
+ * a given query.  In general, you can expect that providing quality results will increase the
+ * likelihood that your app's suggestions are provided in a prominent position, and apps that
+ * provide lower quality suggestions will be more likely to be ranked lower and/or not displayed.
  *
  * <p><b>Search Settings:</b>  Each app that is available to Quick Search Box has an entry in the
  * system settings where the user can enable or disable the inclusion of its results.  Below the
  * name of the application, each application may provide a brief description of what kind of
  * information will be made available via a search settings description string pointed to by the
- * android:searchSettingsDescription attribute in the searchable metadata.
+ * android:searchSettingsDescription attribute in the searchable metadata. Note that the
+ * user will need to visit this settings menu to enable search suggestions for your app before your
+ * app will have a chance to provide search suggestions to Quick Search Box - see the section
+ * called "Important Note" above.
  *
- * <p><b>Shortcuts:</b>  Suggestions that are clicked on by the user are automatically made into
- * shortcuts, or, copied so they can quickly be displayed to the user before querying any of
- * the sources. Thereafter, the shortcutted suggestion will be displayed for the query that yielded
- * the suggestion and for any prefixes of that query.  When multiple shortcuts are made available
- * for a given query, they are ranked based on recency and the number of clicks they have received.
- * You can control how your suggestions are made into shortcuts, and whether they are refreshed,
- * using the {@link #SUGGEST_COLUMN_SHORTCUT_ID} column:
+ * <p><b>Shortcuts:</b>  Suggestions that are clicked on by the user may be automatically made into
+ * shortcuts, which are suggestions that have been copied from your provider in order to be quickly
+ * displayed without the need to re-query the original sources. Shortcutted suggestions may be
+ * displayed for the query that yielded the suggestion and for any prefixes of that query. You can
+ * request how to have your app's suggestions made into shortcuts, and whether they should be
+ * refreshed, using the {@link #SUGGEST_COLUMN_SHORTCUT_ID} column:
  * <ul><li>Suggestions that do not include a shortcut id column will be made into shortcuts and
  * never refreshed.  This makes sense for suggestions that refer to data that will never be changed
  * or removed.</li>
@@ -635,6 +641,9 @@
  * <li>Finally, to prevent a suggestion from being copied into a shortcut, you may provide a
  * shortcut id with a value of {@link #SUGGEST_NEVER_MAKE_SHORTCUT}.</li></ul>
  * 
+ * Note that Quick Search Box will ultimately decide whether to shortcut your app's suggestions,
+ * considering these values as a strong request from your application.
+ * 
  * <a name="ActionKeys"></a>
  * <h3>Action Keys</h3>
  * 
@@ -807,7 +816,12 @@
  *                         and editing.</td>
  *                 </tr>
  *                 </tbody>
- *            </table></td>
+ *            </table>
+ *            Note that the icon of your app will likely be shown alongside any badge you specify,
+ *            to differentiate search in your app from Quick Search Box. The display of this icon
+ *            is not under the app's control.
+ *         </td>
+ *            
  *         <td align="center">No</td>
  *     </tr>
  *     
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c5ca0a3..7669306 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -21,13 +21,18 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.ViewRoot;
 
@@ -51,7 +56,7 @@
     
     static class Globals extends IWallpaperManagerCallback.Stub {
         private IWallpaperManager mService;
-        private Drawable mWallpaper;
+        private Bitmap mWallpaper;
         
         Globals() {
             IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
@@ -69,7 +74,7 @@
             }
         }
         
-        public Drawable peekWallpaper(Context context) {
+        public Bitmap peekWallpaperBitmap(Context context) {
             synchronized (this) {
                 if (mWallpaper != null) {
                     return mWallpaper;
@@ -79,18 +84,82 @@
             }
         }
         
-        private Drawable getCurrentWallpaperLocked(Context context) {
+        private Bitmap getCurrentWallpaperLocked(Context context) {
             try {
-                ParcelFileDescriptor fd = mService.getWallpaper(this);
+                Bundle params = new Bundle();
+                ParcelFileDescriptor fd = mService.getWallpaper(this, params);
                 if (fd != null) {
-                    Bitmap bm = BitmapFactory.decodeFileDescriptor(
-                            fd.getFileDescriptor(), null, null);
-                    if (bm != null) {
-                        // For now clear the density until we figure out how
-                        // to deal with it for wallpapers.
-                        bm.setDensity(0);
-                        return new BitmapDrawable(context.getResources(), bm);
+                    int width = params.getInt("width", 0);
+                    int height = params.getInt("height", 0);
+                    
+                    if (width <= 0 || height <= 0) {
+                        // Degenerate case: no size requested, just load
+                        // bitmap as-is.
+                        Bitmap bm = BitmapFactory.decodeFileDescriptor(
+                                fd.getFileDescriptor(), null, null);
+                        try {
+                            fd.close();
+                        } catch (IOException e) {
+                        }
+                        if (bm != null) {
+                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                        }
+                        return bm;
                     }
+                    
+                    // Load the bitmap with full color depth, to preserve
+                    // quality for later processing.
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    options.inDither = false;
+                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                    Bitmap bm = BitmapFactory.decodeFileDescriptor(
+                            fd.getFileDescriptor(), null, options);
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                    }
+                    if (bm == null) {
+                        return bm;
+                    }
+                    bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                    
+                    // This is the final bitmap we want to return.
+                    Bitmap newbm = Bitmap.createBitmap(width, height,
+                            bm.getConfig());
+                    newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                    Canvas c = new Canvas(newbm);
+                    c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+                    Rect targetRect = new Rect();
+                    targetRect.left = targetRect.top = 0;
+                    targetRect.right = bm.getWidth();
+                    targetRect.bottom = bm.getHeight();
+                    
+                    int deltaw = width - targetRect.right;
+                    int deltah = height - targetRect.bottom;
+                    
+                    if (deltaw > 0 || deltah > 0) {
+                        // We need to scale up so it covers the entire
+                        // area.
+                        float scale = 1.0f;
+                        if (deltaw > deltah) {
+                            scale = width / (float)targetRect.right;
+                        } else {
+                            scale = height / (float)targetRect.bottom;
+                        }
+                        targetRect.right = (int)(targetRect.right*scale);
+                        targetRect.bottom = (int)(targetRect.bottom*scale);
+                        deltaw = width - targetRect.right;
+                        deltah = height - targetRect.bottom;
+                    }
+                    
+                    targetRect.offset(deltaw/2, deltah/2);
+                    Paint paint = new Paint();
+                    paint.setFilterBitmap(true);
+                    paint.setDither(true);
+                    c.drawBitmap(bm, null, targetRect, paint);
+                    
+                    bm.recycle();
+                    return newbm;
                 }
             } catch (RemoteException e) {
             }
@@ -149,7 +218,8 @@
      * null pointer if these is none.
      */
     public Drawable peekDrawable() {
-        return getGlobals().peekWallpaper(mContext);
+        Bitmap bm = getGlobals().peekWallpaperBitmap(mContext);
+        return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
     }
 
     /**
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 1edcb0a..d17775e 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -111,7 +111,8 @@
                 if (mSyncThread != null
                         && mSyncThread.mSyncContext.getISyncContext().asBinder()
                         == syncContext.asBinder()) {
-                    mSyncThread.interrupt();
+                    // TODO: figure out why canceling causes a hang
+//                    mSyncThread.interrupt();
                 }
             }
         }
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index f5a4b75..238792b 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -44,6 +44,7 @@
     private final Integer mExpectedCount;
     private final ContentValues mValuesBackReferences;
     private final Map<Integer, Integer> mSelectionArgsBackReferences;
+    private final boolean mYieldAllowed;
 
     /**
      * Creates a {@link ContentProviderOperation} by copying the contents of a
@@ -58,6 +59,7 @@
         mExpectedCount = builder.mExpectedCount;
         mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
         mValuesBackReferences = builder.mValuesBackReferences;
+        mYieldAllowed = builder.mYieldAllowed;
     }
 
     private ContentProviderOperation(Parcel source) {
@@ -68,7 +70,6 @@
         mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
         mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
         mValuesBackReferences = source.readInt() != 0
-
                 ? ContentValues.CREATOR.createFromParcel(source)
                 : null;
         mSelectionArgsBackReferences = source.readInt() != 0
@@ -80,6 +81,7 @@
                 mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
             }
         }
+        mYieldAllowed = source.readInt() != 0;
     }
 
     public void writeToParcel(Parcel dest, int flags) {
@@ -125,6 +127,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeInt(mYieldAllowed ? 1 : 0);
     }
 
     /**
@@ -167,6 +170,10 @@
         return mUri;
     }
 
+    public boolean isYieldAllowed() {
+        return mYieldAllowed;
+    }
+
     /** @hide exposed for unit tests */
     public int getType() {
         return mType;
@@ -375,6 +382,7 @@
         private Integer mExpectedCount;
         private ContentValues mValuesBackReferences;
         private Map<Integer, Integer> mSelectionArgsBackReferences;
+        private boolean mYieldAllowed;
 
         /** Create a {@link Builder} of a given type. The uri must not be null. */
         private Builder(int type, Uri uri) {
@@ -544,5 +552,10 @@
             mExpectedCount = count;
             return this;
         }
+
+        public Builder withYieldAllowed(boolean yieldAllowed) {
+            mYieldAllowed = yieldAllowed;
+            return this;
+        }
     }
 }
diff --git a/core/java/android/content/OperationApplicationException.java b/core/java/android/content/OperationApplicationException.java
index d4101bf..2fc19bb 100644
--- a/core/java/android/content/OperationApplicationException.java
+++ b/core/java/android/content/OperationApplicationException.java
@@ -21,16 +21,34 @@
  * constraints.
  */
 public class OperationApplicationException extends Exception {
+    private final int mNumSuccessfulYieldPoints;
+
     public OperationApplicationException() {
         super();
+        mNumSuccessfulYieldPoints = 0;
     }
     public OperationApplicationException(String message) {
         super(message);
+        mNumSuccessfulYieldPoints = 0;
     }
     public OperationApplicationException(String message, Throwable cause) {
         super(message, cause);
+        mNumSuccessfulYieldPoints = 0;
     }
     public OperationApplicationException(Throwable cause) {
         super(cause);
+        mNumSuccessfulYieldPoints = 0;
+    }
+    public OperationApplicationException(int numSuccessfulYieldPoints) {
+        super();
+        mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+    }
+    public OperationApplicationException(String message, int numSuccessfulYieldPoints) {
+        super(message);
+        mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+    }
+
+    public int getNumSuccessfulYieldPoints() {
+        return mNumSuccessfulYieldPoints;
     }
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d4a4c11..e48f539 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -20,6 +20,7 @@
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -215,6 +216,12 @@
          * <P>Type: INTEGER</P>
          */
         public static final String HAS_PHONE_NUMBER = "has_phone_number";
+
+        /**
+         * An opaque value that contains hints on how to find the contact if
+         * its row id changed as a result of a sync or aggregation.
+         */
+        public static final String LOOKUP_KEY = "lookup";
     }
 
     /**
@@ -234,6 +241,54 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
 
         /**
+         * A content:// style URI for this table that should be used to create
+         * shortcuts or otherwise create long-term links to contacts. This URI
+         * should always be followed by a "/" and the contact's {@link #LOOKUP_KEY}.
+         * It can optionally also have a "/" and last known contact ID appended after
+         * that. This "complete" format is an important optimization and is highly recommended.
+         * <p>
+         * As long as the contact's row ID remains the same, this URI is
+         * equivalent to {@link #CONTENT_URI}. If the contact's row ID changes
+         * as a result of a sync or aggregation, this URI will look up the
+         * contact using indirect information (sync IDs or constituent raw
+         * contacts).
+         * <p>
+         * Lookup key should be appended unencoded - it is stored in the encoded
+         * form, ready for use in a URI.
+         */
+        public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
+                "lookup");
+
+        /**
+         * Computes a complete lookup URI (see {@link #CONTENT_LOOKUP_URI}).
+         * Pass either a basic content URI with a contact ID to obtain an
+         * equivalent lookup URI. Pass a possibly stale lookup URI to get a fresh
+         * lookup URI for the same contact.
+         * <p>
+         * Returns null if the contact cannot be found.
+         */
+        public static Uri getLookupUri(ContentResolver resolver, Uri contentUri) {
+            Cursor c = resolver.query(contentUri,
+                    new String[]{Contacts.LOOKUP_KEY, Contacts._ID}, null, null, null);
+            if (c == null) {
+                return null;
+            }
+
+            try {
+                if (c.moveToFirst()) {
+                    String lookupKey = c.getString(0);
+                    long contactId = c.getLong(1);
+                    return ContentUris.withAppendedId(
+                            Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
+                            contactId);
+                }
+            } finally {
+                c.close();
+            }
+            return null;
+        }
+
+        /**
          * The content:// style URI for this table joined with useful data from
          * {@link Data}.
          *
@@ -1042,6 +1097,7 @@
             public static final int TYPE_HOME = 1;
             public static final int TYPE_WORK = 2;
             public static final int TYPE_OTHER = 3;
+            public static final int TYPE_MOBILE = 4;
 
             /**
              * The display name for the email address
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
index 9586e34..bbd9dde 100644
--- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -20,5 +20,7 @@
  * @hide
  */
 oneway interface IWallpaperEngine {
+    void setDesiredSize(int width, int height);
+    void setVisibility(boolean visible);
 	void destroy();
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 629e97e..2cdfc66 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -55,6 +55,7 @@
     
     private static final int DO_ATTACH = 10;
     private static final int DO_DETACH = 20;
+    private static final int DO_SET_DESIRED_SIZE = 30;
     
     private static final int MSG_UPDATE_SURFACE = 10000;
     private static final int MSG_VISIBILITY_CHANGED = 10010;
@@ -78,6 +79,8 @@
         IBinder mWindowToken;
         
         boolean mInitializing = true;
+        boolean mVisible;
+        boolean mDestroyed;
         
         // Current window state.
         boolean mCreated;
@@ -129,8 +132,15 @@
                 return mIsCreating;
             }
 
+            @Override
+            public void setFixedSize(int width, int height) {
+                throw new UnsupportedOperationException(
+                        "Wallpapers currently only support sizing from layout");
+            }
+            
             public void setKeepScreenOn(boolean screenOn) {
-                // Ignore.
+                throw new UnsupportedOperationException(
+                        "Wallpapers do not support keep screen on");
             }
             
         };
@@ -166,9 +176,13 @@
             
             @Override
             public void dispatchAppVisibility(boolean visible) {
-                Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
-                        visible ? 1 : 0);
-                mCaller.sendMessage(msg);
+                // We don't do this in preview mode; we'll let the preview
+                // activity tell us when to run.
+                if (!mIWallpaperEngine.mIsPreview) {
+                    Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+                            visible ? 1 : 0);
+                    mCaller.sendMessage(msg);
+                }
             }
 
             @Override
@@ -212,6 +226,15 @@
         }
         
         /**
+         * Return whether the wallpaper is currently visible to the user,
+         * this is the last value supplied to
+         * {@link #onVisibilityChanged(boolean)}.
+         */
+        public boolean isVisible() {
+            return mVisible;
+        }
+        
+        /**
          * Returns true if this engine is running in preview mode -- that is,
          * it is being shown to the user before they select it as the actual
          * wallpaper.
@@ -280,6 +303,13 @@
         }
         
         /**
+         * Called when an application has changed the desired virtual size of
+         * the wallpaper.
+         */
+        public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+        }
+        
+        /**
          * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
          * SurfaceHolder.Callback.surfaceChanged()}.
          */
@@ -301,6 +331,10 @@
         }
 
         void updateSurface(boolean forceRelayout, boolean forceReport) {
+            if (mDestroyed) {
+                Log.w(TAG, "Ignoring updateSurface: destroyed");
+            }
+            
             int myWidth = mSurfaceHolder.getRequestedWidth();
             if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
             int myHeight = mSurfaceHolder.getRequestedHeight();
@@ -314,7 +348,7 @@
             if (forceRelayout || creating || formatChanged || sizeChanged
                     || typeChanged || flagsChanged) {
 
-                if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+                if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
                         + " format=" + formatChanged + " size=" + sizeChanged);
 
                 try {
@@ -343,6 +377,8 @@
                     if (!mCreated) {
                         mLayout.type = mIWallpaperEngine.mWindowType;
                         mLayout.gravity = Gravity.LEFT|Gravity.TOP;
+                        mLayout.windowAnimations =
+                                com.android.internal.R.style.Animation_Wallpaper;
                         mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
                     }
                     
@@ -354,7 +390,7 @@
                             View.VISIBLE, false, mWinFrame, mContentInsets,
                             mVisibleInsets, mSurfaceHolder.mSurface);
 
-                    if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+                    if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
                     
                     int w = mWinFrame.width();
@@ -384,6 +420,8 @@
 
                         if (!mCreated) {
                             mIsCreating = true;
+                            if (DEBUG) Log.v(TAG, "onSurfaceCreated("
+                                    + mSurfaceHolder + "): " + this);
                             onSurfaceCreated(mSurfaceHolder);
                             if (callbacks != null) {
                                 for (SurfaceHolder.Callback c : callbacks) {
@@ -399,6 +437,10 @@
                                         + " formatChanged=" + formatChanged
                                         + " sizeChanged=" + sizeChanged, e);
                             }
+                            if (DEBUG) Log.v(TAG, "onSurfaceChanged("
+                                    + mSurfaceHolder + ", " + mFormat
+                                    + ", " + mCurWidth + ", " + mCurHeight
+                                    + "): " + this);
                             onSurfaceChanged(mSurfaceHolder, mFormat,
                                     mCurWidth, mCurHeight);
                             if (callbacks != null) {
@@ -425,26 +467,73 @@
         
         void attach(IWallpaperEngineWrapper wrapper) {
             if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
+            if (mDestroyed) {
+                return;
+            }
+            
             mIWallpaperEngine = wrapper;
             mCaller = wrapper.mCaller;
             mConnection = wrapper.mConnection;
             mWindowToken = wrapper.mWindowToken;
-            // XXX temp -- should run in size from layout (screen) mode.
-            mSurfaceHolder.setFixedSize(mIWallpaperEngine.mReqWidth,
-                    mIWallpaperEngine.mReqHeight);
-            //mSurfaceHolder.setSizeFromLayout();
+            mSurfaceHolder.setSizeFromLayout();
             mInitializing = true;
             mSession = ViewRoot.getWindowSession(getMainLooper());
             mWindow.setSession(mSession);
             
+            if (DEBUG) Log.v(TAG, "onCreate(): " + this);
             onCreate(mSurfaceHolder);
             
             mInitializing = false;
             updateSurface(false, false);
         }
         
+        void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+            if (!mDestroyed) {
+                if (DEBUG) Log.v(TAG, "onDesiredSizeChanged("
+                        + desiredWidth + "," + desiredHeight + "): " + this);
+                onDesiredSizeChanged(desiredWidth, desiredHeight);
+            }
+        }
+        
+        void doVisibilityChanged(boolean visible) {
+            if (!mDestroyed) {
+                mVisible = visible;
+                if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
+                        + "): " + this);
+                onVisibilityChanged(visible);
+            }
+        }
+        
+        void doOffsetsChanged() {
+            if (mDestroyed) {
+                return;
+            }
+            
+            float xOffset;
+            float yOffset;
+            synchronized (mLock) {
+                xOffset = mPendingXOffset;
+                yOffset = mPendingYOffset;
+                mOffsetMessageEnqueued = false;
+            }
+            if (DEBUG) Log.v(TAG, "Offsets change in " + this
+                    + ": " + xOffset + "," + yOffset);
+            final int availw = mIWallpaperEngine.mReqWidth-mCurWidth;
+            final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
+            final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
+            final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
+            onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+        }
+        
         void detach() {
-            onDestroy();
+            mDestroyed = true;
+            
+            if (mVisible) {
+                mVisible = false;
+                if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this);
+                onVisibilityChanged(false);
+            }
+            
             if (mDestroyReportNeeded) {
                 mDestroyReportNeeded = false;
                 SurfaceHolder.Callback callbacks[];
@@ -456,7 +545,14 @@
                 for (SurfaceHolder.Callback c : callbacks) {
                     c.surfaceDestroyed(mSurfaceHolder);
                 }
+                if (DEBUG) Log.v(TAG, "onSurfaceDestroyed("
+                        + mSurfaceHolder + "): " + this);
+                onSurfaceDestroyed(mSurfaceHolder);
             }
+            
+            if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
+            onDestroy();
+            
             if (mCreated) {
                 try {
                     mSession.remove(mWindow);
@@ -492,16 +588,21 @@
             mReqWidth = reqWidth;
             mReqHeight = reqHeight;
             
-            try {
-                conn.attachEngine(this);
-            } catch (RemoteException e) {
-                destroy();
-            }
-            
             Message msg = mCaller.obtainMessage(DO_ATTACH);
             mCaller.sendMessage(msg);
         }
         
+        public void setDesiredSize(int width, int height) {
+            Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height);
+            mCaller.sendMessage(msg);
+        }
+        
+        public void setVisibility(boolean visible) {
+            Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+                    visible ? 1 : 0);
+            mCaller.sendMessage(msg);
+        }
+
         public void destroy() {
             Message msg = mCaller.obtainMessage(DO_DETACH);
             mCaller.sendMessage(msg);
@@ -510,6 +611,12 @@
         public void executeMessage(Message message) {
             switch (message.what) {
                 case DO_ATTACH: {
+                    try {
+                        mConnection.attachEngine(this);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Wallpaper host disappeared", e);
+                        return;
+                    }
                     Engine engine = onCreateEngine();
                     mEngine = engine;
                     engine.attach(this);
@@ -519,29 +626,20 @@
                     mEngine.detach();
                     return;
                 }
+                case DO_SET_DESIRED_SIZE: {
+                    mEngine.doDesiredSizeChanged(message.arg1, message.arg2);
+                    return;
+                }
                 case MSG_UPDATE_SURFACE:
                     mEngine.updateSurface(true, false);
                     break;
                 case MSG_VISIBILITY_CHANGED:
                     if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
                             + ": " + message.arg1);
-                    mEngine.onVisibilityChanged(message.arg1 != 0);
+                    mEngine.doVisibilityChanged(message.arg1 != 0);
                     break;
                 case MSG_WALLPAPER_OFFSETS: {
-                    float xOffset;
-                    float yOffset;
-                    synchronized (mEngine.mLock) {
-                        xOffset = mEngine.mPendingXOffset;
-                        yOffset = mEngine.mPendingYOffset;
-                        mEngine.mOffsetMessageEnqueued = false;
-                    }
-                    if (DEBUG) Log.v(TAG, "Offsets change in " + mEngine
-                            + ": " + xOffset + "," + yOffset);
-                    final int availw = mReqWidth-mEngine.mCurWidth;
-                    final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
-                    final int availh = mReqHeight-mEngine.mCurHeight;
-                    final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
-                    mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+                    mEngine.doOffsetsChanged();
                 } break;
                 case MSG_WINDOW_RESIZED: {
                     final boolean reportDraw = message.arg1 != 0;
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index c4eb31f..5357469 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -33,52 +33,50 @@
  */
 public class ImageWallpaper extends WallpaperService {
     WallpaperManager mWallpaperManager;
-    ImageWallpaper.DrawableEngine mEngine;
-    private WallpaperObserver mReceiver;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
-        IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
-        mReceiver = new WallpaperObserver();
-        registerReceiver(mReceiver, filter);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        unregisterReceiver(mReceiver);
     }
 
     public Engine onCreateEngine() {
-        mEngine = new DrawableEngine();
-        return mEngine;
-    }
-
-    class WallpaperObserver extends BroadcastReceiver {
-        public void onReceive(Context context, Intent intent) {
-            mEngine.updateWallpaper();
-            mEngine.drawFrame();
-        }
+        return new DrawableEngine();
     }
 
     class DrawableEngine extends Engine {
         private final Object mLock = new Object();
         private final Rect mBounds = new Rect();
+        private WallpaperObserver mReceiver;
         Drawable mBackground;
         float mXOffset;
         float mYOffset;
 
+        class WallpaperObserver extends BroadcastReceiver {
+            public void onReceive(Context context, Intent intent) {
+                updateWallpaper();
+                drawFrame();
+            }
+        }
+
         @Override
         public void onCreate(SurfaceHolder surfaceHolder) {
             super.onCreate(surfaceHolder);
+            IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+            mReceiver = new WallpaperObserver();
+            registerReceiver(mReceiver, filter);
             updateWallpaper();
             surfaceHolder.setSizeFromLayout();
             //setTouchEventsEnabled(true);
         }
 
         @Override
+        public void onDestroy() {
+            super.onDestroy();
+            unregisterReceiver(mReceiver);
+        }
+
+        @Override
         public void onVisibilityChanged(boolean visible) {
             drawFrame();
         }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f789dd..1ea5fa3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -898,7 +898,7 @@
     <permission android:name="android.permission.BIND_WALLPAPER"
         android:label="@string/permlab_bindWallpaper"
         android:description="@string/permdesc_bindWallpaper"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.  Not for use by normal applications. -->
diff --git a/core/res/res/anim/wallpaper_activity_close_enter.xml b/core/res/res/anim/wallpaper_activity_close_enter.xml
index fc6e332..9e9bd80 100644
--- a/core/res/res/anim/wallpaper_activity_close_enter.xml
+++ b/core/res/res/anim/wallpaper_activity_close_enter.xml
@@ -27,4 +27,6 @@
            android:duration="@android:integer/config_mediumAnimTime" />
 	<translate android:fromXDelta="-150%" android:toXDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/wallpaper_activity_close_exit.xml b/core/res/res/anim/wallpaper_activity_close_exit.xml
index edd00fd..badbbf0 100644
--- a/core/res/res/anim/wallpaper_activity_close_exit.xml
+++ b/core/res/res/anim/wallpaper_activity_close_exit.xml
@@ -26,4 +26,6 @@
            android:duration="@android:integer/config_mediumAnimTime" />
 	<translate android:fromXDelta="0%" android:toXDelta="100%"
         android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/wallpaper_activity_open_enter.xml b/core/res/res/anim/wallpaper_activity_open_enter.xml
index 5b44d97..e60bac2 100644
--- a/core/res/res/anim/wallpaper_activity_open_enter.xml
+++ b/core/res/res/anim/wallpaper_activity_open_enter.xml
@@ -26,4 +26,6 @@
            android:duration="@android:integer/config_mediumAnimTime" />
     <translate android:fromXDelta="100%" android:toXDelta="0"
             android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/wallpaper_activity_open_exit.xml b/core/res/res/anim/wallpaper_activity_open_exit.xml
index fa39bee..01abbb7 100644
--- a/core/res/res/anim/wallpaper_activity_open_exit.xml
+++ b/core/res/res/anim/wallpaper_activity_open_exit.xml
@@ -27,4 +27,6 @@
            android:duration="@android:integer/config_mediumAnimTime" />
     <translate android:fromXDelta="0" android:toXDelta="-150%"
             android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/wallpaper_enter.xml b/core/res/res/anim/wallpaper_enter.xml
new file mode 100644
index 0000000..981f5f6
--- /dev/null
+++ b/core/res/res/anim/wallpaper_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+    <scale android:fromXScale="3.0" android:toXScale="1.0"
+           android:fromYScale="3.0" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_longAnimTime" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_longAnimTime" />
+</set>
diff --git a/core/res/res/anim/wallpaper_exit.xml b/core/res/res/anim/wallpaper_exit.xml
new file mode 100644
index 0000000..2306071
--- /dev/null
+++ b/core/res/res/anim/wallpaper_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/accelerate_interpolator">
+    <scale android:fromXScale="1.0" android:toXScale="3.0"
+           android:fromYScale="1.0" android:toYScale="3.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_longAnimTime" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="@android:integer/config_longAnimTime"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default.png b/core/res/res/drawable-hdpi/btn_code_lock_default.png
index 9f44d0f..df3137f 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
index a4cc5bf..bf9e46a 100644
--- a/core/res/res/drawable-hdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 86e6139..abb575c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -64,4 +64,21 @@
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->
     <bool name="config_bypass_keyguard_if_slider_open">true</bool>
+    
+    <!-- Vibrator pattern for feedback about a long screen/key press -->
+    <integer-array name="config_longPressVibePattern">
+        <item>0</item>
+        <item>1</item>
+        <item>20</item>
+        <item>21</item>
+    </integer-array>
+    
+    <!-- Vibrator pattern for feedback about touching a virtual key -->
+    <integer-array name="config_virtualKeyVibePattern">
+        <item>0</item>
+        <item>10</item>
+        <item>20</item>
+        <item>30</item>
+    </integer-array>
+    
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3950cb1..55f8167 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -160,6 +160,12 @@
         <item name="windowExitAnimation">@anim/fade_out</item>
     </style>
 
+    <!-- Standard animations for wallpapers. -->
+    <style name="Animation.Wallpaper">
+        <item name="windowEnterAnimation">@anim/wallpaper_enter</item>
+        <item name="windowExitAnimation">@anim/wallpaper_exit</item>
+    </style>
+
     <!-- Status Bar Styles -->
 
     <style name="TextAppearance.StatusBarTitle">
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 459ad37..ef1a1ea 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -399,6 +399,9 @@
           <li><a href="<?cs var:toroot ?>guide/samples/NotePad/index.html">
                 <span class="en">Note Pad</span>
               </a></li>
+          <li><a href="<?cs var:toroot ?>guide/samples/SearchableDictionary/index.html">
+                <span class="en">Searchable Dictionary</span>
+              </a></li>
           <li><a href="<?cs var:toroot ?>guide/samples/Snake/index.html">
                 <span class="en">Snake</span>
               </a></li>
diff --git a/docs/html/guide/samples/images/SearchableDictionary1.png b/docs/html/guide/samples/images/SearchableDictionary1.png
new file mode 100644
index 0000000..ebb4604
--- /dev/null
+++ b/docs/html/guide/samples/images/SearchableDictionary1.png
Binary files differ
diff --git a/docs/html/guide/samples/images/SearchableDictionary2.png b/docs/html/guide/samples/images/SearchableDictionary2.png
new file mode 100644
index 0000000..34746cd
--- /dev/null
+++ b/docs/html/guide/samples/images/SearchableDictionary2.png
Binary files differ
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index d8bbc41..6e79d50 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -33,6 +33,10 @@
   <dd>An application for saving notes. Similar (but not identical) to the 
     <a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
   
+ <dt><a href="SearchableDictionary/index.html">Searchable Dictionary</a></dt>
+  <dd>A sample application that demonstrates Android's search framework, 
+  including how to provide search suggestions for Quick Search Box.</dd>
+  
  <dt><a href="Snake/index.html">Snake</a></dt>
   <dd>An implementation of the classic game "Snake."</dd>
   
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 77a126c..3a419b5 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -136,8 +136,17 @@
 
 AudioFlinger::~AudioFlinger()
 {
-    mRecordThreads.clear();
-    mPlaybackThreads.clear();
+    while (!mRecordThreads.isEmpty()) {
+        // closeInput() will remove first entry from mRecordThreads
+        closeInput(mRecordThreads.keyAt(0));
+    }
+    while (!mPlaybackThreads.isEmpty()) {
+        // closeOutput() will remove first entry from mPlaybackThreads
+        closeOutput(mPlaybackThreads.keyAt(0));
+    }
+    if (mAudioHardware) {
+        delete mAudioHardware;
+    }
 }
 
 
diff --git a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
index c25e476..cbd1ff8 100644
--- a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
+++ b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
@@ -21,13 +21,12 @@
 
   <FrameLayout
     android:layout_width="fill_parent"
-    android:layout_height="0px"
-    android:layout_weight="1">
+    android:layout_height="fill_parent">
     
   <SurfaceView
      android:id="@+id/surface_view"
-     android:layout_width="320dip"
-     android:layout_height="240dip"
+     android:layout_width="fill_parent"
+     android:layout_height="fill_parent"
      android:layout_centerInParent="true"
      />
      
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
index e65cf41..5e830a8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
@@ -69,10 +69,6 @@
         setContentView(R.layout.surface_view);
         mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
         ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
-        lp.width = 320;
-        lp.height = 240;
-        mSurfaceView.setLayoutParams(lp);
-        mSurfaceView.getHolder().setFixedSize(320, 240);  
         mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
         
         //Get the midi fd
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index ea42f53..30e2d6c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -435,9 +435,16 @@
     @LargeTest
     public void testLocalMp3PrepareAsyncCallback() throws Exception {
         boolean onPrepareSuccess = 
-            CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+            CodecTest.prepareAsyncCallback(MediaNames.MP3CBR, false);
         assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess);
     }
+
+    @LargeTest
+    public void testLocalH263AMRPrepareAsyncCallback() throws Exception {
+        boolean onPrepareSuccess =
+            CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+        assertTrue("testLocalH263AMRPrepareAsyncCallback", onPrepareSuccess);
+    }
     
     @LargeTest
     public void testStreamPrepareAsyncCallback() throws Exception {
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
index 3513215..ea14307 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.subscribedfeeds;
 
+import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -35,7 +36,10 @@
 
     public void onReceive(Context context, Intent intent) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received intent " + intent);
-            intent.setClass(context, SubscribedFeedsIntentService.class);
+        if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+            setResultCode(Activity.RESULT_OK);
+        }
+        intent.setClass(context, SubscribedFeedsIntentService.class);
         context.startService(intent);
     }
 }
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 2bd039f..7385359 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -36,17 +36,15 @@
     private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
     private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
 
-    private int mDockState;
-    private boolean mPendingIntent;
+    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    private boolean mSystemReady;
 
     private final Context mContext;
 
     public DockObserver(Context context) {
         mContext = context;
-
-        startObserving(DOCK_UEVENT_MATCH);
-
         init();  // set initial status
+        startObserving(DOCK_UEVENT_MATCH);
     }
 
     @Override
@@ -55,55 +53,59 @@
             Log.v(TAG, "Dock UEVENT: " + event.toString());
         }
 
-        try {
-            update(Integer.parseInt(event.get("SWITCH_STATE")));
-        } catch (NumberFormatException e) {
-            Log.e(TAG, "Could not parse switch state from event " + event);
+        synchronized (this) {
+            try {
+                int newState = Integer.parseInt(event.get("SWITCH_STATE"));
+                if (newState != mDockState) {
+                    mDockState = newState;
+                    if (mSystemReady) {
+                        update();
+                    }
+                }
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Could not parse switch state from event " + event);
+            }
         }
     }
 
-    private synchronized final void init() {
+    private final void init() {
         char[] buffer = new char[1024];
 
-        int newState = mDockState;
         try {
             FileReader file = new FileReader(DOCK_STATE_PATH);
             int len = file.read(buffer, 0, 1024);
-            newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+            mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
 
         } catch (FileNotFoundException e) {
             Log.w(TAG, "This kernel does not have dock station support");
         } catch (Exception e) {
             Log.e(TAG, "" , e);
         }
-
-        update(newState);
     }
 
-    private synchronized final void update(int newState) {
-        if (newState != mDockState) {
-            mDockState = newState;
-
-            mPendingIntent = true;
-            mHandler.sendEmptyMessage(0);
+    void systemReady() {
+        synchronized (this) {
+            // don't bother broadcasting undocked here
+            if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                update();
+            }
+            mSystemReady = true;
         }
     }
 
-    private synchronized final void sendIntent() {
-        Log.d(TAG, "Broadcasting dock state " + mDockState);
-
-        // Pack up the values and broadcast them to everyone
-        Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
-        intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-        mContext.sendStickyBroadcast(intent);
+    private final void update() {
+        mHandler.sendEmptyMessage(0);
     }
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            if (mPendingIntent) {
-                sendIntent();
-                mPendingIntent = false;
+            synchronized (this) {
+                Log.d(TAG, "Broadcasting dock state " + mDockState);
+                // Pack up the values and broadcast them to everyone
+                Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+                intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+                mContext.sendStickyBroadcast(intent);
             }
         }
     };
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index ceef39f..4dfeb9d 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -84,12 +84,16 @@
                     if (hasSensor(sensor)) {
                         removeSensor(sensor);
                         try {
-                            deactivateIfUnused(sensor);
+                            deactivateIfUnusedLocked(sensor);
                         } catch (RemoteException e) {
                             Log.w(TAG, "RemoteException in binderDied");
                         }
                     }
                 }
+                if (mListeners.size() == 0) {
+                    _sensors_control_wake();
+                    _sensors_control_close();
+                }
                 mListeners.notify();
             }
         }
@@ -102,9 +106,12 @@
     }
     
     public Bundle getDataChannel() throws RemoteException {
-        return _sensors_control_open();
+        // synchronize so we do not require sensor HAL to be thread-safe.
+        synchronized(mListeners) {
+            return _sensors_control_open();
+        }
     }
-    
+
     public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
              throws RemoteException {
         if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
@@ -163,7 +170,7 @@
                 l.addSensor(sensor, enable);
             } else {
                 l.removeSensor(sensor);
-                deactivateIfUnused(sensor);
+                deactivateIfUnusedLocked(sensor);
                 if (l.mSensors == 0) {
                     mListeners.remove(l);
                     binder.unlinkToDeath(l, 0);
@@ -173,12 +180,13 @@
             
             if (mListeners.size() == 0) {
                 _sensors_control_wake();
+                _sensors_control_close();
             }
         }        
         return true;
     }
 
-    void deactivateIfUnused(int sensor) throws RemoteException {
+    private void deactivateIfUnusedLocked(int sensor) throws RemoteException {
         int size = mListeners.size();
         for (int i=0 ; i<size ; i++) {
             if (mListeners.get(i).hasSensor(sensor))
@@ -187,10 +195,11 @@
         _sensors_control_activate(sensor, false);
     }
 
-    ArrayList<Listener> mListeners = new ArrayList<Listener>();
+    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
 
     private static native int _sensors_control_init();
     private static native Bundle _sensors_control_open();
+    private static native int _sensors_control_close();
     private static native boolean _sensors_control_activate(int sensor, boolean activate);
     private static native int _sensors_control_set_delay(int ms);
     private static native int _sensors_control_wake();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 95edbeb..df01c61 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -392,6 +392,7 @@
         if (wallpaper != null) wallpaper.systemReady();
         if (battery != null) battery.systemReady();
         if (connectivity != null) connectivity.systemReady();
+        if (dock != null) dock.systemReady();
         Watchdog.getInstance().start();
 
         Looper.loop();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 3c62aa0..c101463 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.FileObserver;
@@ -232,6 +233,16 @@
                 mWidth = width;
                 mHeight = height;
                 saveSettingsLocked();
+                if (mWallpaperConnection != null) {
+                    if (mWallpaperConnection.mEngine != null) {
+                        try {
+                            mWallpaperConnection.mEngine.setDesiredSize(
+                                    width, height);
+                        } catch (RemoteException e) {
+                        }
+                        notifyCallbacksLocked();
+                    }
+                }
             }
         }
     }
@@ -248,9 +259,14 @@
         }
     }
 
-    public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb) {
+    public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+            Bundle outParams) {
         synchronized (mLock) {
             try {
+                if (outParams != null) {
+                    outParams.putInt("width", mWidth);
+                    outParams.putInt("height", mHeight);
+                }
                 mCallbacks.register(cb);
                 File f = WALLPAPER_FILE;
                 if (!f.exists()) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 4321b0d..81e0136 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -412,6 +412,8 @@
     // to another, and this is the higher one in Z-order.
     WindowState mUpperWallpaperTarget = null;
     int mWallpaperAnimLayerAdjustment;
+    float mLastWallpaperX;
+    float mLastWallpaperY;
     
     AppWindowToken mFocusedApp = null;
 
@@ -1371,6 +1373,11 @@
         // what is below it for later.
         foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
         
+        if (visible) {
+            mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+            mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+        }
+        
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
         int curTokenIndex = mWallpaperTokens.size();
@@ -1383,8 +1390,7 @@
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 
                 if (visible) {
-                    updateWallpaperOffsetLocked(mWallpaperTarget,
-                            wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
                 }
                 
                 // First, make sure the client has the current visibility
@@ -1455,36 +1461,35 @@
         }
     }
 
-    boolean updateWallpaperOffsetLocked(WindowState target,
-            WindowState wallpaperWin, int dw, int dh) {
+    boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
         boolean changed = false;
         boolean rawChanged = false;
-        if (target.mWallpaperX >= 0) {
+        if (mLastWallpaperX >= 0) {
             int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
-            int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
+            int offset = availw > 0 ? -(int)(availw*mLastWallpaperX+.5f) : 0;
             changed = wallpaperWin.mXOffset != offset;
             if (changed) {
                 if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
                         + wallpaperWin + " x: " + offset);
                 wallpaperWin.mXOffset = offset;
             }
-            if (wallpaperWin.mWallpaperX != target.mWallpaperX) {
-                wallpaperWin.mWallpaperX = target.mWallpaperX;
+            if (wallpaperWin.mWallpaperX != mLastWallpaperX) {
+                wallpaperWin.mWallpaperX = mLastWallpaperX;
                 rawChanged = true;
             }
         }
         
-        if (target.mWallpaperY >= 0) {
+        if (mLastWallpaperY >= 0) {
             int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
-            int offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
+            int offset = availh > 0 ? -(int)(availh*mLastWallpaperY+.5f) : 0;
             if (wallpaperWin.mYOffset != offset) {
                 if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
                         + wallpaperWin + " y: " + offset);
                 changed = true;
                 wallpaperWin.mYOffset = offset;
             }
-            if (wallpaperWin.mWallpaperY != target.mWallpaperY) {
-                wallpaperWin.mWallpaperY = target.mWallpaperY;
+            if (wallpaperWin.mWallpaperY != mLastWallpaperY) {
+                wallpaperWin.mWallpaperY = mLastWallpaperY;
                 rawChanged = true;
             }
         }
@@ -1511,6 +1516,8 @@
         
         WindowState target = mWallpaperTarget;
         if (target != null) {
+            mLastWallpaperX = target.mWallpaperX;
+            mLastWallpaperY = target.mWallpaperY;
             int curTokenIndex = mWallpaperTokens.size();
             while (curTokenIndex > 0) {
                 curTokenIndex--;
@@ -1519,7 +1526,7 @@
                 while (curWallpaperIndex > 0) {
                     curWallpaperIndex--;
                     WindowState wallpaper = token.windows.get(curWallpaperIndex);
-                    if (updateWallpaperOffsetLocked(target, wallpaper, dw, dh)) {
+                    if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
                         wallpaper.computeShownFrameLocked();
                         changed = true;
                     }
@@ -1545,8 +1552,7 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 if (visible) {
-                    updateWallpaperOffsetLocked(mWallpaperTarget,
-                            wallpaper, dw, dh);                        
+                    updateWallpaperOffsetLocked(wallpaper, dw, dh);                        
                 }
                 
                 if (wallpaper.mWallpaperVisible != visible) {
@@ -2188,6 +2194,10 @@
             }
             newConfig = updateOrientationFromAppTokensLocked(null, null);
             performLayoutAndPlaceSurfacesLocked();
+            if (displayed && win.mIsWallpaper) {
+                updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
+                        mDisplay.getHeight());
+            }
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
             }
@@ -3010,6 +3020,23 @@
                 return;
             }
 
+            // If this is a translucent or wallpaper window, then don't
+            // show a starting window -- the current effect (a full-screen
+            // opaque starting window that fades away to the real contents
+            // when it is ready) does not work for this.
+            if (theme != 0) {
+                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+                        com.android.internal.R.styleable.Window);
+                if (ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+                    return;
+                }
+                if (ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+                    return;
+                }
+            }
+            
             mStartingIconInTransition = true;
             wtoken.startingData = new StartingData(
                     pkg, theme, nonLocalizedLabel,
@@ -6544,10 +6571,9 @@
             visibleInsets.right = frame.right-visible.right;
             visibleInsets.bottom = frame.bottom-visible.bottom;
 
-            if (mIsWallpaper && (fw != frame.width() || fh != frame.height())
-                    && mWallpaperTarget != null) {
-                updateWallpaperOffsetLocked(mWallpaperTarget, this,
-                        mDisplay.getWidth(), mDisplay.getHeight());
+            if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
+                updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
+                        mDisplay.getHeight());
             }
             
             if (localLOGV) {
@@ -9851,6 +9877,10 @@
             pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
             pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
             pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
+            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
+                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
+                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
+            }
             pw.print("  mInTouchMode="); pw.println(mInTouchMode);
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -9865,6 +9895,8 @@
                     pw.print(mInputMethodAnimLayerAdjustment);
                     pw.print("  mWallpaperAnimLayerAdjustment=");
                     pw.println(mWallpaperAnimLayerAdjustment);
+            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
+                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
                     pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 7390786..3911d1f 100644
--- a/services/jni/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
@@ -111,6 +111,15 @@
     return bundle;
 }
 
+static jint
+android_close(JNIEnv *env, jclass clazz)
+{
+    if (sSensorDevice->close_data_source)
+        return sSensorDevice->close_data_source(sSensorDevice);
+    else
+        return 0;
+}
+
 static jboolean
 android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
 {
@@ -135,6 +144,7 @@
 static JNINativeMethod gMethods[] = {
     {"_sensors_control_init",     "()I",   (void*) android_init },
     {"_sensors_control_open",     "()Landroid/os/Bundle;",  (void*) android_open },
+    {"_sensors_control_close",     "()I",  (void*) android_close },
     {"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
     {"_sensors_control_wake",     "()I", (void*) android_data_wake },
     {"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 598f945..14b1563d 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -421,4 +421,6 @@
     static public final int RESULT_ERROR_NULL_PDU           = 3;
     /** Failed because service is currently unavailable */
     static public final int RESULT_ERROR_NO_SERVICE         = 4;
+    /** Failed because we reached the sending queue limit.  {@hide} */
+    static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 79c4b41..ece708a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -280,16 +280,8 @@
                         if (!dataEnabled[apnId]) {
                             dataEnabled[apnId] = true;
                             enabledCount++;
-                            if (enabledCount == 1) {
-                                if (onTrySetupData(null) == false) {
-                                    // failed to setup data - note we can't optimize by only adj
-                                    // these after a successfull call.  dataEnabled must be set
-                                    // prior or we think data is not available.
-                                    dataEnabled[apnId] = false;
-                                    enabledCount--;
-                                }
-                            }
                         }
+                        onTrySetupData(null);
                     } else {
                         // disable
                         if (dataEnabled[apnId]) {
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index d66c20b..bbfc6c9 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -61,6 +61,7 @@
 import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
 import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
 import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
+import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
 
 
 public abstract class SMSDispatcher extends Handler {
@@ -105,6 +106,9 @@
     /** Alert is timeout */
     static final protected int EVENT_ALERT_TIMEOUT = 9;
 
+    /** Stop the sending */
+    static final protected int EVENT_STOP_SENDING = 10;
+
     protected Phone mPhone;
     protected Context mContext;
     protected ContentResolver mResolver;
@@ -120,6 +124,8 @@
     private static final int SEND_RETRY_DELAY = 2000;
     /** single part SMS */
     private static final int SINGLE_PART_SMS = 1;
+    /** Message sending queue limit */
+    private static final int MO_MSG_QUEUE_LIMIT = 5;
 
     /**
      * Message reference for a CONCATENATED_8_BIT_REFERENCE or
@@ -130,7 +136,7 @@
 
     private SmsCounter mCounter;
 
-    private SmsTracker mSTracker;
+    private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT);
 
     /** Wake lock to ensure device stays awake while dispatching the SMS intent. */
     private PowerManager.WakeLock mWakeLock;
@@ -214,7 +220,6 @@
         mContext = phone.getContext();
         mResolver = mContext.getContentResolver();
         mCm = phone.mCM;
-        mSTracker = null;
 
         createWakelock();
 
@@ -330,17 +335,41 @@
         case EVENT_ALERT_TIMEOUT:
             ((AlertDialog)(msg.obj)).dismiss();
             msg.obj = null;
-            mSTracker = null;
+            if (mSTrackers.isEmpty() == false) {
+                try {
+                    SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0);
+                    sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+                } catch (CanceledException ex) {
+                    Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+                }
+            }
+            if (Config.LOGD) {
+                Log.d(TAG, "EVENT_ALERT_TIMEOUT, message stop sending");
+            }
             break;
 
         case EVENT_SEND_CONFIRMED_SMS:
-            if (mSTracker!=null) {
-                if (isMultipartTracker(mSTracker)) {
-                    sendMultipartSms(mSTracker);
+            if (mSTrackers.isEmpty() == false) {
+                SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+                if (isMultipartTracker(sTracker)) {
+                    sendMultipartSms(sTracker);
                 } else {
-                    sendSms(mSTracker);
+                    sendSms(sTracker);
                 }
-                mSTracker = null;
+                removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
+            }
+            break;
+
+        case EVENT_STOP_SENDING:
+            if (mSTrackers.isEmpty() == false) {
+                // Remove the latest one.
+                try {
+                    SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+                    sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+                } catch (CanceledException ex) {
+                    Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+                }
+                removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
             }
             break;
         }
@@ -693,6 +722,15 @@
      * An SmsTracker for the current message.
      */
     protected void handleReachSentLimit(SmsTracker tracker) {
+        if (mSTrackers.size() >= MO_MSG_QUEUE_LIMIT) {
+            // Deny the sending when the queue limit is reached.
+            try {
+                tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+            } catch (CanceledException ex) {
+                Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+            }
+            return;
+        }
 
         Resources r = Resources.getSystem();
 
@@ -702,13 +740,13 @@
                 .setTitle(r.getString(R.string.sms_control_title))
                 .setMessage(appName + " " + r.getString(R.string.sms_control_message))
                 .setPositiveButton(r.getString(R.string.sms_control_yes), mListener)
-                .setNegativeButton(r.getString(R.string.sms_control_no), null)
+                .setNegativeButton(r.getString(R.string.sms_control_no), mListener)
                 .create();
 
         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         d.show();
 
-        mSTracker = tracker;
+        mSTrackers.add(tracker);
         sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
                 DEFAULT_SMS_TIMOUEOUT);
     }
@@ -819,6 +857,9 @@
                 if (which == DialogInterface.BUTTON_POSITIVE) {
                     Log.d(TAG, "click YES to send out sms");
                     sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
+                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+                    Log.d(TAG, "click NO to stop sending");
+                    sendMessage(obtainMessage(EVENT_STOP_SENDING));
                 }
             }
         };
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 3cabd2d..ffaa1cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -568,8 +568,7 @@
     private boolean retryAfterDisconnected(String reason) {
         boolean retry = true;
 
-        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
-             Phone.REASON_DATA_DISABLED.equals(reason) ) {
+        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
             retry = false;
         }
         return retry;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d057dfe..0215ab2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1010,8 +1010,7 @@
     private boolean retryAfterDisconnected(String reason) {
         boolean retry = true;
 
-        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
-             Phone.REASON_DATA_DISABLED.equals(reason) ) {
+        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
             retry = false;
         }
         return retry;
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index dbcef6d..b00d8b0 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1819,6 +1819,19 @@
     AaptDir::print();
 }
 
+sp<AaptDir> AaptAssets::resDir(const String8& name)
+{
+    const Vector<sp<AaptDir> >& dirs = mDirs;
+    const size_t N = dirs.size();
+    for (size_t i=0; i<N; i++) {
+        const sp<AaptDir>& d = dirs.itemAt(i);
+        if (d->getLeaf() == name) {
+            return d;
+        }
+    }
+    return NULL;
+}
+
 bool
 valid_symbol_name(const String8& symbol)
 {
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 32efa4e..865efd1 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -508,6 +508,7 @@
     void print() const;
 
     inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
+    sp<AaptDir> resDir(const String8& name);
 
     inline sp<AaptAssets> getOverlay() { return mOverlay; }
     inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a671bd7..234e5b2 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -39,7 +39,7 @@
           mRequireLocalization(false), mPseudolocalize(false),
           mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL),
-          mAssetSourceDir(NULL),
+          mAssetSourceDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL),
           mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
@@ -88,6 +88,8 @@
      */
     const char* getAssetSourceDir() const { return mAssetSourceDir; }
     void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+    const char* getProguardFile() const { return mProguardFile; }
+    void setProguardFile(const char* file) { mProguardFile = file; }
     const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
     void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
     const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
@@ -161,6 +163,7 @@
     int         mCompressionMethod;
     const char* mOutputAPKFile;
     const char* mAssetSourceDir;
+    const char* mProguardFile;
     const char* mAndroidManifestFile;
     const char* mPublicOutputFile;
     const char* mRClassDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 790b474..f2cdf75 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -233,7 +233,7 @@
     return -1;
 }
 
-static String8 getAttribute(const ResXMLTree& tree, const char* ns,
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
                             const char* attr, String8* outError)
 {
     ssize_t idx = tree.indexOfAttribute(ns, attr);
@@ -1158,6 +1158,12 @@
         }
     }
 
+    // Write out the ProGuard file
+    err = writeProguardFile(bundle, assets);
+    if (err < 0) {
+        goto bail;
+    }
+
     // Write the apk
     if (outputAPKFile) {
         err = writeAPK(bundle, assets, String8(outputAPKFile));
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 882714c..e61010c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -59,9 +59,9 @@
         "        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
         "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
         "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
-        "        [--app-version-name TEXT] \\\n"
+        "        [--app-version-name TEXT]\\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
-        "        [-A asset-source-dir] [-P public-definitions-file] \\\n"
+        "        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
         "        [-F apk-file] [-J R-file-dir] \\\n"
         "        [raw-files-dir [raw-files-dir] ...]\n"
@@ -109,6 +109,7 @@
         "   -z  require localization of resource attributes marked with\n"
         "       localization=\"suggested\"\n"
         "   -A  additional directory in which to find raw asset files\n"
+        "   -G  A file to output proguard options into.\n"
         "   -F  specify the apk file to output\n"
         "   -I  add an existing package to base include set\n"
         "   -J  specify where to output R.java resource constant definitions\n"
@@ -274,6 +275,17 @@
                 convertPath(argv[0]);
                 bundle.setAssetSourceDir(argv[0]);
                 break;
+            case 'G':
+                argc--;
+                argv++;
+                if (!argc) {
+                    fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
+                    wantUsage = true;
+                    goto bail;
+                }
+                convertPath(argv[0]);
+                bundle.setProguardFile(argv[0]);
+                break;
             case 'I':
                 argc--;
                 argv++;
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index 34ca5e5..3ba4f39 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -33,6 +33,8 @@
 extern android::status_t writeResourceSymbols(Bundle* bundle,
     const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
 
+extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
+
 extern bool isValidResourceType(const String8& type);
 
 ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
@@ -41,4 +43,7 @@
 
 int dumpResources(Bundle* bundle);
 
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
+                            const char* attr, String8* outError);
+
 #endif // __MAIN_H
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index e8410cd..4c9853d 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1630,3 +1630,230 @@
 
     return NO_ERROR;
 }
+
+
+
+class ProguardKeepSet
+{
+public:
+    // { rule --> { file locations } }
+    KeyedVector<String8, SortedVector<String8> > rules;
+
+    void add(const String8& rule, const String8& where);
+};
+
+void ProguardKeepSet::add(const String8& rule, const String8& where)
+{
+    ssize_t index = rules.indexOfKey(rule);
+    if (index < 0) {
+        index = rules.add(rule, SortedVector<String8>());
+    }
+    rules.editValueAt(index).add(where);
+}
+
+status_t
+writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+    status_t err;
+    ResXMLTree tree;
+    size_t len;
+    ResXMLTree::event_code_t code;
+    int depth = 0;
+    bool inApplication = false;
+    String8 error;
+    sp<AaptGroup> assGroup;
+    sp<AaptFile> assFile;
+    String8 pkg;
+
+    // First, look for a package file to parse.  This is required to
+    // be able to generate the resource information.
+    assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml"));
+    if (assGroup == NULL) {
+        fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
+        return -1;
+    }
+
+    if (assGroup->getFiles().size() != 1) {
+        fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
+                assGroup->getFiles().valueAt(0)->getPrintableSource().string());
+    }
+
+    assFile = assGroup->getFiles().valueAt(0);
+
+    err = parseXMLResource(assFile, &tree);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    tree.restart();
+
+    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+        if (code == ResXMLTree::END_TAG) {
+            if (/* name == "Application" && */ depth == 2) {
+                inApplication = false;
+            }
+            depth--;
+            continue;
+        }
+        if (code != ResXMLTree::START_TAG) {
+            continue;
+        }
+        depth++;
+        String8 tag(tree.getElementName(&len));
+        // printf("Depth %d tag %s\n", depth, tag.string());
+        if (depth == 1) {
+            if (tag != "manifest") {
+                fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
+                return -1;
+            }
+            pkg = getAttribute(tree, NULL, "package", NULL);
+        } else if (depth == 2 && tag == "application") {
+            inApplication = true;
+        }
+        if (inApplication) {
+            if (tag == "application" || tag == "activity" || tag == "service" || tag == "receiver"
+                    || tag == "provider") {
+                String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android",
+                        "name", &error);
+                if (error != "") {
+                    fprintf(stderr, "ERROR: %s\n", error.string());
+                    return -1;
+                }
+                // asdf     --> package.asdf
+                // .asdf  .a.b  --> package.asdf package.a.b
+                // asdf.adsf --> asdf.asdf
+                String8 rule("-keep class ");
+                const char* p = name.string();
+                const char* q = strchr(p, '.');
+                if (p == q) {
+                    rule += pkg;
+                    rule += name;
+                } else if (q == NULL) {
+                    rule += pkg;
+                    rule += ".";
+                    rule += name;
+                } else {
+                    rule += name;
+                }
+
+                String8 location = tag;
+                location += " ";
+                location += assFile->getSourceFile();
+                char lineno[20];
+                sprintf(lineno, ":%d", tree.getLineNumber());
+                location += lineno;
+
+                keep->add(rule, location);
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t
+writeProguardForLayout(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile)
+{
+    status_t err;
+    ResXMLTree tree;
+    size_t len;
+    ResXMLTree::event_code_t code;
+
+    err = parseXMLResource(layoutFile, &tree);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    tree.restart();
+
+    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+        if (code != ResXMLTree::START_TAG) {
+            continue;
+        }
+        String8 tag(tree.getElementName(&len));
+
+        // If there is no '.', we'll assume that it's one of the built in names.
+        if (strchr(tag.string(), '.')) {
+            String8 rule("-keep class ");
+            rule += tag;
+            rule += " { <init>(...); }";
+
+            String8 location("view ");
+            location += layoutFile->getSourceFile();
+            char lineno[20];
+            sprintf(lineno, ":%d", tree.getLineNumber());
+            location += lineno;
+
+            keep->add(rule, location);
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t
+writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+    status_t err;
+    sp<AaptDir> layout = assets->resDir(String8("layout"));
+
+    if (layout != NULL) {
+        const KeyedVector<String8,sp<AaptGroup> > groups = layout->getFiles();
+        const size_t N = groups.size();
+        for (size_t i=0; i<N; i++) {
+            const sp<AaptGroup>& group = groups.valueAt(i);
+            const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
+            const size_t M = files.size();
+            for (size_t j=0; j<M; j++) {
+                err = writeProguardForLayout(keep, files.valueAt(j));
+                if (err < 0) {
+                    return err;
+                }
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t
+writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets)
+{
+    status_t err = -1;
+
+    if (!bundle->getProguardFile()) {
+        return NO_ERROR;
+    }
+
+    ProguardKeepSet keep;
+
+    err = writeProguardForAndroidManifest(&keep, assets);
+    if (err < 0) {
+        return err;
+    }
+
+    err = writeProguardForLayouts(&keep, assets);
+    if (err < 0) {
+        return err;
+    }
+
+    FILE* fp = fopen(bundle->getProguardFile(), "w+");
+    if (fp == NULL) {
+        fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
+                bundle->getProguardFile(), strerror(errno));
+        return UNKNOWN_ERROR;
+    }
+
+    const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules;
+    const size_t N = rules.size();
+    for (size_t i=0; i<N; i++) {
+        const SortedVector<String8>& locations = rules.valueAt(i);
+        const size_t M = locations.size();
+        for (size_t j=0; j<M; j++) {
+            fprintf(fp, "# %s\n", locations.itemAt(j).string());
+        }
+        fprintf(fp, "%s\n\n", rules.keyAt(i).string());
+    }
+    fclose(fp);
+
+    return err;
+}