Merge change 23223 into eclair

* changes:
  SensorService: call close_data_source when we have no more sensor clients.
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/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/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/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d4a4c11..0d51b93 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1042,6 +1042,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/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/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 2bd039f..73853595 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/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);