Merge change 22030 into eclair

* changes:
  Potential fix for NPE at startExtractingText.
diff --git a/api/current.xml b/api/current.xml
index e9082bc..e9c3b30 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -8567,6 +8567,50 @@
  visibility="public"
 >
 </field>
+<field name="wallpaperActivityCloseEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843412"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityCloseExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843413"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843410"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843411"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="webViewStyle"
  type="int"
  transient="false"
@@ -12087,6 +12131,17 @@
  visibility="public"
 >
 </field>
+<field name="Animation_InputMethod"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973910"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Animation_Toast"
  type="int"
  transient="false"
@@ -144974,6 +145029,8 @@
 >
 <parameter name="dirty" type="android.graphics.Rect">
 </parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
 <exception name="Surface.OutOfResourcesException" type="android.view.Surface.OutOfResourcesException">
 </exception>
 </method>
@@ -175196,6 +175253,39 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="canPause"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getBufferPercentage"
  return="int"
  abstract="true"
@@ -183524,6 +183614,39 @@
 <parameter name="defStyle" type="int">
 </parameter>
 </constructor>
+<method name="canPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getBufferPercentage"
  return="int"
  abstract="false"
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 56f6338..185e6ac 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -70,6 +70,7 @@
 
     long numIterationsLeft = gNumRepetitions;
     MediaSource::ReadOptions options;
+
     while (numIterationsLeft-- > 0) {
         MediaBuffer *buffer;
 
diff --git a/core/java/android/pim/ContactsAsyncHelper.java b/core/java/android/pim/ContactsAsyncHelper.java
index a21281e..342d208 100644
--- a/core/java/android/pim/ContactsAsyncHelper.java
+++ b/core/java/android/pim/ContactsAsyncHelper.java
@@ -27,8 +27,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
+import android.provider.ContactsContract.Contacts;
 import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
@@ -39,35 +38,35 @@
  * Helper class for async access of images.
  */
 public class ContactsAsyncHelper extends Handler {
-    
+
     private static final boolean DBG = false;
     private static final String LOG_TAG = "ContactsAsyncHelper";
-    
+
     /**
      * Interface for a WorkerHandler result return.
      */
     public interface OnImageLoadCompleteListener {
         /**
          * Called when the image load is complete.
-         * 
+         *
          * @param imagePresent true if an image was found
-         */  
+         */
         public void onImageLoadComplete(int token, Object cookie, ImageView iView,
                 boolean imagePresent);
     }
-     
+
     // constants
     private static final int EVENT_LOAD_IMAGE = 1;
     private static final int DEFAULT_TOKEN = -1;
-    
+
     // static objects
     private static Handler sThreadHandler;
     private static ContactsAsyncHelper sInstance;
-    
+
     static {
         sInstance = new ContactsAsyncHelper();
     }
-    
+
     private static final class WorkerArgs {
         public Context context;
         public ImageView view;
@@ -78,12 +77,12 @@
         public OnImageLoadCompleteListener listener;
         public CallerInfo info;
     }
-    
+
     /**
-     * public inner class to help out the ContactsAsyncHelper callers 
-     * with tracking the state of the CallerInfo Queries and image 
+     * public inner class to help out the ContactsAsyncHelper callers
+     * with tracking the state of the CallerInfo Queries and image
      * loading.
-     * 
+     *
      * Logic contained herein is used to remove the race conditions
      * that exist as the CallerInfo queries run and mix with the image
      * loads, which then mix with the Phone state changes.
@@ -94,11 +93,11 @@
         public static final int DISPLAY_UNDEFINED = 0;
         public static final int DISPLAY_IMAGE = -1;
         public static final int DISPLAY_DEFAULT = -2;
-        
+
         // State of the image on the imageview.
         private CallerInfo mCurrentCallerInfo;
         private int displayMode;
-        
+
         public ImageTracker() {
             mCurrentCallerInfo = null;
             displayMode = DISPLAY_UNDEFINED;
@@ -107,17 +106,17 @@
         /**
          * Used to see if the requested call / connection has a
          * different caller attached to it than the one we currently
-         * have in the CallCard. 
+         * have in the CallCard.
          */
         public boolean isDifferentImageRequest(CallerInfo ci) {
             // note, since the connections are around for the lifetime of the
-            // call, and the CallerInfo-related items as well, we can 
+            // call, and the CallerInfo-related items as well, we can
             // definitely use a simple != comparison.
             return (mCurrentCallerInfo != ci);
         }
-        
+
         public boolean isDifferentImageRequest(Connection connection) {
-            // if the connection does not exist, see if the 
+            // if the connection does not exist, see if the
             // mCurrentCallerInfo is also null to match.
             if (connection == null) {
                 if (DBG) Log.d(LOG_TAG, "isDifferentImageRequest: connection is null");
@@ -133,57 +132,58 @@
             }
             return runQuery;
         }
-        
+
         /**
-         * Simple setter for the CallerInfo object. 
+         * Simple setter for the CallerInfo object.
          */
         public void setPhotoRequest(CallerInfo ci) {
-            mCurrentCallerInfo = ci; 
+            mCurrentCallerInfo = ci;
         }
-        
+
         /**
-         * Convenience method used to retrieve the URI 
-         * representing the Photo file recorded in the attached 
-         * CallerInfo Object. 
+         * Convenience method used to retrieve the URI
+         * representing the Photo file recorded in the attached
+         * CallerInfo Object.
          */
         public Uri getPhotoUri() {
             if (mCurrentCallerInfo != null) {
-                return ContentUris.withAppendedId(People.CONTENT_URI, 
+                return ContentUris.withAppendedId(Contacts.CONTENT_URI,
                         mCurrentCallerInfo.person_id);
             }
-            return null; 
+            return null;
         }
-        
+
         /**
-         * Simple setter for the Photo state. 
+         * Simple setter for the Photo state.
          */
         public void setPhotoState(int state) {
             displayMode = state;
         }
-        
+
         /**
-         * Simple getter for the Photo state. 
+         * Simple getter for the Photo state.
          */
         public int getPhotoState() {
             return displayMode;
         }
     }
-    
+
     /**
-     * Thread worker class that handles the task of opening the stream and loading 
+     * Thread worker class that handles the task of opening the stream and loading
      * the images.
      */
     private class WorkerHandler extends Handler {
         public WorkerHandler(Looper looper) {
             super(looper);
         }
-        
+
+        @Override
         public void handleMessage(Message msg) {
             WorkerArgs args = (WorkerArgs) msg.obj;
-            
+
             switch (msg.arg1) {
                 case EVENT_LOAD_IMAGE:
-                    InputStream inputStream = Contacts.People.openContactPhotoInputStream(
+                    InputStream inputStream = Contacts.openContactPhotoInputStream(
                             args.context.getContentResolver(), args.uri);
                     if (inputStream != null) {
                         args.result = Drawable.createFromStream(inputStream, args.uri.toString());
@@ -192,22 +192,22 @@
                                 " token: " + msg.what + " image URI: " + args.uri);
                     } else {
                         args.result = null;
-                        if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 + 
-                                " token: " + msg.what + " image URI: " + args.uri + 
+                        if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
+                                " token: " + msg.what + " image URI: " + args.uri +
                                 ", using default image.");
                     }
                     break;
                 default:
             }
-            
-            // send the reply to the enclosing class. 
+
+            // send the reply to the enclosing class.
             Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
             reply.arg1 = msg.arg1;
             reply.obj = msg.obj;
             reply.sendToTarget();
         }
     }
-    
+
     /**
      * Private constructor for static class
      */
@@ -216,14 +216,14 @@
         thread.start();
         sThreadHandler = new WorkerHandler(thread.getLooper());
     }
-    
+
     /**
      * Convenience method for calls that do not want to deal with listeners and tokens.
      */
-    public static final void updateImageViewWithContactPhotoAsync(Context context, 
+    public static final void updateImageViewWithContactPhotoAsync(Context context,
             ImageView imageView, Uri person, int placeholderImageResource) {
         // Added additional Cookie field in the callee.
-        updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context, 
+        updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
                 imageView, person, placeholderImageResource);
     }
 
@@ -231,24 +231,24 @@
      * Convenience method for calls that do not want to deal with listeners and tokens, but have
      * a CallerInfo object to cache the image to.
      */
-    public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context, 
+    public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
             ImageView imageView, Uri person, int placeholderImageResource) {
         // Added additional Cookie field in the callee.
-        updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context, 
+        updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
                 imageView, person, placeholderImageResource);
     }
 
-    
+
     /**
      * Start an image load, attach the result to the specified CallerInfo object.
      * Note, when the query is started, we make the ImageView INVISIBLE if the
      * placeholderImageResource value is -1.  When we're given a valid (!= -1)
      * placeholderImageResource value, we make sure the image is visible.
      */
-    public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token, 
-            OnImageLoadCompleteListener listener, Object cookie, Context context, 
+    public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
+            OnImageLoadCompleteListener listener, Object cookie, Context context,
             ImageView imageView, Uri person, int placeholderImageResource) {
-        
+
         // in case the source caller info is null, the URI will be null as well.
         // just update using the placeholder image in this case.
         if (person == null) {
@@ -257,10 +257,10 @@
             imageView.setImageResource(placeholderImageResource);
             return;
         }
-        
+
         // Added additional Cookie field in the callee to handle arguments
         // sent to the callback function.
-        
+
         // setup arguments
         WorkerArgs args = new WorkerArgs();
         args.cookie = cookie;
@@ -270,15 +270,15 @@
         args.defaultResource = placeholderImageResource;
         args.listener = listener;
         args.info = info;
-        
+
         // setup message arguments
         Message msg = sThreadHandler.obtainMessage(token);
         msg.arg1 = EVENT_LOAD_IMAGE;
         msg.obj = args;
-        
-        if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri + 
+
+        if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
                 ", displaying default image for now.");
-        
+
         // set the default image first, when the query is complete, we will
         // replace the image with the correct one.
         if (placeholderImageResource != -1) {
@@ -287,11 +287,11 @@
         } else {
             imageView.setVisibility(View.INVISIBLE);
         }
-        
+
         // notify the thread to begin working
         sThreadHandler.sendMessage(msg);
     }
-    
+
     /**
      * Called when loading is done.
      */
@@ -316,21 +316,21 @@
                     args.view.setVisibility(View.VISIBLE);
                     args.view.setImageResource(args.defaultResource);
                 }
-                
+
                 // Note that the data is cached.
                 if (args.info != null) {
                     args.info.isCachedPhotoCurrent = true;
                 }
-                
+
                 // notify the listener if it is there.
                 if (args.listener != null) {
-                    if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() + 
+                    if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
                             " image: " + args.uri + " completed");
                     args.listener.onImageLoadComplete(msg.what, args.cookie, args.view,
                             imagePresent);
                 }
                 break;
-            default:    
+            default:
         }
     }
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 50c9c8c..5932040 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,15 +19,21 @@
 import android.accounts.Account;
 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;
+import android.database.Cursor;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.text.TextUtils;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
 /**
  * The contract between the contacts provider and applications. Contains definitions
  * for the supported URIs and columns.
@@ -299,6 +305,55 @@
              */
             public static final String CONTENT_DIRECTORY = "suggestions";
         }
+
+        /**
+         * Returns a URI that can be used to retrieve the contact's default photo.
+         *
+         * @param contactUri the contact whose photo should be used
+         */
+        public static Uri getPhotoUri(ContentResolver cr, Uri contactUri) {
+            long photoId = -1;
+            Cursor cursor = cr.query(contactUri, new String[]{Contacts.PHOTO_ID}, null, null, null);
+            try {
+                if (!cursor.moveToNext()) {
+                    return null;
+                }
+
+                if (cursor.isNull(0)) {
+                    return null;
+                }
+
+                photoId = cursor.getLong(0);
+            } finally {
+                cursor.close();
+            }
+
+            return ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, photoId);
+        }
+
+        /**
+         * Opens an InputStream for the person's default photo and returns the
+         * photo as a Bitmap stream.
+         *
+         * @param contactUri the contact whose photo should be used
+         */
+        public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+            Uri photoUri = getPhotoUri(cr, contactUri);
+            Cursor cursor = cr.query(photoUri,
+                    new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
+            try {
+                if (!cursor.moveToNext()) {
+                    return null;
+                }
+                byte[] data = cursor.getBlob(0);
+                if (data == null) {
+                    return null;
+                }
+                return new ByteArrayInputStream(data);
+            } finally {
+                cursor.close();
+            }
+        }
     }
 
     private interface RawContactsColumns {
@@ -1557,14 +1612,6 @@
         public static final String SHOULD_SYNC = "should_sync";
 
         /**
-         * Overriding flag indicating if contacts from this source should be
-         * visible in any user interface.
-         * <p>
-         * Type: INTEGER (boolean)
-         */
-        public static final String SOURCE_VISIBLE = "source_visible";
-
-        /**
          * Flag indicating if contacts without any {@link GroupMembership}
          * entries should be visible in any user interface.
          * <p>
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 9ec1013..5cecac3 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -246,7 +246,7 @@
     };
 
     /**
-     * Sets the display metrics used to provide canva's width/height in comaptibility mode.
+     * Sets the display metrics used to provide canva's width/height in compatibility mode.
      */
     void setCompatibleDisplayMetrics(DisplayMetrics metrics, Translator translator) {
         mCompatibleDisplayMetrics = metrics;
@@ -275,7 +275,8 @@
     public native   void clear();
     
     /** draw into a surface */
-    public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException {
+    public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException
+    {
         /* the dirty rectangle may be expanded to the surface's size, if
          * for instance it has been resized or if the bits were lost, since
          * the last call.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index f4e9900..ea08f33 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -344,6 +344,12 @@
     public final int TRANSIT_TASK_TO_FRONT = 10;
     /** A window in an existing task is being put below all other tasks. */
     public final int TRANSIT_TASK_TO_BACK = 11;
+    /** A window in a new activity is being opened on top of an existing one,
+     * and both are on top of the wallpaper. */
+    public final int TRANSIT_WALLPAPER_ACTIVITY_OPEN = 12;
+    /** The window in the top-most activity is being closed to reveal the
+     * previous activity, and both are on top of he wallpaper. */
+    public final int TRANSIT_WALLPAPER_ACTIVITY_CLOSE = 13;
     
     /** Screen turned off because of power button */
     public final int OFF_BECAUSE_OF_USER = 1;
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 0c9d980..9910c37 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -250,6 +250,29 @@
     }
 
     /**
+     * Disable pause or seek buttons if the stream cannot be paused or seeked.
+     * This requires the control interface to be a MediaPlayerControlExt
+     */
+    private void disableUnsupportedButtons() {
+        try {
+            if (mPauseButton != null && !mPlayer.canPause()) {
+                mPauseButton.setEnabled(false);
+            }
+            if (mRewButton != null && !mPlayer.canSeekBackward()) {
+                mRewButton.setEnabled(false);
+            }
+            if (mFfwdButton != null && !mPlayer.canSeekForward()) {
+                mFfwdButton.setEnabled(false);
+            }
+        } catch (IncompatibleClassChangeError ex) {
+            // We were given an old version of the interface, that doesn't have
+            // the canPause/canSeekXYZ methods. This is OK, it just means we
+            // assume the media can be paused and seeked, and so we don't disable
+            // the buttons.
+        }
+    }
+    
+    /**
      * Show the controller on screen. It will go away
      * automatically after 'timeout' milliseconds of inactivity.
      * @param timeout The timeout in milliseconds. Use 0 to show
@@ -259,6 +282,7 @@
 
         if (!mShowing && mAnchor != null) {
             setProgress();
+            disableUnsupportedButtons();
 
             int [] anchorpos = new int[2];
             mAnchor.getLocationOnScreen(anchorpos);
@@ -421,17 +445,13 @@
     };
 
     private void updatePausePlay() {
-        if (mRoot == null)
-            return;
-
-        ImageButton button = (ImageButton) mRoot.findViewById(com.android.internal.R.id.pause);
-        if (button == null)
+        if (mRoot == null || mPauseButton == null)
             return;
 
         if (mPlayer.isPlaying()) {
-            button.setImageResource(com.android.internal.R.drawable.ic_media_pause);
+            mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_pause);
         } else {
-            button.setImageResource(com.android.internal.R.drawable.ic_media_play);
+            mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_play);
         }
     }
 
@@ -516,7 +536,7 @@
         if (mProgress != null) {
             mProgress.setEnabled(enabled);
         }
-
+        disableUnsupportedButtons();
         super.setEnabled(enabled);
     }
 
@@ -579,5 +599,8 @@
         void    seekTo(int pos);
         boolean isPlaying();
         int     getBufferPercentage();
-    };
+        boolean canPause();
+        boolean canSeekBackward();
+        boolean canSeekForward();
+    }
 }
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 5bc2507..e60ff25 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -23,6 +23,7 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
+import android.media.Metadata;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.net.Uri;
@@ -34,7 +35,7 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
-import android.widget.MediaController.MediaPlayerControl;
+import android.widget.MediaController.*;
 
 import java.io.IOException;
 
@@ -81,6 +82,9 @@
     private int         mCurrentBufferPercentage;
     private OnErrorListener mOnErrorListener;
     private int         mSeekWhenPrepared;  // recording the seek position while preparing
+    private boolean     mCanPause;
+    private boolean     mCanSeekBack;
+    private boolean     mCanSeekForward;
 
     public VideoView(Context context) {
         super(context);
@@ -259,6 +263,17 @@
     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
         public void onPrepared(MediaPlayer mp) {
             mCurrentState = STATE_PREPARED;
+
+            // Get the capabilities of the player for this stream
+            Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
+                                      MediaPlayer.BYPASS_METADATA_FILTER);
+            mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
+                    || data.getBoolean(Metadata.PAUSE_AVAILABLE);
+            mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
+                    || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
+            mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
+                    || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
+
             if (mOnPreparedListener != null) {
                 mOnPreparedListener.onPrepared(mMediaPlayer);
             }
@@ -267,6 +282,7 @@
             }
             mVideoWidth = mp.getVideoWidth();
             mVideoHeight = mp.getVideoHeight();
+
             int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call
             if (seekToPosition != 0) {
                 seekTo(seekToPosition);
@@ -580,4 +596,16 @@
                 mCurrentState != STATE_IDLE &&
                 mCurrentState != STATE_PREPARING);
     }
+
+    public boolean canPause() {
+        return mCanPause;
+    }
+
+    public boolean canSeekBackward() {
+        return mCanSeekBack;
+    }
+
+    public boolean canSeekForward() {
+        return mCanSeekForward;
+    }
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2e73372..f61e247 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -525,6 +525,7 @@
     char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
     char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
+    char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
     bool checkJni = false;
     bool checkDexSum = false;
@@ -597,16 +598,10 @@
     mOptions.add(opt);
     //options[curOpt++].optionString = "-verbose:class";
 
-#ifdef CUSTOM_RUNTIME_HEAP_MAX
-#define __make_max_heap_opt(val) #val
-#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
-    opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
-#undef __make_max_heap_opt
-#undef _make_max_heap_opt
-#else
-    /* limit memory use to 16MB */
-    opt.optionString = "-Xmx16m";
-#endif
+    strcpy(heapsizeOptsBuf, "-Xmx");
+    property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
+    //LOGI("Heap size: %s", heapsizeOptsBuf);
+    opt.optionString = heapsizeOptsBuf;
     mOptions.add(opt);
 
     /*
diff --git a/core/res/res/anim/wallpaper_activity_close_enter.xml b/core/res/res/anim/wallpaper_activity_close_enter.xml
new file mode 100644
index 0000000..fc6e332
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_enter.xml
@@ -0,0 +1,30 @@
+<?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"
+        android:zAdjustment="top">
+    <scale android:fromXScale="2.0" android:toXScale="1.0"
+           android:fromYScale="2.0" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_mediumAnimTime" />
+	<translate android:fromXDelta="-150%" android:toXDelta="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
new file mode 100644
index 0000000..edd00fd
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_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=".5"
+           android:fromYScale="1.0" android:toYScale=".5"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_mediumAnimTime" />
+	<translate android:fromXDelta="0%" android:toXDelta="100%"
+        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
new file mode 100644
index 0000000..5b44d97
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_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=".5" android:toXScale="1.0"
+           android:fromYScale=".5" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <translate android:fromXDelta="100%" android:toXDelta="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
new file mode 100644
index 0000000..fa39bee
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_exit.xml
@@ -0,0 +1,30 @@
+<?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"
+        android:zAdjustment="top">
+    <scale android:fromXScale="1.0" android:toXScale="2.0"
+           android:fromYScale="1.0" android:toYScale="2.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <translate android:fromXDelta="0" android:toXDelta="-150%"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index eee87e6..e03211d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -937,18 +937,68 @@
         <attr name="windowShowAnimation" format="reference" />
         <!-- The animation used when a window is going from VISIBLE to INVISIBLE. -->
         <attr name="windowHideAnimation" format="reference" />
+        
+        <!--  When opening a new activity, this is the animation that is
+              run on the next activity (which is entering the screen). -->
         <attr name="activityOpenEnterAnimation" format="reference" />
+        <!--  When opening a new activity, this is the animation that is
+              run on the previous activity (which is exiting the screen). -->
         <attr name="activityOpenExitAnimation" format="reference" />
+        <!--  When closing the current activity, this is the animation that is
+              run on the next activity (which is entering the screen). -->
         <attr name="activityCloseEnterAnimation" format="reference" />
+        <!--  When closing the current activity, this is the animation that is
+              run on the current activity (which is exiting the screen). -->
         <attr name="activityCloseExitAnimation" format="reference" />
+        <!--  When opening an activity in a new task, this is the animation that is
+              run on the activity of the new task (which is entering the screen). -->
         <attr name="taskOpenEnterAnimation" format="reference" />
+        <!--  When opening an activity in a new task, this is the animation that is
+              run on the activity of the old task (which is exiting the screen). -->
         <attr name="taskOpenExitAnimation" format="reference" />
+        <!--  When closing the last activity of a task, this is the animation that is
+              run on the activity of the next task (which is entering the screen). -->
         <attr name="taskCloseEnterAnimation" format="reference" />
+        <!--  When opening an activity in a new task, this is the animation that is
+              run on the activity of the old task (which is exiting the screen). -->
         <attr name="taskCloseExitAnimation" format="reference" />
+        <!--  When bringing an existing task to the foreground, this is the
+              animation that is run on the top activity of the task being brought
+              to the foreground (which is entering the screen). -->
         <attr name="taskToFrontEnterAnimation" format="reference" />
+        <!--  When bringing an existing task to the foreground, this is the
+              animation that is run on the current foreground activity
+              (which is exiting the screen). -->
         <attr name="taskToFrontExitAnimation" format="reference" />
+        <!--  When sending the current task to the background, this is the
+              animation that is run on the top activity of the task behind
+              it (which is entering the screen). -->
         <attr name="taskToBackEnterAnimation" format="reference" />
+        <!--  When sending the current task to the background, this is the
+              animation that is run on the top activity of the current task
+              (which is exiting the screen). -->
         <attr name="taskToBackExitAnimation" format="reference" />
+        
+        <!--  When opening a new activity that is on top of the wallpaper
+              when the current activity is also on top of the wallpaper,
+              this is the animation that is run on the new activity
+              (which is entering the screen). -->
+        <attr name="wallpaperActivityOpenEnterAnimation" format="reference" />
+        <!--  When opening a new activity that is on top of the wallpaper
+              when the current activity is also on top of the wallpaper,
+              this is the animation that is run on the current activity
+              (which is exiting the screen). -->
+        <attr name="wallpaperActivityOpenExitAnimation" format="reference" />
+        <!--  When closing a foreround activity that is on top of the wallpaper
+              when the previous activity is also on top of the wallpaper,
+              this is the animation that is run on the previous activity
+              (which is entering the screen). -->
+        <attr name="wallpaperActivityCloseEnterAnimation" format="reference" />
+        <!--  When closing a foreround activity that is on top of the wallpaper
+              when the previous activity is also on top of the wallpaper,
+              this is the animation that is run on the current activity
+              (which is exiting the screen). -->
+        <attr name="wallpaperActivityCloseExitAnimation" format="reference" />
     </declare-styleable>
 
     <!-- ============================= -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 60b492a..bbeb78d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1150,6 +1150,10 @@
   <public type="attr" name="contentAuthority" />
   <public type="attr" name="userVisible" />
   <public type="attr" name="windowShowWallpaper" />
+  <public type="attr" name="wallpaperActivityOpenEnterAnimation" />
+  <public type="attr" name="wallpaperActivityOpenExitAnimation" />
+  <public type="attr" name="wallpaperActivityCloseEnterAnimation" />
+  <public type="attr" name="wallpaperActivityCloseExitAnimation" />
 
   <public type="style" name="Theme.Wallpaper" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 22f9136..c14ecc0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1350,7 +1350,7 @@
 
     <!-- When the battery is low, this is the label of the button to go to the
          power usage activity to find out what drained the battery. -->
-    <string name="battery_low_why">Why?</string>
+    <string name="battery_low_why">Battery use</string>
 
     <!-- Title of the alert when something went wrong in the factory test. -->
     <string name="factorytest_failed">Factory test failed</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4aa4210..10d2093 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -66,6 +66,10 @@
         <item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
         <item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
         <item name="taskToBackExitAnimation">@anim/task_close_exit</item>
+        <item name="wallpaperActivityOpenEnterAnimation">@anim/wallpaper_activity_open_enter</item>
+        <item name="wallpaperActivityOpenExitAnimation">@anim/wallpaper_activity_open_exit</item>
+        <item name="wallpaperActivityCloseEnterAnimation">@anim/wallpaper_activity_close_enter</item>
+        <item name="wallpaperActivityCloseExitAnimation">@anim/wallpaper_activity_close_exit</item>
     </style>
 
     <!-- Standard animations for a non-full-screen window or activity. -->
@@ -130,8 +134,7 @@
         <item name="windowExitAnimation">@anim/slide_out_down</item>
     </style>
 
-    <!-- Window animations that are applied to input method overlay windows.
-         {@hide Pending API council approval} -->
+    <!-- Window animations that are applied to input method overlay windows. -->
     <style name="Animation.InputMethod">
         <item name="windowEnterAnimation">@anim/input_method_enter</item>
         <item name="windowExitAnimation">@anim/input_method_exit</item>
@@ -151,8 +154,7 @@
         <item name="windowExitAnimation">@anim/search_bar_exit</item>
     </style>
 
-    <!-- Window animations that are applied to the zoom buttons overlay window.
-         {@hide Pending API council approval} -->
+    <!-- Window animations that are applied to the zoom buttons overlay window. -->
     <style name="Animation.ZoomButtons">
         <item name="windowEnterAnimation">@anim/fade_in</item>
         <item name="windowExitAnimation">@anim/fade_out</item>
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 2d5b8d8..6ce2581 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -28,23 +28,23 @@
 namespace android {
 
 enum {
-    kKeyMIMEType         = 'mime',
-    kKeyWidth            = 'widt',
-    kKeyHeight           = 'heig',
-    kKeyChannelCount     = '#chn',
-    kKeySampleRate       = 'srte',
-    kKeyBitRate          = 'brte',
-    kKeyESDS             = 'esds',
-    kKeyAVCC             = 'avcc',
-    kKeyTimeUnits        = '#tim',
-    kKeyTimeScale        = 'scal',
-    kKeyNeedsNALFraming  = 'NALf',
-    kKeyIsSyncFrame      = 'sync',
-    kKeyDuration         = 'dura',
-    kKeyColorFormat      = 'colf',
-    kKeyPlatformPrivate  = 'priv',
-    kKeyDecoderComponent = 'decC',
-    kKeyBufferID         = 'bfID',
+    kKeyMIMEType          = 'mime',
+    kKeyWidth             = 'widt',
+    kKeyHeight            = 'heig',
+    kKeyChannelCount      = '#chn',
+    kKeySampleRate        = 'srte',
+    kKeyBitRate           = 'brte',
+    kKeyESDS              = 'esds',
+    kKeyAVCC              = 'avcc',
+    kKeyTimeUnits         = '#tim',
+    kKeyTimeScale         = 'scal',
+    kKeyWantsNALFragments = 'NALf',
+    kKeyIsSyncFrame       = 'sync',
+    kKeyDuration          = 'dura',
+    kKeyColorFormat       = 'colf',
+    kKeyPlatformPrivate   = 'priv',
+    kKeyDecoderComponent  = 'decC',
+    kKeyBufferID          = 'bfID',
 };
 
 enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index d4ae349..c8ee255 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -79,7 +79,7 @@
 
     enum Quirks {
         kNeedsFlushBeforeDisable             = 1,
-        kWantsRawNALFrames                   = 2,
+        kWantsNALFragments                   = 2,
         kRequiresLoadedToIdleAfterAllocation = 4,
         kRequiresAllocateBufferOnInputPorts  = 8,
     };
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index 0abc5a6..99d803a 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -76,7 +76,7 @@
     };
 
     enum Quirks {
-        kWantsRawNALFrames                   = 1,
+        kWantsNALFragments                   = 1,
         kDoesntReturnBuffersOnDisable        = 2,
         kDoesntFlushOnExecutingToIdle        = 4,
         kDoesntProperlyFlushAllPortsAtOnce   = 8,
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 932a70a..5d231e6d 100644
--- a/include/ui/ISurfaceFlingerClient.h
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -52,6 +52,9 @@
     struct surface_data_t {
         int32_t             token;
         int32_t             identity;
+        uint32_t            width;
+        uint32_t            height;
+        uint32_t            format;
         status_t readFromParcel(const Parcel& parcel);
         status_t writeToParcel(Parcel* parcel) const;
     };
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index a67764e..f348a62 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -68,17 +68,18 @@
 
     int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
     int sqr = r * r;
+    float invs = 1.0f / s;
 
     int h = 0;
-    for ( ; h < r; h++) {
+    for ( ; h < r; h += 1) {
         int sqv = h * h;
         int yn = origin + (y - h) * (width + 2);
         int yp = origin + (y + h) * (width + 2);
         int w = 0;
-        for ( ; w < r; w++) {
+        for ( ; w < r; w += 1) {
             int squ = w * w;
             if (squ + sqv < sqr) {
-                int v = -sqrtf((sqr - (squ + sqv)) << 16) / s;
+                int v = -sqrtf((sqr - (squ + sqv)) << 16) * invs;
                 current[yn + x + w] = v;
                 current[yp + x + w] = v;
                 current[yn + x - w] = v;
@@ -110,16 +111,16 @@
     while (h) {
         int w = width;
         while (w) {
-            int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - next[0];
+            int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - *next;
             droplet -= (droplet >> DAMP);
-            next[0] = droplet;
-            current++;
-            next++;
-            w--;
+            *next = droplet;
+            current += 1;
+            next += 1;
+            w -= 1;
         }
         current += 2;
         next += 2;
-        h--;
+        h -= 1;
     }
 }
 
@@ -149,10 +150,14 @@
     int *map = loadArrayI32(RSID_REFRACTION_MAP, 0);
     float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
 
+    float fw = (float) width;
+    float fh = (float) height;
+    float fy = (1.0f / 512.0f) * (1.0f / RIPPLE_HEIGHT);
+
     int h = height - 1;
     while (h >= 0) {
         int w = width - 1;
-        int wave = current[0];
+        int wave = *current;
         int offset = h * width;
         while (w >= 0) {
             int nextWave = current[1];
@@ -169,40 +174,47 @@
             v &= ~(v >> 31);
             if (v >= height) v = height - 1;
 
-            vertices[(offset + w) * 8 + 3] = u / (float) width;
-            vertices[(offset + w) * 8 + 4] = v / (float) height;
+            int index = (offset + w) << 3;
+            vertices[index + 3] = u / fw;
+            vertices[index + 4] = v / fh;
 
             // Update Z coordinate of the vertex
-            vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
+            vertices[index + 7] = dy * fy;
             
-            w--;
-            current++;
+            w -= 1;
+            current += 1;
             wave = nextWave;
         }
-        h--;
+        h -= 1;
         current += 2;
     }
 
     // Compute the normals for lighting
     int y = 0;
-    for ( ; y < height; y++) {
+    int w8 = width << 3;
+    for ( ; y < height; y += 1) {
         int x = 0;
         int yOffset = y * width;
-        for ( ; x < width; x++) {
+        for ( ; x < width; x += 1) {
+            int o = (yOffset + x) << 3;
+            int o1 = o + 8;
+            int ow = o + w8;
+            int ow1 = ow + 8;
+
             // V1
-            float v1x = vertices[(yOffset + x) * 8 + 5];
-            float v1y = vertices[(yOffset + x) * 8 + 6];
-            float v1z = vertices[(yOffset + x) * 8 + 7];
+            float v1x = vertices[o + 5];
+            float v1y = vertices[o + 6];
+            float v1z = vertices[o + 7];
 
             // V2
-            float v2x = vertices[(yOffset + x + 1) * 8 + 5];
-            float v2y = vertices[(yOffset + x + 1) * 8 + 6];
-            float v2z = vertices[(yOffset + x + 1) * 8 + 7];
+            float v2x = vertices[o1 + 5];
+            float v2y = vertices[o1 + 6];
+            float v2z = vertices[o1 + 7];
             
             // V3
-            float v3x = vertices[(yOffset + width + x) * 8 + 5];
-            float v3y = vertices[(yOffset + width + x) * 8 + 6];
-            float v3z = vertices[(yOffset + width + x) * 8 + 7];
+            float v3x = vertices[ow + 5];
+            float v3y = vertices[ow + 6];
+            float v3z = vertices[ow + 7];
 
             // N1
             float n1x = v2x - v1x;
@@ -220,15 +232,15 @@
             float n3z = n1x * n2y - n1y * n2x;
 
             // Normalize
-            float len = magf3(n3x, n3y, n3z);
-            n3x /= len;
-            n3y /= len;
-            n3z /= len;
+            float len = 1.0f / magf3(n3x, n3y, n3z);
+            n3x *= len;
+            n3y *= len;
+            n3z *= len;
             
             // V2
-            v2x = vertices[(yOffset + width + x + 1) * 8 + 5];
-            v2y = vertices[(yOffset + width + x + 1) * 8 + 6];
-            v2z = vertices[(yOffset + width + x + 1) * 8 + 7];
+            v2x = vertices[ow1 + 5];
+            v2y = vertices[ow1 + 6];
+            v2z = vertices[ow1 + 7];
 
             // N1
             n1x = v2x - v1x;
@@ -240,23 +252,23 @@
             n2y = v3y - v1y;
             n2z = v3z - v1z;
 
-            // Avegare of previous normal and N1 x N2
-            n3x = n3x / 2.0f + (n1y * n2z - n1z * n2y) / 2.0f;
-            n3y = n3y / 2.0f + (n1z * n2x - n1x * n2z) / 2.0f;
-            n3z = n3z / 2.0f + (n1x * n2y - n1y * n2x) / 2.0f;
+            // Average of previous normal and N1 x N2
+            n3x = n3x * 0.5f + (n1y * n2z - n1z * n2y) * 0.5f;
+            n3y = n3y * 0.5f + (n1z * n2x - n1x * n2z) * 0.5f;
+            n3z = n3z * 0.5f + (n1x * n2y - n1y * n2x) * 0.5f;
 
             // Normalize
-            len = magf3(n3x, n3y, n3z);
-            n3x /= len;
-            n3y /= len;
-            n3z /= len;
+            len = 1.0f / magf3(n3x, n3y, n3z);
+            n3x *= len;
+            n3y *= len;
+            n3z *= len;
 
-            vertices[(yOffset + x) * 8 + 0] = n3x;
-            vertices[(yOffset + x) * 8 + 1] = n3y;
-            vertices[(yOffset + x) * 8 + 2] = -n3z;
+            vertices[o + 0] = n3x;
+            vertices[o + 1] = n3y;
+            vertices[o + 2] = -n3z;
             
             // reset Z
-            //vertices[(yOffset + x) * 8 + 7] = 0.0f;
+            //vertices[(yOffset + x) << 3 + 7] = 0.0f;
         }
     }
 }
@@ -264,10 +276,10 @@
 float averageZ(float x1, float x2, float y1, float y2, float* vertices,
         int meshWidth, int meshHeight, float glWidth, float glHeight) {
 
-    x1 = ((x1 + glWidth / 2.0f) / glWidth) * meshWidth;
-    x2 = ((x2 + glWidth / 2.0f) / glWidth) * meshWidth;
-    y1 = ((y1 + glHeight / 2.0f) / glHeight) * meshHeight;
-    y2 = ((y2 + glHeight / 2.0f) / glHeight) * meshHeight;
+    x1 = ((x1 + glWidth * 0.5f) / glWidth) * meshWidth;
+    x2 = ((x2 + glWidth * 0.5f) / glWidth) * meshWidth;
+    y1 = ((y1 + glHeight * 0.5f) / glHeight) * meshHeight;
+    y2 = ((y2 + glHeight * 0.5f) / glHeight) * meshHeight;
 
     int quadX1 = clamp(x1, 0, meshWidth);
     int quadX2 = clamp(x2, 0, meshWidth);
@@ -278,12 +290,12 @@
     int vertexCount = 0;
 
     int y = quadY1;
-    for ( ; y < quadY2; y++) {
+    for ( ; y < quadY2; y += 1) {
         int x = quadX1;
         int yOffset = y * meshWidth;
-        for ( ; x < quadX2; x++) {
-            z += vertices[(yOffset + x) * 8 + 7];
-            vertexCount++;
+        for ( ; x < quadX2; x += 1) {
+            z += vertices[(yOffset + x) << 3 + 7];
+            vertexCount += 1;
         }
     }
 
@@ -319,10 +331,10 @@
     if (a > 0.0f) {
         tz = -a;
     } else {
-        z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
-        z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
-        z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
-        z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+//        z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
     }
 
     x1 -= x;
@@ -346,8 +358,8 @@
     if (a <= 0.0f) {
         float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
         if (rippled < 0.0f) {
-            drop(((x + glWidth / 2.0f) / glWidth) * meshWidth,
-                 meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+            drop(((x + glWidth * 0.5f) / glWidth) * meshWidth,
+                 meshHeight - ((y + glHeight * 0.5f) / glHeight) * meshHeight,
                  DROP_RADIUS);
             spin /= 4.0f;
             leafStruct[LEAF_STRUCT_SPIN] = spin;
@@ -454,6 +466,35 @@
     drawTriangleMesh(NAMED_WaterMesh);
 }
 
+void drawNormals() {
+    int width = State_meshWidth;
+    int height = State_meshHeight;
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+    bindProgramVertex(NAMED_PVSky);
+    bindProgramFragment(NAMED_PFLighting);
+
+    color(1.0f, 0.0f, 0.0f, 1.0f);
+
+    float scale = 1.0f / 10.0f;
+    int y = 0;
+    for ( ; y < height; y += 1) {
+        int yOffset = y * width;
+        int x = 0;
+        for ( ; x < width; x += 1) {
+            int offset = (yOffset + x) << 3;
+            float vx = vertices[offset + 5];
+            float vy = vertices[offset + 6];
+            float vz = vertices[offset + 7];
+            float nx = vertices[offset + 0];
+            float ny = vertices[offset + 1];
+            float nz = vertices[offset + 2];
+            drawLine(vx, vy, vz, vx + nx * scale, vy + ny * scale, vz + nz * scale);
+        }
+    }
+}
+
 int main(int index) {
     int dropX = Drop_dropX;
     if (dropX != -1) {
@@ -471,6 +512,7 @@
     drawSky();
     drawLighting();
     drawLeaves();
+    //drawNormals();
 
     return 1;
 }
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
index 02d4737..3b13bed 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -177,22 +177,37 @@
         hResolution += 2;        
         
         for (int y = 0; y <= hResolution; y++) {
+            final boolean shift = (y & 0x1) == 0;
             final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
             final float t = 1.0f - y / (float) hResolution;
             for (int x = 0; x <= wResolution; x++) {
-                rs.triangleMeshAddVertex_XYZ_ST_NORM(
-                        -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
-                        x / (float) wResolution, t,
-                        0.0f, 0.0f, -1.0f);
+                if (shift) {
+                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
+                            -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
+                            x / (float) wResolution, t,
+                            0.0f, 0.0f, -1.0f);
+                } else {
+                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
+                            -1.0f + x * quadWidth - quadWidth * 0.5f, yOffset, 0.0f,
+                            x / (float) wResolution, t,
+                            0.0f, 0.0f, -1.0f);
+                }
             }
         }
 
         for (int y = 0; y < hResolution; y++) {
+            final boolean shift = (y & 0x1) == 0;
+            final int yOffset = y * (wResolution + 1);
             for (int x = 0; x < wResolution; x++) {
-                final int index = y * (wResolution + 1) + x;
+                final int index = yOffset + x;
                 final int iWR1 = index + wResolution + 1;
-                rs.triangleMeshAddTriangle(index, index + 1, iWR1);
-                rs.triangleMeshAddTriangle(index + 1, iWR1, iWR1 + 1);
+                if (shift) {
+                    rs.triangleMeshAddTriangle(index, index + 1, iWR1);
+                    rs.triangleMeshAddTriangle(index + 1, iWR1 + 1, iWR1);
+                } else {
+                    rs.triangleMeshAddTriangle(index, iWR1 + 1, iWR1);
+                    rs.triangleMeshAddTriangle(index, index + 1, iWR1 + 1);
+                }
             }
         }
 
diff --git a/libs/rs/java/Galaxy/res/raw/galaxy.c b/libs/rs/java/Galaxy/res/raw/galaxy.c
index 59c31a1..9ff449f 100644
--- a/libs/rs/java/Galaxy/res/raw/galaxy.c
+++ b/libs/rs/java/Galaxy/res/raw/galaxy.c
@@ -19,11 +19,13 @@
 
 #define RSID_PARTICLES 1
 
-#define PARTICLE_STRUCT_FIELDS_COUNT 4
+#define PARTICLE_STRUCT_FIELDS_COUNT 6
 #define PARTICLE_STRUCT_ANGLE 0
 #define PARTICLE_STRUCT_DISTANCE 1
 #define PARTICLE_STRUCT_SPEED 2
 #define PARTICLE_STRUCT_RADIUS 3
+#define PARTICLE_STRUCT_S 4
+#define PARTICLE_STRUCT_T 5
 
 #define RSID_PARTICLES_BUFFER 2
 #define PARTICLE_BUFFER_COMPONENTS_COUNT 5
@@ -31,19 +33,14 @@
 #define PARTICLES_TEXTURES_COUNT 2
 
 #define ELLIPSE_RATIO 0.892f
-#define ELLIPSE_TWIST 0.02333333333f
 
 void drawSpace(int width, int height) {
     bindTexture(NAMED_PFBackground, 0, NAMED_TSpace);
     drawQuadTexCoords(
-            0.0f, 0.0f, 0.0f,
-            0.0f, 1.0f,
-            width, 0.0f, 0.0f,
-            2.0f, 1.0f,
-            width, height, 0.0f,
-            2.0f, 0.0f,
-            0.0f, height, 0.0f,
-            0.0f, 0.0f);
+            0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+            width, 0.0f, 0.0f, 2.0f, 1.0f,
+            width, height, 0.0f, 2.0f, 0.0f,
+            0.0f, height, 0.0f, 0.0f, 0.0f);
 }
 
 void drawLights(int width, int height) {
@@ -61,39 +58,34 @@
              x + 512.0f * 1.1f, y + 512.0f, 0.0f);
 }
 
-void drawParticle(float *particle, int index, float *particleBuffer, int bufferIndex,
-        float w, float h) {
-
-    float distance = particle[index + PARTICLE_STRUCT_DISTANCE];
-    float angle = particle[index + PARTICLE_STRUCT_ANGLE];
-    float speed = particle[index + PARTICLE_STRUCT_SPEED];
-    float r = particle[index + PARTICLE_STRUCT_RADIUS];
+void drawParticle(float *particle, float *particleBuffer, float w, float h) {
+    float distance = particle[PARTICLE_STRUCT_DISTANCE];
+    float angle = particle[PARTICLE_STRUCT_ANGLE];
+    float speed = particle[PARTICLE_STRUCT_SPEED];
+    float r = particle[PARTICLE_STRUCT_RADIUS];
 
     float a = angle + speed;
     float x = distance * sinf_fast(a);
     float y = distance * cosf_fast(a) * ELLIPSE_RATIO;
-    float z = distance * ELLIPSE_TWIST;
-    float s = cosf_fast(z);
-    float t = sinf_fast(z);
+    float s = particle[PARTICLE_STRUCT_S];
+    float t = particle[PARTICLE_STRUCT_T];
 
     float sX = t * x + s * y + w;
     float sY = s * x - t * y + h;
 
     // lower left vertex of the particle's triangle
-    particleBuffer[bufferIndex + 1] = sX - r;     // X
-    particleBuffer[bufferIndex + 2] = sY + r;     // Y
+    particleBuffer[1] = sX - r;     // X
+    particleBuffer[2] = sY + r;     // Y
 
     // lower right vertex of the particle's triangle
-    bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT;
-    particleBuffer[bufferIndex + 1] = sX + r;     // X
-    particleBuffer[bufferIndex + 2] = sY + r;     // Y
+    particleBuffer[6] = sX + r;     // X
+    particleBuffer[7] = sY + r;     // Y
 
     // upper middle vertex of the particle's triangle
-    bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT;
-    particleBuffer[bufferIndex + 1] = sX;         // X
-    particleBuffer[bufferIndex + 2] = sY - r;     // Y
+    particleBuffer[11] = sX;         // X
+    particleBuffer[12] = sY - r;     // Y
 
-    particle[index + PARTICLE_STRUCT_ANGLE] = a;
+    particle[PARTICLE_STRUCT_ANGLE] = a;
 }
 
 void drawParticles(int width, int height) {
@@ -103,7 +95,6 @@
 
     int radius = State_galaxyRadius;
     int particlesCount = State_particlesCount;
-    int count = particlesCount * PARTICLE_STRUCT_FIELDS_COUNT;
 
     float *particle = loadArrayF(RSID_PARTICLES, 0);
     float *particleBuffer = loadArrayF(RSID_PARTICLES_BUFFER, 0);
@@ -112,11 +103,11 @@
     float h = height * 0.5f;
 
     int i = 0;
-    int bufferIndex = 0;
-    for ( ; i < count; i += PARTICLE_STRUCT_FIELDS_COUNT) {
-        drawParticle(particle, i, particleBuffer, bufferIndex, w, h);
-        // each particle is a triangle (3 vertices) of 6 properties (ABGR, X, Y, Z, S, T)
-        bufferIndex += 3 * PARTICLE_BUFFER_COMPONENTS_COUNT;
+    for ( ; i < particlesCount; i++) {
+        drawParticle(particle, particleBuffer, w, h);
+        particle += PARTICLE_STRUCT_FIELDS_COUNT;
+        // each particle is a triangle (3 vertices) of 5 properties (ABGR, X, Y, S, T)
+        particleBuffer += 3 * PARTICLE_BUFFER_COMPONENTS_COUNT;
     }
 
     uploadToBufferObject(NAMED_ParticlesBuffer);
diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java
index 717100d..c6f5816 100644
--- a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java
+++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java
@@ -42,9 +42,11 @@
 
 import java.util.TimeZone;
 
+@SuppressWarnings({"FieldCanBeLocal"})
 class GalaxyRS {
     private static final int GALAXY_RADIUS = 300;
     private static final int PARTICLES_COUNT = 12000;
+    private static final float ELLIPSE_TWIST = 0.023333333f;
 
     private static final int RSID_STATE = 0;
 
@@ -54,11 +56,13 @@
     private static final int RSID_TEXTURE_FLARES = 2;
 
     private static final int RSID_PARTICLES = 1;
-    private static final int PARTICLE_STRUCT_FIELDS_COUNT = 4;
+    private static final int PARTICLE_STRUCT_FIELDS_COUNT = 6;
     private static final int PARTICLE_STRUCT_ANGLE = 0;
     private static final int PARTICLE_STRUCT_DISTANCE = 1;
     private static final int PARTICLE_STRUCT_SPEED = 2;
     private static final int PARTICLE_STRUCT_RADIUS = 3;
+    private static final int PARTICLE_STRUCT_S = 4;
+    private static final int PARTICLE_STRUCT_T = 5;
 
     private static final int RSID_PARTICLES_BUFFER = 2;
 
@@ -103,35 +107,6 @@
         initRS();
     }
 
-    public void destroy() {
-        mScript.destroy();
-        mSampler.destroy();
-        mLightSampler.destroy();
-        mPfBackground.destroy();
-        mPfsBackground.destroy();
-        mPvBackground.destroy();
-        mPvOrthoAlloc.mAlloc.destroy();
-        for (Allocation a : mTextures) {
-            a.destroy();
-        }
-        mState.destroy();
-        mPfLighting.destroy();
-        mParticles.destroy();
-        mPfsLights.destroy();
-        mParticlesMesh.destroy();
-        mParticlesBuffer.destroy();
-        mStateType.destroy();
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            destroy();
-        } finally {
-            super.finalize();
-        }
-    }
-
     private void initRS() {
         createProgramVertex();
         createProgramFragmentStore();
@@ -218,13 +193,16 @@
         float d = abs(randomGauss()) * GALAXY_RADIUS / 2.0f + random(-4.0f, 4.0f);
         float z = randomGauss() * 0.5f * 0.8f * ((GALAXY_RADIUS - d) / (float) GALAXY_RADIUS);
         z += 1.0f;
+        float p = d * ELLIPSE_TWIST;
 
         particles[index + PARTICLE_STRUCT_ANGLE] = random(0.0f, (float) (Math.PI * 2.0));
         particles[index + PARTICLE_STRUCT_DISTANCE] = d;
         particles[index + PARTICLE_STRUCT_SPEED] = random(0.0015f, 0.0025f) *
                 (0.5f + (0.5f * (float) GALAXY_RADIUS / d)) * 0.7f;
         particles[index + PARTICLE_STRUCT_RADIUS] = z * random(1.2f, 2.1f);
-
+        particles[index + PARTICLE_STRUCT_S] = (float) Math.cos(p);
+        particles[index + PARTICLE_STRUCT_T] = (float) Math.sin(p);
+        
         int red, green, blue;
         if (d < GALAXY_RADIUS / 3.0f) {
             red = (int) (220 + (d / (float) GALAXY_RADIUS) * 35);
diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java
index 341293b..4f6d3f0 100644
--- a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java
+++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java
@@ -22,8 +22,6 @@
 import android.renderscript.RSSurfaceView;
 
 class GalaxyView extends RSSurfaceView {
-    private GalaxyRS mRender;
-
     public GalaxyView(Context context) {
         super(context);
         setFocusable(true);
@@ -34,12 +32,7 @@
         super.surfaceChanged(holder, format, w, h);
 
         RenderScript RS = createRenderScript();
-        mRender = new GalaxyRS(w, h);
-        mRender.init(RS, getResources());
-    }
-
-    @Override
-    public void surfaceDestroyed(SurfaceHolder holder) {
-        if (mRender != null) mRender.destroy();
+        GalaxyRS render = new GalaxyRS(w, h);
+        render.init(RS, getResources());
     }
 }
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 7bfa81ed..413caab 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -25,7 +25,6 @@
 using namespace android;
 using namespace android::renderscript;
 
-Context * Context::gCon = NULL;
 pthread_key_t Context::gThreadTLSKey = 0;
 
 void Context::initEGL()
@@ -84,6 +83,9 @@
 
 bool Context::runRootScript()
 {
+#if RS_LOG_TIMES
+    timerSet(RS_TIMER_CLEAR_SWAP);
+#endif
     rsAssert(mRootScript->mEnviroment.mIsRoot);
 
     //glColor4f(1,1,1,1);
@@ -102,24 +104,55 @@
     glClear(GL_DEPTH_BUFFER_BIT);
 
 #if RS_LOG_TIMES
-    struct timespec startTime;
-    clock_gettime(CLOCK_MONOTONIC, &startTime);
+    timerSet(RS_TIMER_SCRIPT);
 #endif
     bool ret = runScript(mRootScript.get(), 0);
-
-#if RS_LOG_TIMES
-    struct timespec endTime;
-    clock_gettime(CLOCK_MONOTONIC, &endTime);
-
-    uint64_t t1 = endTime.tv_nsec + ((uint64_t)endTime.tv_sec * 1000 * 1000 * 1000);
-    uint64_t t2 = startTime.tv_nsec + ((uint64_t)startTime.tv_sec * 1000 * 1000 * 1000);
-    int t3 = (int)((t1 - t2) / 1000 / 1000);
-    LOGE("times  %i", t3);
-#endif
-
     return ret;
 }
 
+uint64_t Context::getTime() const
+{
+    struct timespec t;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+void Context::timerReset()
+{
+    for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) {
+        mTimers[ct] = 0;
+    }
+}
+
+void Context::timerInit()
+{
+    mTimeLast = getTime();
+    mTimerActive = RS_TIMER_INTERNAL;
+    timerReset();
+}
+
+void Context::timerSet(Timers tm)
+{
+    uint64_t last = mTimeLast;
+    mTimeLast = getTime();
+    mTimers[mTimerActive] += mTimeLast - last;
+    mTimerActive = tm;
+}
+
+void Context::timerPrint()
+{
+    double total = 0;
+    for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) {
+        total += mTimers[ct];
+    }
+
+    LOGV("RS Time Data: Idle %2.1f (%lli),  Internal %2.1f (%lli),  Script %2.1f (%lli),  Clear & Swap %2.1f (%lli)",
+         100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
+         100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000,
+         100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000,
+         100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimers[RS_TIMER_CLEAR_SWAP] / 1000000);
+}
+
 void Context::setupCheck()
 {
     if (mFragmentStore.get()) {
@@ -168,9 +201,19 @@
 
          if (mDraw) {
              mDraw = rsc->runRootScript();
+#if RS_LOG_TIMES
+             rsc->timerSet(RS_TIMER_CLEAR_SWAP);
+#endif
              eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+#if RS_LOG_TIMES
+             rsc->timerSet(RS_TIMER_INTERNAL);
+             rsc->timerPrint();
+             rsc->timerReset();
+#endif
          }
-         rsc->objDestroyOOBRun();
+         if (rsc->mObjDestroy.mNeedToEmpty) {
+             rsc->objDestroyOOBRun();
+         }
      }
 
      glClearColor(0,0,0,0);
@@ -188,9 +231,6 @@
     mRunning = false;
     mExit = false;
 
-    // see comment in header
-    gCon = this;
-
     int status;
     pthread_attr_t threadAttr;
 
@@ -213,6 +253,7 @@
     mWndSurface = sur;
 
     objDestroyOOBInit();
+    timerInit();
 
     LOGV("RS Launching thread");
     status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 52901b2..ca67e40 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -72,8 +72,6 @@
 
     ScriptCState mScriptC;
 
-    static Context * getContext() {return gCon;}
-
     void swapBuffers();
     void setRootScript(Script *);
     void setVertex(ProgramVertex *);
@@ -120,6 +118,20 @@
     ThreadIO mIO;
     void objDestroyAdd(ObjectBase *);
 
+    // Timers
+    enum Timers {
+        RS_TIMER_IDLE,
+        RS_TIMER_INTERNAL,
+        RS_TIMER_SCRIPT,
+        RS_TIMER_CLEAR_SWAP,
+        _RS_TIMER_TOTAL
+    };
+    uint64_t getTime() const;
+    void timerInit();
+    void timerReset();
+    void timerSet(Timers);
+    void timerPrint();
+
 protected:
     Device *mDev;
 
@@ -164,13 +176,15 @@
 
     static void * threadProc(void *);
 
-    // todo: put in TLS
-    static Context *gCon;
     Surface *mWndSurface;
 
     Vector<ObjectBase *> mNames;
     KeyedVector<String8,int> mInt32Defines;
     KeyedVector<String8,float> mFloatDefines;
+
+    uint64_t mTimers[_RS_TIMER_TOTAL];
+    Timers mTimerActive;
+    uint64_t mTimeLast;
 };
 
 
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 20b0a94..4a1dbbb 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -32,12 +32,18 @@
 
 bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
 {
-    uint32_t cmdID = 0;
-    uint32_t cmdSize = 0;
     bool ret = false;
     while(!mToCore.isEmpty() || waitForCommand) {
+        uint32_t cmdID = 0;
+        uint32_t cmdSize = 0;
         ret = true;
+#if RS_LOG_TIMES
+        con->timerSet(Context::RS_TIMER_IDLE);
+#endif
         const void * data = mToCore.get(&cmdID, &cmdSize);
+#if RS_LOG_TIMES
+        con->timerSet(Context::RS_TIMER_INTERNAL);
+#endif
         waitForCommand = false;
         //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 419574c..fd54e35 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -730,14 +730,6 @@
     return owner;
 }
 
-
-void LayerBaseClient::Surface::getSurfaceData(
-        ISurfaceFlingerClient::surface_data_t* params) const 
-{
-    params->token = mToken;
-    params->identity = mIdentity;
-}
-
 status_t LayerBaseClient::Surface::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 65bf55b..7791941 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -321,10 +321,9 @@
     class Surface : public BnSurface 
     {
     public:
+        int32_t getToken() const { return mToken; }
+        int32_t getIdentity() const { return mIdentity; }
         
-        virtual void getSurfaceData(
-                ISurfaceFlingerClient::surface_data_t* params) const;
-
     protected:
         Surface(const sp<SurfaceFlinger>& flinger, 
                 SurfaceID id, int identity, 
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 5e74451..dd61e1a 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -97,11 +97,9 @@
     err = allocator.alloc(w, h, format, usage, &handle, &stride);
     
     if (err == NO_ERROR) {
-        if (err == NO_ERROR) {
-            width  = w;
-            height = h;
-            mVStride = 0;
-        }
+        width  = w;
+        height = h;
+        mVStride = 0;
     }
 
     return err;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 102899c..3824024 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1239,9 +1239,11 @@
     switch (flags & eFXSurfaceMask) {
         case eFXSurfaceNormal:
             if (UNLIKELY(flags & ePushBuffers)) {
-                layer = createPushBuffersSurfaceLocked(client, d, id, w, h, flags);
+                layer = createPushBuffersSurfaceLocked(client, d, id,
+                        w, h, flags);
             } else {
-                layer = createNormalSurfaceLocked(client, d, id, w, h, format, flags);
+                layer = createNormalSurfaceLocked(client, d, id,
+                        w, h, flags, format);
             }
             break;
         case eFXSurfaceBlur:
@@ -1255,8 +1257,13 @@
     if (layer != 0) {
         setTransactionFlags(eTransactionNeeded);
         surfaceHandle = layer->getSurface();
-        if (surfaceHandle != 0)
-            surfaceHandle->getSurfaceData(params);
+        if (surfaceHandle != 0) { 
+            params->token = surfaceHandle->getToken();
+            params->identity = surfaceHandle->getIdentity();
+            params->width = w;
+            params->height = h;
+            params->format = format;
+        }
     }
 
     return surfaceHandle;
@@ -1264,7 +1271,8 @@
 
 sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
         const sp<Client>& client, DisplayID display,
-        int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+        int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+        PixelFormat& format)
 {
     // initialize the surfaces
     switch (format) { // TODO: take h/w into account
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 2569a0f..56ea97a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -195,8 +195,8 @@
 
     sp<LayerBaseClient> createNormalSurfaceLocked(
             const sp<Client>& client, DisplayID display,
-            int32_t id, uint32_t w, uint32_t h, 
-            PixelFormat format, uint32_t flags);
+            int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+            PixelFormat& format);
 
     sp<LayerBaseClient> createBlurSurfaceLocked(
             const sp<Client>& client, DisplayID display,
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index 51e8422..4a6a1d7 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -189,8 +189,11 @@
 
 status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
 {
-    token = parcel.readInt32();
-    identity  = parcel.readInt32();
+    token    = parcel.readInt32();
+    identity = parcel.readInt32();
+    width    = parcel.readInt32();
+    height   = parcel.readInt32();
+    format   = parcel.readInt32();
     return NO_ERROR;
 }
 
@@ -198,6 +201,9 @@
 {
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
+    parcel->writeInt32(width);
+    parcel->writeInt32(height);
+    parcel->writeInt32(format);
     return NO_ERROR;
 }
 
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index f6792c4..36a10cf 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -64,11 +64,16 @@
 {
     // we own the handle in this case
     width  = data.readInt32();
-    height = data.readInt32();
-    stride = data.readInt32();
-    format = data.readInt32();
-    usage  = data.readInt32();
-    handle = data.readNativeHandle();
+    if (width < 0) {
+        width = height = stride = format = usage = 0;
+        handle = 0;
+    } else {
+        height = data.readInt32();
+        stride = data.readInt32();
+        format = data.readInt32();
+        usage  = data.readInt32();
+        handle = data.readNativeHandle();
+    }
 }
 
 SurfaceBuffer::~SurfaceBuffer()
@@ -108,16 +113,25 @@
 status_t SurfaceBuffer::writeToParcel(Parcel* reply, 
         android_native_buffer_t const* buffer)
 {
-    if (buffer == NULL) {
+    if (buffer == NULL)
         return BAD_VALUE;
+
+    if (buffer->width < 0 || buffer->height < 0)
+        return BAD_VALUE;
+
+    status_t err = NO_ERROR;
+    if (buffer->handle == NULL) {
+        // this buffer doesn't have a handle
+        reply->writeInt32(NO_MEMORY);
+    } else {
+        reply->writeInt32(buffer->width);
+        reply->writeInt32(buffer->height);
+        reply->writeInt32(buffer->stride);
+        reply->writeInt32(buffer->format);
+        reply->writeInt32(buffer->usage);
+        err = reply->writeNativeHandle(buffer->handle);
     }
-    reply->writeInt32(buffer->width);
-    reply->writeInt32(buffer->height);
-    reply->writeInt32(buffer->stride);
-    reply->writeInt32(buffer->format);
-    reply->writeInt32(buffer->usage);
-    reply->writeNativeHandle(buffer->handle);
-    return NO_ERROR;
+    return err;
 }
 
 // ----------------------------------------------------------------------
@@ -183,7 +197,8 @@
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
     : mClient(client), mSurface(surface),
       mToken(data.token), mIdentity(data.identity),
-      mWidth(w), mHeight(h), mFormat(format), mFlags(flags)
+      mWidth(data.width), mHeight(data.height), mFormat(data.format),
+      mFlags(flags)
 {
 }
         
@@ -434,7 +449,7 @@
     // this is a client-side operation, the surface is destroyed, unmap
     // its buffers in this process.
     for (int i=0 ; i<2 ; i++) {
-        if (mBuffers[i] != 0) {
+        if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
             getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
         }
     }
@@ -590,17 +605,24 @@
     if ((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged) {
         mUsageChanged = false;
         err = getBufferLocked(backIdx, mUsage);
+        if (err == NO_ERROR) {
+            // reset the width/height with the what we get from the buffer
+            const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+            mWidth  = uint32_t(backBuffer->width);
+            mHeight = uint32_t(backBuffer->height);
+        }
     }
 
     if (err == NO_ERROR) {
         const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
-        // reset the width/height with the what we get from the buffer
-        mWidth  = uint32_t(backBuffer->width);
-        mHeight = uint32_t(backBuffer->height);
-        mDirtyRegion.set(backBuffer->width, backBuffer->height);
-        *buffer = backBuffer.get();
+        if (backBuffer != 0) {
+            mDirtyRegion.set(backBuffer->width, backBuffer->height);
+            *buffer = backBuffer.get();
+        } else {
+            err = NO_MEMORY;
+        }
     }
-  
+
     return err;
 }
 
@@ -716,7 +738,8 @@
             } else {
                 newDirtyRegion.andSelf(bounds);
                 const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
-                if (backBuffer->width  == frontBuffer->width && 
+                if (frontBuffer !=0 &&
+                    backBuffer->width  == frontBuffer->width && 
                     backBuffer->height == frontBuffer->height &&
                     !(lcblk->flags & eNoCopyBack)) 
                 {
@@ -788,18 +811,24 @@
     if (s == 0) return NO_INIT;
 
     status_t err = NO_MEMORY;
+
+    // free the current buffer
+    sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
+    if (currentBuffer != 0) {
+        getBufferMapper().unregisterBuffer(currentBuffer->handle);
+        currentBuffer.clear();
+    }
+
     sp<SurfaceBuffer> buffer = s->getBuffer(usage);
     LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
-    if (buffer != 0) {
-        sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
-        if (currentBuffer != 0) {
-            getBufferMapper().unregisterBuffer(currentBuffer->handle);
-            currentBuffer.clear();
-        }
-        err = getBufferMapper().registerBuffer(buffer->handle);
-        LOGW_IF(err, "registerBuffer(...) failed %d (%s)", err, strerror(-err));
-        if (err == NO_ERROR) {
-            currentBuffer = buffer;
+    if (buffer != 0) { // this should never happen by construction
+        if (buffer->handle != NULL) { 
+            err = getBufferMapper().registerBuffer(buffer->handle);
+            LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
+                    err, strerror(-err));
+            if (err == NO_ERROR) {
+                currentBuffer = buffer;
+            }
         }
     }
     return err; 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 05b68d4..0a1b142 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1391,21 +1391,26 @@
             } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
                 int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
                                                BluetoothHeadset.STATE_ERROR);
-                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
-                String address = btDevice.getAddress();
                 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-                int btClass = btDevice.getBluetoothClass();
-                if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) {
-                    switch (BluetoothClass.Device.getDevice(btClass)) {
-                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
-                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-                        break;
-                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
-                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                        break;
-                    default:
-                        break;
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                String address = null;
+                int btClass = BluetoothClass.ERROR;
+                if (btDevice != null) {
+                    address = btDevice.getAddress();
+                    btClass = btDevice.getBluetoothClass();
+                    if (BluetoothClass.Device.Major.getDeviceMajor(btClass) ==
+                                BluetoothClass.Device.Major.AUDIO_VIDEO) {
+                        switch (BluetoothClass.Device.getDevice(btClass)) {
+                        case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+                        case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+                            break;
+                        case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                            break;
+                        default:
+                            break;
+                        }
                     }
                 }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 662d5fb..894d46c 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,9 +19,6 @@
 
 #include <arpa/inet.h>
 
-#undef NDEBUG
-#include <assert.h>
-
 #include <ctype.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -31,6 +28,7 @@
 #include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SampleTable.h>
@@ -70,10 +68,8 @@
     MediaBufferGroup *mGroup;
 
     MediaBuffer *mBuffer;
-    size_t mBufferOffset;
-    size_t mBufferSizeRemaining;
 
-    bool mNeedsNALFraming;
+    bool mWantsNALFragments;
 
     uint8_t *mSrcBuffer;
 
@@ -138,7 +134,7 @@
             return "video/avc";
 
         default:
-            assert(!"should not be here.");
+            CHECK(!"should not be here.");
             return NULL;
     }
 }
@@ -279,7 +275,7 @@
                     return err;
                 }
             }
-            assert(*offset == stop_offset);
+            CHECK_EQ(*offset, stop_offset);
 
             if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
                 mHaveMetadata = true;
@@ -291,7 +287,7 @@
 
         case FOURCC('t', 'k', 'h', 'd'):
         {
-            assert(chunk_data_size >= 4);
+            CHECK(chunk_data_size >= 4);
 
             uint8_t version;
             if (mDataSource->read_at(data_offset, &version, 1) < 1) {
@@ -444,7 +440,7 @@
             }
 
             uint8_t buffer[8];
-            assert(chunk_data_size >= (off_t)sizeof(buffer));
+            CHECK(chunk_data_size >= (off_t)sizeof(buffer));
             if (mDataSource->read_at(
                         data_offset, buffer, 8) < 8) {
                 return ERROR_IO;
@@ -470,7 +466,7 @@
                     return err;
                 }
             }
-            assert(*offset == stop_offset);
+            CHECK_EQ(*offset, stop_offset);
             break;
         }
 
@@ -518,7 +514,7 @@
                     return err;
                 }
             }
-            assert(*offset == stop_offset);
+            CHECK_EQ(*offset, stop_offset);
             break;
         }
 
@@ -560,7 +556,7 @@
                     return err;
                 }
             }
-            assert(*offset == stop_offset);
+            CHECK_EQ(*offset, stop_offset);
             break;
         }
 
@@ -728,16 +724,14 @@
       mStarted(false),
       mGroup(NULL),
       mBuffer(NULL),
-      mBufferOffset(0),
-      mBufferSizeRemaining(0),
-      mNeedsNALFraming(false),
+      mWantsNALFragments(false),
       mSrcBuffer(NULL) {
     const char *mime;
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
-    assert(success);
+    CHECK(success);
 
     success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
-    assert(success);
+    CHECK(success);
 
     mIsAVC = !strcasecmp(mime, "video/avc");
 }
@@ -749,21 +743,21 @@
 }
 
 status_t MPEG4Source::start(MetaData *params) {
-    assert(!mStarted);
+    CHECK(!mStarted);
 
     int32_t val;
-    if (mIsAVC && params && params->findInt32(kKeyNeedsNALFraming, &val)
+    if (params && params->findInt32(kKeyWantsNALFragments, &val)
         && val != 0) {
-        mNeedsNALFraming = true;
+        mWantsNALFragments = true;
     } else {
-        mNeedsNALFraming = false;
+        mWantsNALFragments = false;
     }
 
     mGroup = new MediaBufferGroup;
 
     size_t max_size;
     status_t err = mSampleTable->getMaxSampleSize(&max_size);
-    assert(err == OK);
+    CHECK_EQ(err, OK);
 
     // Assume that a given buffer only contains at most 10 fragments,
     // each fragment originally prefixed with a 2 byte length will
@@ -779,7 +773,7 @@
 }
 
 status_t MPEG4Source::stop() {
-    assert(mStarted);
+    CHECK(mStarted);
 
     if (mBuffer != NULL) {
         mBuffer->release();
@@ -804,7 +798,7 @@
 
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
-    assert(mStarted);
+    CHECK(mStarted);
 
     *out = NULL;
 
@@ -830,38 +824,124 @@
 
     off_t offset;
     size_t size;
-    status_t err = mSampleTable->getSampleOffsetAndSize(
-            mCurrentSampleIndex, &offset, &size);
-
-    if (err != OK) {
-        return err;
-    }
-
     uint32_t dts;
-    err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+    bool newBuffer = false;
+    if (mBuffer == NULL) {
+        newBuffer = true;
 
-    if (err != OK) {
-        return err;
+        status_t err = mSampleTable->getSampleOffsetAndSize(
+                mCurrentSampleIndex, &offset, &size);
+
+        if (err != OK) {
+            return err;
+        }
+
+        err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+
+        if (err != OK) {
+            return err;
+        }
+
+        err = mGroup->acquire_buffer(&mBuffer);
+        if (err != OK) {
+            CHECK_EQ(mBuffer, NULL);
+            return err;
+        }
     }
 
-    err = mGroup->acquire_buffer(&mBuffer);
-    if (err != OK) {
-        assert(mBuffer == NULL);
-        return err;
-    }
+    if (!mIsAVC || mWantsNALFragments) {
+        if (newBuffer) {
+            ssize_t num_bytes_read =
+                mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
 
-    if (!mIsAVC || !mNeedsNALFraming) {
+            if (num_bytes_read < (ssize_t)size) {
+                mBuffer->release();
+                mBuffer = NULL;
+
+                return ERROR_IO;
+            }
+
+            mBuffer->set_range(0, size);
+            mBuffer->meta_data()->clear();
+            mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+            mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+            ++mCurrentSampleIndex;
+        }
+
+        if (!mIsAVC) {
+            *out = mBuffer;
+            mBuffer = NULL;
+
+            return OK;
+        }
+
+        // Each NAL unit is split up into its constituent fragments and
+        // each one of them returned in its own buffer.
+
+        CHECK(mBuffer->range_length() >= 2);
+
+        const uint8_t *src =
+            (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
+
+        size_t nal_size = U16_AT(src);
+
+        CHECK(mBuffer->range_length() >= 2 + nal_size);
+
+        MediaBuffer *clone = mBuffer->clone();
+        clone->set_range(mBuffer->range_offset() + 2, nal_size);
+
+        mBuffer->set_range(
+                mBuffer->range_offset() + 2 + nal_size,
+                mBuffer->range_length() - 2 - nal_size);
+
+        if (mBuffer->range_length() == 0) {
+            mBuffer->release();
+            mBuffer = NULL;
+        }
+
+        *out = clone;
+
+        return OK;
+    } else {
+        // Whole NAL units are returned but each fragment is prefixed by
+        // the start code (0x00 00 00 01).
+
         ssize_t num_bytes_read =
-            mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+            mDataSource->read_at(offset, mSrcBuffer, size);
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
-            return err;
+            return ERROR_IO;
         }
 
-        mBuffer->set_range(0, size);
+        uint8_t *dstData = (uint8_t *)mBuffer->data();
+        size_t srcOffset = 0;
+        size_t dstOffset = 0;
+        while (srcOffset < size) {
+            CHECK(srcOffset + 1 < size);
+            size_t nalLength =
+                (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+            CHECK(srcOffset + 1 + nalLength < size);
+            srcOffset += 2;
+
+            if (nalLength == 0) {
+                continue;
+            }
+
+            CHECK(dstOffset + 4 <= mBuffer->size());
+
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 1;
+            memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+            srcOffset += nalLength;
+            dstOffset += nalLength;
+        }
+
+        mBuffer->set_range(0, dstOffset);
         mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
         mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
@@ -872,52 +952,6 @@
 
         return OK;
     }
-
-    ssize_t num_bytes_read =
-        mDataSource->read_at(offset, mSrcBuffer, size);
-
-    if (num_bytes_read < (ssize_t)size) {
-        mBuffer->release();
-        mBuffer = NULL;
-
-        return err;
-    }
-
-    uint8_t *dstData = (uint8_t *)mBuffer->data();
-    size_t srcOffset = 0;
-    size_t dstOffset = 0;
-    while (srcOffset < size) {
-        assert(srcOffset + 1 < size);
-        size_t nalLength =
-            (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
-        assert(srcOffset + 1 + nalLength < size);
-        srcOffset += 2;
-
-        if (nalLength == 0) {
-            continue;
-        }
-
-        assert(dstOffset + 4 <= mBuffer->size());
-
-        dstData[dstOffset++] = 0;
-        dstData[dstOffset++] = 0;
-        dstData[dstOffset++] = 0;
-        dstData[dstOffset++] = 1;
-        memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
-        srcOffset += nalLength;
-        dstOffset += nalLength;
-    }
-
-    mBuffer->set_range(0, dstOffset);
-    mBuffer->meta_data()->clear();
-    mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
-    mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
-    ++mCurrentSampleIndex;
-
-    *out = mBuffer;
-    mBuffer = NULL;
-
-    return OK;
 }
 
 bool SniffMPEG4(
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 35d599c..1774eaf 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -30,6 +30,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MmapSource.h>
 #include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
 #include <utils/Vector.h>
 
 #include <OMX_Audio.h>
@@ -116,6 +117,39 @@
     return NULL;
 }
 
+enum {
+    kAVCProfileBaseline      = 0x42,
+    kAVCProfileMain          = 0x4d,
+    kAVCProfileExtended      = 0x58,
+    kAVCProfileHigh          = 0x64,
+    kAVCProfileHigh10        = 0x6e,
+    kAVCProfileHigh422       = 0x7a,
+    kAVCProfileHigh444       = 0xf4,
+    kAVCProfileCAVLC444Intra = 0x2c
+};
+
+static const char *AVCProfileToString(uint8_t profile) {
+    switch (profile) {
+        case kAVCProfileBaseline:
+            return "Baseline";
+        case kAVCProfileMain:
+            return "Main";
+        case kAVCProfileExtended:
+            return "Extended";
+        case kAVCProfileHigh:
+            return "High";
+        case kAVCProfileHigh10:
+            return "High 10";
+        case kAVCProfileHigh422:
+            return "High 422";
+        case kAVCProfileHigh444:
+            return "High 444";
+        case kAVCProfileCAVLC444Intra:
+            return "CAVLC 444 Intra";
+        default:   return "Unknown";
+    }
+}
+
 // static
 sp<OMXCodec> OMXCodec::Create(
         const sp<IOMX> &omx,
@@ -152,7 +186,7 @@
 
     uint32_t quirks = 0;
     if (!strcmp(componentName, "OMX.PV.avcdec")) {
-        quirks |= kWantsRawNALFrames;
+        quirks |= kWantsNALFragments;
     }
     if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
         quirks |= kNeedsFlushBeforeDisable;
@@ -189,29 +223,72 @@
     } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
         printf("found avcc of size %d\n", size);
 
-        const uint8_t *ptr = (const uint8_t *)data + 6;
+        // Parse the AVCDecoderConfigurationRecord
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        CHECK(size >= 7);
+        CHECK_EQ(ptr[0], 1);  // configurationVersion == 1
+        uint8_t profile = ptr[1];
+        uint8_t level = ptr[3];
+
+        CHECK((ptr[4] >> 2) == 0x3f);  // reserved
+
+        size_t lengthSize = 1 + (ptr[4] & 3);
+
+        // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+        // violates it...
+        // CHECK((ptr[5] >> 5) == 7);  // reserved
+
+        size_t numSeqParameterSets = ptr[5] & 31;
+
+        ptr += 6;
         size -= 6;
-        while (size >= 2) {
-            size_t length = ptr[0] << 8 | ptr[1];
+
+        for (size_t i = 0; i < numSeqParameterSets; ++i) {
+            CHECK(size >= 2);
+            size_t length = U16_AT(ptr);
 
             ptr += 2;
             size -= 2;
 
-            // printf("length = %d, size = %d\n", length, size);
-
             CHECK(size >= length);
 
             codec->addCodecSpecificData(ptr, length);
 
             ptr += length;
             size -= length;
+        }
 
-            if (size <= 1) {
-                break;
-            }
+        CHECK(size >= 1);
+        size_t numPictureParameterSets = *ptr;
+        ++ptr;
+        --size;
 
-            ptr++;  // XXX skip trailing 0x01 byte???
-            --size;
+        for (size_t i = 0; i < numPictureParameterSets; ++i) {
+            CHECK(size >= 2);
+            size_t length = U16_AT(ptr);
+
+            ptr += 2;
+            size -= 2;
+
+            CHECK(size >= length);
+
+            codec->addCodecSpecificData(ptr, length);
+
+            ptr += length;
+            size -= length;
+        }
+
+        LOGI("AVC profile = %d (%s), level = %d",
+             (int)profile, AVCProfileToString(profile), (int)level / 10);
+
+        if (!strcmp(componentName, "OMX.TI.Video.Decoder")
+            && (profile != kAVCProfileBaseline || level > 39)) {
+            // This stream exceeds the decoder's capabilities.
+
+            LOGE("Profile and/or level exceed the decoder's capabilities.");
+            return NULL;
         }
     }
 
@@ -529,7 +606,7 @@
 
 OMXCodec::OMXCodec(
         const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
-        bool isEncoder, 
+        bool isEncoder,
         const char *mime,
         const char *componentName,
         const sp<MediaSource> &source)
@@ -554,7 +631,7 @@
 }
 
 OMXCodec::~OMXCodec() {
-    CHECK_EQ(mState, LOADED);
+    CHECK(mState == LOADED || mState == ERROR);
 
     status_t err = mOMX->observe_node(mNode, NULL);
     CHECK_EQ(err, OK);
@@ -569,7 +646,7 @@
 
     free(mComponentName);
     mComponentName = NULL;
-    
+
     free(mMIME);
     mMIME = NULL;
 }
@@ -772,7 +849,7 @@
                 mBufferFilled.signal();
             } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
                 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
-                
+
                 MediaBuffer *buffer = info->mMediaBuffer;
 
                 buffer->set_range(
@@ -1149,8 +1226,8 @@
 
         size_t size = specific->mSize;
 
-        if (!strcasecmp(mMIME, "video/avc")
-            && !(mQuirks & kWantsRawNALFrames)) {
+        if (!strcasecmp("video/avc", mMIME)
+                && !(mQuirks & kWantsNALFragments)) {
             static const uint8_t kNALStartCode[4] =
                     { 0x00, 0x00, 0x00, 0x01 };
 
@@ -1383,7 +1460,7 @@
     CHECK_EQ(def.eDomain, OMX_PortDomainImage);
 
     OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
-    
+
     CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
     imageDef->eColorFormat = format;
     imageDef->nFrameWidth = width;
@@ -1460,10 +1537,10 @@
     if (mState != LOADED) {
         return UNKNOWN_ERROR;
     }
-    
+
     sp<MetaData> params = new MetaData;
-    if (!strcasecmp(mMIME, "video/avc") && !(mQuirks & kWantsRawNALFrames)) {
-        params->setInt32(kKeyNeedsNALFraming, true);
+    if (mQuirks & kWantsNALFragments) {
+        params->setInt32(kKeyWantsNALFragments, true);
     }
     status_t err = mSource->start(params.get());
 
@@ -1630,7 +1707,7 @@
         "OMX_COLOR_Format16bitBGR565",
         "OMX_COLOR_Format18bitRGB666",
         "OMX_COLOR_Format18bitARGB1665",
-        "OMX_COLOR_Format19bitARGB1666", 
+        "OMX_COLOR_Format19bitARGB1666",
         "OMX_COLOR_Format24bitRGB888",
         "OMX_COLOR_Format24bitBGR888",
         "OMX_COLOR_Format24bitARGB1887",
@@ -1653,11 +1730,11 @@
         "OMX_COLOR_FormatRawBayer8bit",
         "OMX_COLOR_FormatRawBayer10bit",
         "OMX_COLOR_FormatRawBayer8bitcompressed",
-        "OMX_COLOR_FormatL2", 
-        "OMX_COLOR_FormatL4", 
-        "OMX_COLOR_FormatL8", 
-        "OMX_COLOR_FormatL16", 
-        "OMX_COLOR_FormatL24", 
+        "OMX_COLOR_FormatL2",
+        "OMX_COLOR_FormatL4",
+        "OMX_COLOR_FormatL8",
+        "OMX_COLOR_FormatL16",
+        "OMX_COLOR_FormatL24",
         "OMX_COLOR_FormatL32",
         "OMX_COLOR_FormatYUV420PackedSemiPlanar",
         "OMX_COLOR_FormatYUV422PackedSemiPlanar",
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index 94cca43..cf08fa5 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -139,7 +139,7 @@
 
     uint32_t quirks = 0;
     if (!strcmp(codec, "OMX.PV.avcdec")) {
-        quirks |= kWantsRawNALFrames;
+        quirks |= kWantsNALFragments;
     }
     if (!strcmp(codec, "OMX.TI.AAC.decode")
         || !strcmp(codec, "OMX.TI.MP3.decode")) {
@@ -274,8 +274,8 @@
     // mDealer->dump("Decoder Dealer");
 
     sp<MetaData> params = new MetaData;
-    if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
-        params->setInt32(kKeyNeedsNALFraming, true);
+    if (mQuirks & kWantsNALFragments) {
+        params->setInt32(kKeyWantsNALFragments, true);
     }
 
     status_t err = mSource->start(params.get());
@@ -1331,7 +1331,7 @@
 
         size_t range_length = 0;
 
-        if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
+        if (mIsAVC && !(mQuirks & kWantsNALFragments)) {
             assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
 
             memcpy(mem->pointer(), kNALStartCode, 4);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a00a756..7ca8b52 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -405,6 +405,7 @@
     // If non-null, this is the currently visible window that is associated
     // with the wallpaper.
     WindowState mWallpaperTarget = null;
+    WindowState mUpcomingWallpaperTarget = null;
     int mWallpaperAnimLayerAdjustment;
     
     AppWindowToken mFocusedApp = null;
@@ -1178,60 +1179,136 @@
     boolean adjustWallpaperWindowsLocked() {
         boolean changed = false;
         
+        mUpcomingWallpaperTarget = null;
+        
         // First find top-most window that has asked to be on top of the
         // wallpaper; all wallpapers go behind it.
         final ArrayList localmWindows = mWindows;
         int N = localmWindows.size();
         WindowState w = null;
+        WindowState foundW = null;
+        int foundI = 0;
+        AppWindowToken topToken = null;
+        AppWindowToken behindToken = null;
         int i = N;
-        boolean visible = false;
         while (i > 0) {
             i--;
             w = (WindowState)localmWindows.get(i);
+            if (topToken != null) {
+                if (w.mAppToken == topToken) {
+                    continue;
+                }
+                if (w.mAppToken != null) {
+                    if (behindToken == null) {
+                        // We need to look through for what is behind the
+                        // potential new wallpaper target...  skip all tokens
+                        // that are hidden and not animating, since they can't
+                        // be involved with the transition.
+                        if (w.mAppToken.hidden && w.mAppToken.animation == null) {
+                            continue;
+                        }
+                        behindToken = w.mAppToken;
+                    }
+                    if (w.mAppToken != behindToken) {
+                        break;
+                    }
+                }
+            }
             if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
                     && !w.mDrawPending && !w.mCommitDrawPending) {
-                visible = true;
+                if (behindToken != null && w.mAppToken == behindToken) {
+                    // We had previously found a wallpaper window that was
+                    // animating, and now we found one behind it.  We could
+                    // be doing an animation between two windows on top of
+                    // the wallpaper!
+                    if (mWallpaperTarget == w || mWallpaperTarget == foundW) {
+                        // Retain the current wallpaper target (don't move
+                        // the wallpaper yet), but note the window that is
+                        // going to become the wallpaper target so that
+                        // others know about this special state.
+                        if (DEBUG_WALLPAPER) Log.v(TAG,
+                                "Switching wallpaper activities: cur#" + i + "="
+                                + w + " upcoming#" + foundI + "=" + foundW);
+                        mUpcomingWallpaperTarget = foundW;
+                        foundW = w;
+                        foundI = i;
+                        break;
+                    }
+                }
+                foundW = w;
+                foundI = i;
+                if (w.mAppToken != null && w.mAppToken.animation != null) {
+                    // If this app token is animating, we want to keep the
+                    // wallpaper below it if it is animating on top of another
+                    // app with a wallpaper.
+                    topToken = w.mAppToken;
+                    continue;
+                }
                 break;
             }
         }
 
-        if (!visible) w = null;
-        if (DEBUG_WALLPAPER && mWallpaperTarget != w) {
-            Log.v(TAG, "New wallpaper target: " + w);
+        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+            // If we are currently waiting for an app transition, and either
+            // the current target or the next target are involved with it,
+            // then hold off on doing anything with the wallpaper.
+            // Note that we are checking here for just whether the target
+            // is part of an app token...  which is potentially overly aggressive
+            // (the app token may not be involved in the transition), but good
+            // enough (we'll just wait until whatever transition is pending
+            // executes).
+            if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) {
+                return false;
+            }
+            if (foundW != null && foundW.mAppToken != null) {
+                return false;
+            }
+            if (mUpcomingWallpaperTarget != null && mUpcomingWallpaperTarget.mAppToken != null) {
+                return false;
+            }
         }
-        mWallpaperTarget = w;
         
+        if (mWallpaperTarget != foundW) {
+            mWallpaperTarget = foundW;
+            if (DEBUG_WALLPAPER) {
+                Log.v(TAG, "New wallpaper target: " + foundW);
+            }
+        }
+        
+        boolean visible = foundW != null;
         if (visible) {
             // The window is visible to the compositor...  but is it visible
             // to the user?  That is what the wallpaper cares about.
-            visible = !w.mObscured;
+            visible = !foundW.mObscured;
             if (DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper visibility: " + visible);
             
             // If the wallpaper target is animating, we may need to copy
-            // its layer adjustment.
-            mWallpaperAnimLayerAdjustment = w.mAppToken != null
-                    ? w.mAppToken.animLayerAdjustment : 0;
+            // its layer adjustment.  Only do this if we are not transfering
+            // between two wallpaper targets.
+            mWallpaperAnimLayerAdjustment =
+                    (mUpcomingWallpaperTarget == null && foundW.mAppToken != null)
+                    ? foundW.mAppToken.animLayerAdjustment : 0;
             
             // Now w is the window we are supposed to be behind...  but we
             // need to be sure to also be behind any of its attached windows,
             // AND any starting window associated with it.
-            while (i > 0) {
-                WindowState wb = (WindowState)localmWindows.get(i-1);
-                if (wb.mAttachedWindow != w &&
+            while (foundI > 0) {
+                WindowState wb = (WindowState)localmWindows.get(foundI-1);
+                if (wb.mAttachedWindow != foundW &&
                         (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
-                                wb.mToken != w.mToken)) {
+                                wb.mToken != foundW.mToken)) {
                     // This window is not related to the previous one in any
                     // interesting way, so stop here.
                     break;
                 }
-                w = wb;
-                i--;
+                foundW = wb;
+                foundI--;
             }
         }
         
         // Okay i is the position immediately above the wallpaper.  Look at
         // what is below it for later.
-        w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
+        foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
         
         final int dw = mDisplay.getWidth();
         final int dh = mDisplay.getHeight();
@@ -1271,9 +1348,10 @@
                 
                 // First, if this window is at the current index, then all
                 // is well.
-                if (wallpaper == w) {
-                    i--;
-                    w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
+                if (wallpaper == foundW) {
+                    foundI--;
+                    foundW = foundI > 0
+                            ? (WindowState)localmWindows.get(foundI-1) : null;
                     continue;
                 }
                 
@@ -1283,16 +1361,16 @@
                 int oldIndex = localmWindows.indexOf(wallpaper);
                 if (oldIndex >= 0) {
                     localmWindows.remove(oldIndex);
-                    if (oldIndex < i) {
-                        i--;
+                    if (oldIndex < foundI) {
+                        foundI--;
                     }
                 }
                 
                 // Now stick it in.
                 if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
-                        + " from " + oldIndex + " to " + i);
+                        + " from " + oldIndex + " to " + foundI);
                 
-                localmWindows.add(i, wallpaper);
+                localmWindows.add(foundI, wallpaper);
                 changed = true;
             }
         }
@@ -2246,6 +2324,16 @@
                                 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
                                 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
                         break;
+                    case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN:
+                        animAttr = enter
+                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenEnterAnimation
+                                : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenExitAnimation;
+                        break;
+                    case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE:
+                        animAttr = enter
+                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseEnterAnimation
+                                : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseExitAnimation;
+                        break;
                 }
                 a = loadAnimation(lp, animAttr);
                 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
@@ -6874,7 +6962,8 @@
             
             // Wallpapers are animated based on the "real" window they
             // are currently targeting.
-            if (mAttrs.type == TYPE_WALLPAPER && mWallpaperTarget != null) {
+            if (mAttrs.type == TYPE_WALLPAPER && mUpcomingWallpaperTarget == null
+                    && mWallpaperTarget != null) {
                 if (mWallpaperTarget.mHasLocalTransformation) {
                     attachedTransformation = mWallpaperTarget.mTransformation;
                 }
@@ -7511,7 +7600,7 @@
                 if (w == mInputMethodTarget) {
                     setInputMethodAnimLayerAdjustment(adj);
                 }
-                if (w == mWallpaperTarget) {
+                if (w == mWallpaperTarget && mUpcomingWallpaperTarget == null) {
                     setWallpaperAnimLayerAdjustmentLocked(adj);
                 }
             }
@@ -8636,6 +8725,60 @@
 
                         mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
 
+                        boolean wallpaperMoved = adjustWallpaperWindowsLocked();
+                        if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+                                "Old wallpaper target=" + mWallpaperTarget
+                                + ", upcoming target=" + mUpcomingWallpaperTarget);
+                        if (mUpcomingWallpaperTarget != mWallpaperTarget &&
+                                mUpcomingWallpaperTarget != null &&
+                                mWallpaperTarget != null) {
+                            // Need to determine if both the closing and
+                            // opening app token sets are wallpaper targets,
+                            // in which case special animations are needed
+                            // (since the wallpaper needs to stay static
+                            // behind them).
+                            int found = 0;
+                            NN = mOpeningApps.size();
+                            for (i=0; i<NN; i++) {
+                                AppWindowToken wtoken = mOpeningApps.get(i);
+                                if (mUpcomingWallpaperTarget.mAppToken == wtoken) {
+                                    found |= 1;
+                                }
+                                if (mWallpaperTarget.mAppToken == wtoken) {
+                                    found |= 1;
+                                }
+                            }
+                            NN = mClosingApps.size();
+                            for (i=0; i<NN; i++) {
+                                AppWindowToken wtoken = mClosingApps.get(i);
+                                if (mUpcomingWallpaperTarget.mAppToken == wtoken) {
+                                    found |= 2;
+                                }
+                                if (mWallpaperTarget.mAppToken == wtoken) {
+                                    found |= 2;
+                                }
+                            }
+                            
+                            if (found == 3) {
+                                if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+                                        "Wallpaper animation!");
+                                switch (transit) {
+                                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+                                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+                                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+                                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN;
+                                        break;
+                                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+                                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
+                                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
+                                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE;
+                                        break;
+                                }
+                                if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+                                        "New transit: " + transit);
+                            }
+                        }
+                        
                         // We need to figure out which animation to use...
                         WindowManager.LayoutParams lp = findAnimations(mAppTokens,
                                 mOpeningApps, mClosingApps);
@@ -8671,7 +8814,6 @@
                         // This has changed the visibility of windows, so perform
                         // a new layout to get them all up-to-date.
                         mLayoutNeeded = true;
-                        adjustWallpaperWindowsLocked();
                         if (!moveInputMethodWindowsIfNeededLocked(true)) {
                             assignLayersLocked();
                         }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index afc8b62..bda2d22 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,9 +20,8 @@
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.text.TextUtils;
 import android.telephony.TelephonyManager;
 import android.telephony.PhoneNumberUtils;
@@ -134,44 +133,39 @@
                 int columnIndex;
 
                 // Look for the name
-                columnIndex = cursor.getColumnIndex(People.NAME);
+                columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
                 if (columnIndex != -1) {
                     info.name = cursor.getString(columnIndex);
                 }
 
                 // Look for the number
-                columnIndex = cursor.getColumnIndex(Phones.NUMBER);
+                columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
                 if (columnIndex != -1) {
                     info.phoneNumber = cursor.getString(columnIndex);
                 }
 
                 // Look for the label/type combo
-                columnIndex = cursor.getColumnIndex(Phones.LABEL);
+                columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
                 if (columnIndex != -1) {
-                    int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE);
+                    int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
                     if (typeColumnIndex != -1) {
                         info.numberType = cursor.getInt(typeColumnIndex);
                         info.numberLabel = cursor.getString(columnIndex);
-                        info.phoneLabel = Contacts.Phones.getDisplayLabel(context,
+                        info.phoneLabel = Phone.getDisplayLabel(context,
                                 info.numberType, info.numberLabel)
                                 .toString();
                     }
                 }
 
                 // Look for the person ID
-                columnIndex = cursor.getColumnIndex(Phones.PERSON_ID);
+                columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
                 if (columnIndex != -1) {
                     info.person_id = cursor.getLong(columnIndex);
-                } else {
-                    columnIndex = cursor.getColumnIndex(People._ID);
-                    if (columnIndex != -1) {
-                        info.person_id = cursor.getLong(columnIndex);
-                    }
                 }
 
                 // look for the custom ringtone, create from the string stored
                 // in the database.
-                columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE);
+                columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
                 if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
                     info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
                 } else {
@@ -180,7 +174,7 @@
 
                 // look for the send to voicemail flag, set it to true only
                 // under certain circumstances.
-                columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL);
+                columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
                 info.shouldSendToVoicemail = (columnIndex != -1) &&
                         ((cursor.getInt(columnIndex)) == 1);
                 info.contactExists = true;
@@ -256,8 +250,7 @@
             }
         }
 
-        Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL,
-                                              Uri.encode(number));
+        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
 
         CallerInfo info = getCallerInfo(context, contactUri);
 
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index f81f42a..ef456f0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,7 +24,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.provider.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -303,7 +303,7 @@
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
         //contruct the URI object and start Query.
-        Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number);
+        Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
 
         CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
         c.allocate(context, contactRef);
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index c2bed88..6657060 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -595,7 +595,7 @@
 
         // this is common for all radio technologies
         if (!mIccCardStatus.getCardState().isCardPresent()) {
-            return IccCard.State.NOT_READY;
+            return IccCard.State.ABSENT;
         }
 
         RadioState currentRadioState = mPhone.mCM.getRadioState();