Merge changes 20497,20498,20499

* changes:
  minor code clean-up
  added EGLUtils::strerror
  better error handling
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ee3ec1a..6b6d3c9 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -268,7 +268,7 @@
 
     private void printRestoreSets(RestoreSet[] sets) {
         for (RestoreSet s : sets) {
-            System.out.println("  " + s.token + " : " + s.name);
+            System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
         }
     }
 
@@ -294,7 +294,7 @@
     private void doRestore() {
         long token;
         try {
-            token = Long.parseLong(nextArg());
+            token = Long.parseLong(nextArg(), 16);
         } catch (NumberFormatException e) {
             showUsage();
             return;
@@ -311,12 +311,14 @@
                 return;
             }
             RestoreSet[] sets = mRestore.getAvailableRestoreSets();
-            for (RestoreSet s : sets) {
-                if (s.token == token) {
-                    System.out.println("Scheduling restore: " + s.name);
-                    mRestore.performRestore(token, observer);
-                    didRestore = true;
-                    break;
+            if (sets != null) {
+                for (RestoreSet s : sets) {
+                    if (s.token == token) {
+                        System.out.println("Scheduling restore: " + s.name);
+                        mRestore.performRestore(token, observer);
+                        didRestore = true;
+                        break;
+                    }
                 }
             }
             if (!didRestore) {
@@ -327,21 +329,24 @@
                     printRestoreSets(sets);
                 }
             }
+
+            // now wait for it to be done
+            synchronized (observer) {
+                while (!observer.done) {
+                    try {
+                        observer.wait();
+                    } catch (InterruptedException ex) {
+                    }
+                }
+            }
+
+            // once the restore has finished, close down the session and we're done
             mRestore.endRestoreSession();
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(BMGR_NOT_RUNNING_ERR);
         }
 
-        // now wait for it to be done
-        synchronized (observer) {
-            while (!observer.done) {
-                try {
-                    observer.wait();
-                } catch (InterruptedException ex) {
-                }
-            }
-        }
         System.out.println("done");
     }
 
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index fd681a2..e6d0503 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -1,5 +1,3 @@
-ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
-
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -62,5 +60,3 @@
 # LOCAL_MODULE:= play
 # 
 # include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 62d9267..9799ac4 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -18,11 +18,13 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.os.SystemClock;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -31,6 +33,7 @@
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
+import android.widget.FrameLayout.LayoutParams;
 
 /**
  * Provides the glue to show AppWidget views. This class offers automatic animation
@@ -58,7 +61,8 @@
     };
 
     Context mContext;
-    
+    Context mRemoteContext;
+
     int mAppWidgetId;
     AppWidgetProviderInfo mInfo;
     View mView;
@@ -104,6 +108,16 @@
         return mInfo;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        // We're being asked to inflate parameters, probably by a LayoutInflater
+        // in a remote Context. To help resolve any remote references, we
+        // inflate through our last mRemoteContext when it exists.
+        final Context context = mRemoteContext != null ? mRemoteContext : mContext;
+        return new FrameLayout.LayoutParams(context, attrs);
+    }
+
     /**
      * Process a set of {@link RemoteViews} coming in as an update from the
      * AppWidget provider. Will animate into these new views as needed.
@@ -143,6 +157,9 @@
             mLayoutId = -1;
             mViewMode = VIEW_MODE_DEFAULT;
         } else {
+            // Prepare a local reference to the remote Context so we're ready to
+            // inflate any requested LayoutParams.
+            mRemoteContext = getRemoteContext(remoteViews);
             int layoutId = remoteViews.getLayoutId();
 
             // If our stale view has been prepared to match active, and the new
@@ -203,6 +220,24 @@
         }
     }
 
+    /**
+     * Build a {@link Context} cloned into another package name, usually for the
+     * purposes of reading remote resources.
+     */
+    private Context getRemoteContext(RemoteViews views) {
+        // Bail if missing package name
+        final String packageName = views.getPackage();
+        if (packageName == null) return mContext;
+
+        try {
+            // Return if cloned successfully, otherwise default
+            return mContext.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Package name " + packageName + " not found");
+            return mContext;
+        }
+    }
+
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         if (CROSSFADE) {
             int alpha;
@@ -246,17 +281,15 @@
      * {@link FrameLayout.LayoutParams} before inserting.
      */
     protected void prepareView(View view) {
-        // Take requested dimensions from parent, but apply default gravity.
-        ViewGroup.LayoutParams requested = view.getLayoutParams();
+        // Take requested dimensions from child, but apply default gravity.
+        FrameLayout.LayoutParams requested = (FrameLayout.LayoutParams)view.getLayoutParams();
         if (requested == null) {
             requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
                     LayoutParams.FILL_PARENT);
         }
-        
-        FrameLayout.LayoutParams params =
-            new FrameLayout.LayoutParams(requested.width, requested.height);
-        params.gravity = Gravity.CENTER;
-        view.setLayoutParams(params);
+
+        requested.gravity = Gravity.CENTER;
+        view.setLayoutParams(requested);
     }
     
     /**
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index ac851cc..c5606ac 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -85,6 +85,7 @@
                             cursor.getCount();
                         }
                     } catch (Exception e) {
+                        Log.d(TAG, e.toString());
                         cursor = null;
                     }
 
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8cf4a77..9b0c70e 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -180,15 +180,33 @@
          * Reference to the row in the data table holding the primary phone number.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_ID = "primary_phone_id";
 
         /**
+         * Reference to the row in the data table holding the default phone number.
+         * If the contact has only one phone number, that number is the default one.
+         * Otherwise it is the one explicitly selected by the user as primary.
+         * <P>Type: INTEGER REFERENCES data(_id)</P>
+         */
+        public static final String DEFAULT_PHONE_ID = "default_phone_id";
+
+        /**
          * Reference to the row in the data table holding the primary email address.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
+        @Deprecated
         public static final String PRIMARY_EMAIL_ID = "primary_email_id";
 
         /**
+         * Reference to the row in the data table holding the default email address.
+         * If the contact has only one email address, that address is the default one.
+         * Otherwise it is the one explicitly selected by the user as primary.
+         * <P>Type: INTEGER REFERENCES data(_id)</P>
+         */
+        public static final String DEFAULT_EMAIL_ID = "default_email_id";
+
+        /**
          * Reference to the row in the data table holding the photo.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
@@ -210,19 +228,40 @@
          * The type of data, for example Home or Work.
          * <P>Type: INTEGER</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_TYPE = CommonDataKinds.Phone.TYPE;
 
         /**
+         * The type of data, for example Home or Work.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DEFAULT_PHONE_TYPE = "default_phone_type";
+
+        /**
          * The user defined label for the primary phone.
          * <P>Type: TEXT</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_LABEL = CommonDataKinds.Phone.LABEL;
 
         /**
+         * The user defined label for the default phone.
+         * <P>Type: TEXT</P>
+         */
+        public static final String DEFAULT_PHONE_LABEL = "default_phone_label";
+
+        /**
          * The primary phone number.
          * <P>Type: TEXT</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_NUMBER = CommonDataKinds.Phone.NUMBER;
+
+        /**
+         * The default phone number.
+         * <P>Type: TEXT</P>
+         */
+        public static final String DEFAULT_PHONE_NUMBER = "default_phone_number";
     }
 
     /**
@@ -393,6 +432,7 @@
          *
          * @hide
          */
+        @Deprecated
         public static final Uri CONTENT_FILTER_EMAIL_URI =
                 Uri.withAppendedPath(CONTENT_URI, "filter_email");
 
@@ -603,13 +643,13 @@
          * Reference to the {@link RawContacts#_ID} this presence references.
          * <P>Type: INTEGER</P>
          */
-        public static final String RAW_CONTACT_ID = "raw_contact_id";
+        public static final String RAW_CONTACT_ID = "presence_raw_contact_id";
 
         /**
          * Reference to the {@link Data#_ID} entry that owns this presence.
          * <P>Type: INTEGER</P>
          */
-        public static final String DATA_ID = "data_id";
+        public static final String DATA_ID = "presence_data_id";
 
         /**
          * The IM service the presence is coming from. Formatted using either
@@ -911,6 +951,22 @@
             /** MIME type used when storing this in data table. */
             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email";
 
+            /**
+             * The content:// style URI for all data records of the
+             * {@link Email#CONTENT_ITEM_TYPE} MIME type, combined with the
+             * associated raw contact and aggregate contact data.
+             */
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+                    "emails");
+
+            /**
+             * The content:// style URL for filtering data rows by email address. The
+             * filter argument should be passed as an additional path segment after
+             * this URI.
+             */
+            public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI,
+                    "filter");
+
             public static final int TYPE_HOME = 1;
             public static final int TYPE_WORK = 2;
             public static final int TYPE_OTHER = 3;
@@ -1191,7 +1247,7 @@
 
             public static final int TYPE_ANNIVERSARY = 1;
             public static final int TYPE_OTHER = 2;
-            
+
             /**
              * The event start date as the user entered it.
              * <P>Type: TEXT</P>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1db17c8..3e818eb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2992,6 +2992,12 @@
                 "vending_require_sim_for_purchase";
 
         /**
+         * Indicates the Vending Machine backup state. It is set if the
+         * Vending application has been backed up at least once.
+         */
+        public static final String VENDING_BACKUP_STATE = "vending_backup_state";
+
+        /**
          * The current version id of the Vending Machine terms of service.
          */
         public static final String VENDING_TOS_VERSION = "vending_tos_version";
@@ -3298,39 +3304,6 @@
                 "short_keylight_delay_ms";
 
         /**
-         * URL that points to the voice search servers. To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_URL = "voice_search_url";
-
-        /**
-         * Speech encoding used with voice search on 3G networks. To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_ENCODING_THREE_G = "voice_search_encoding_three_g";
-
-        /**
-         * Speech encoding used with voice search on WIFI networks. To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_ENCODING_WIFI = "voice_search_encoding_wifi";
-
-        /**
-         * Whether to use automatic gain control in voice search (0 = disable, 1 = enable).
-         * To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_ENABLE_AGC = "voice_search_enable_agc";
-
-        /**
-         * Whether to use noise suppression in voice search (0 = disable, 1 = enable).
-         * To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_ENABLE_NS = "voice_search_enable_ns";
-
-        /**
-         * Whether to use the IIR filter in voice search (0 = disable, 1 = enable).
-         * To be factored out of this class.
-         */
-        public static final String VOICE_SEARCH_ENABLE_IIR = "voice_search_enable_iir";
-
-        /**
          * List of test suites (local disk filename) for the automatic instrumentation test runner.
          * The file format is similar to automated_suites.xml, see AutoTesterService.
          * If this setting is missing or empty, the automatic test runner will not start.
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 06581c1..2ac77ac 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -560,13 +560,6 @@
             return loadListener;
         }
 
-        // during synchronous load, the WebViewCore thread is blocked, so we
-        // need to endCacheTransaction first so that http thread won't be 
-        // blocked in setupFile() when createCacheFile.
-        if (synchronous) {
-            CacheManager.endCacheTransaction();
-        }
-
         FrameLoader loader = new FrameLoader(loadListener, mSettings, method);
         loader.setHeaders(headers);
         loader.setPostData(postData);
@@ -581,10 +574,6 @@
         }
         checker.responseAlert("startLoadingResource succeed");
 
-        if (synchronous) {
-            CacheManager.startCacheTransaction();
-        }
-
         return !synchronous ? loadListener : null;
     }
 
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 9a02fbe..7b32a26 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -534,12 +534,7 @@
                 // cache file. If it is not, resolve the collision.
                 while (file.exists()) {
                     if (checkOldPath) {
-                        // as this is called from http thread through 
-                        // createCacheFile, we need endCacheTransaction before 
-                        // database access.
-                        WebViewCore.endCacheTransaction();
                         CacheResult oldResult = mDataBase.getCache(url);
-                        WebViewCore.startCacheTransaction();
                         if (oldResult != null && oldResult.contentLength > 0) {
                             if (path.equals(oldResult.localPath)) {
                                 path = oldResult.localPath;
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 45bd0cf..e4aaf38 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -233,6 +233,8 @@
             if (c.moveToFirst()) {
                 long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
                 bindFromContactId(contactId);
+            } else {
+                bindStatic(emailAddress, "");
             }
         } finally {
             if (c != null) {
@@ -257,6 +259,8 @@
             if (c.moveToFirst()) {
                 long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
                 bindFromContactId(contactId);
+            } else {
+                bindStatic(number, "");
             }
         } finally {
             if (c != null) {
@@ -265,6 +269,13 @@
         }
     }
 
+    public void bindStatic(String main, String secondary) {
+        mDisplayNameView.setText(main);
+        mStatusView.setText(secondary);
+        mStarredView.setVisibility(View.GONE);
+        mPhotoView.setImageBitmap(loadPlaceholderPhoto(null));
+    }
+
     protected void redrawHeader() {
         if (mContactDataUri != null) {
             mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, mContactDataUri, HEADER_PROJECTION,
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 4a13e80..527bf07 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -711,6 +711,7 @@
                                 method_onDeviceFound,
                                 env->NewStringUTF(c_address),
                                 str_array);
+            env->DeleteLocalRef(str_array);
         } else
             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
         return DBUS_HANDLER_RESULT_HANDLED;
@@ -774,6 +775,7 @@
             env->CallVoidMethod(nat->me,
                               method_onPropertyChanged,
                               str_array);
+            env->DeleteLocalRef(str_array);
         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
         return DBUS_HANDLER_RESULT_HANDLED;
     } else if (dbus_message_is_signal(msg,
@@ -786,6 +788,7 @@
                             method_onDevicePropertyChanged,
                             env->NewStringUTF(remote_device_path),
                             str_array);
+            env->DeleteLocalRef(str_array);
         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
         return DBUS_HANDLER_RESULT_HANDLED;
 
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index babf1a0..8a9c1a7 100644
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -91,17 +91,17 @@
     <string name="today">Heute</string>
     <string name="tomorrow">Morgen</string>
 
-    <string name="hour_minute_24">%-k:%M h</string>
+    <string name="hour_minute_24">%-k:%M</string>
     <string name="hour_minute_ampm">%-l:%M %p</string>
     <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
     <string name="twelve_hour_time_format">h:mm a</string>
-    <string name="twenty_four_hour_time_format">H:mm \'h\'</string>
+    <string name="twenty_four_hour_time_format">H:mm</string>
     <string name="numeric_date">%d.%m.%Y</string>
     <string name="numeric_date_format">dd.MM.yyyy</string>
     <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
-    <string name="time_of_day">%H:%M:%S h</string>
-    <string name="date_and_time">%d.%m.%Y, %H:%M:%S h</string>
+    <string name="time_of_day">%H:%M:%S</string>
+    <string name="date_and_time">%d.%m.%Y, %H:%M:%S</string>
     <string name="date_time">%1$s, %2$s</string>
     <string name="time_date">%3$s, %1$s</string>
     <string name="abbrev_month_day_year">%d.%m.%Y</string>
@@ -111,37 +111,37 @@
     <string name="abbrev_month_day">%-e. %b</string>
     <string name="abbrev_month">%-b</string>
     <string name="abbrev_month_year">%b %Y</string>
-    <string name="time1_time2">%1$s bis %2$s</string>
-    <string name="date1_date2">%2$s bis %5$s</string>
-    <string name="numeric_md1_md2">%3$s.%2$s. bis %8$s.%7$s.</string>
-    <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. bis %6$s, %8$s.%7$s.</string>
-    <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s bis %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s bis %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s.%2$s.%4$s, %5$s bis %6$s, %8$s.%7$s.%9$s, %10$s</string>
-    <string name="numeric_md1_time1_md2_time2">%3$s.%2$s., %5$s bis %8$s.%7$s., %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s.%2$s., %5$s bis %6$s, %8$s.%7$s., %10$s</string>
-    <string name="numeric_mdy1_time1_mdy2_time2">%3$s.%2$s.%4$s, %5$s bis %8$s.%7$s.%9$s, %10$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s bis %4$s, %5$s, %6$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s, %2$s bis %4$s, %5$s</string>
-    <string name="date1_time1_date2_time2">%2$s, %3$s bis %5$s, %6$s</string>
+    <string name="time1_time2">%1$s - %2$s</string>
+    <string name="date1_date2">%2$s - %5$s</string>
+    <string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
+    <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
+    <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s.%2$s.%4$s, %5$s - %6$s, %8$s.%7$s.%9$s, %10$s</string>
+    <string name="numeric_md1_time1_md2_time2">%3$s.%2$s., %5$s - %8$s.%7$s., %10$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s.%2$s., %5$s - %6$s, %8$s.%7$s., %10$s</string>
+    <string name="numeric_mdy1_time1_mdy2_time2">%3$s.%2$s.%4$s, %5$s - %8$s.%7$s.%9$s, %10$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="date1_time1_date2_time2">%2$s, %3$s - %5$s, %6$s</string>
     <string name="time_wday_date">%2$s, %3$s, %1$s</string>
     <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%2$s, %1$s</string>
-    <string name="same_year_md1_md2">%3$s. %2$s bis %8$s. %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s bis %6$s, %8$s. %7$s</string>
-    <string name="same_year_md1_time1_md2_time2">%3$s. %2$s, %5$s bis %8$s. %7$s, %10$s</string>
-    <string name="same_month_md1_time1_md2_time2">%3$s. %2$s, %5$s bis %8$s. %7$s, %10$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s. %2$s, %5$s bis %6$s, %8$s. %7$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s. %2$s, %5$s bis %6$s, %8$s. %7$s, %10$s</string>
-    <string name="same_year_mdy1_time1_mdy2_time2">%3$s. %2$s %4$s, %5$s bis %8$s. %7$s %9$s, %10$s</string>
-    <string name="same_month_mdy1_time1_mdy2_time2">%3$s. %2$s %4$s, %5$s bis %8$s. %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s. %2$s %4$s, %5$s bis %6$s, %8$s. %7$s %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s. %2$s %4$s, %5$s bis %6$s, %8$s. %7$s %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s bis %6$s, %8$s. %7$s %9$s</string>
-    <string name="same_month_md1_md2">%3$s. bis %8$s. %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s bis %6$s, %8$s. %7$s</string>
-    <string name="same_year_mdy1_mdy2">%3$s. %2$s bis %8$s. %7$s %9$s</string>
-    <string name="same_month_mdy1_mdy2">%3$s. bis %8$s. %2$s %9$s</string>
-    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s bis %6$s, %8$s. %7$s %9$s</string>
+    <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+    <string name="same_year_md1_time1_md2_time2">%3$s. %2$s, %5$s - %8$s. %7$s, %10$s</string>
+    <string name="same_month_md1_time1_md2_time2">%3$s. %2$s, %5$s - %8$s. %7$s, %10$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s. %2$s, %5$s - %6$s, %8$s. %7$s, %10$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s. %2$s, %5$s - %6$s, %8$s. %7$s, %10$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">%3$s. %2$s %4$s, %5$s - %8$s. %7$s %9$s, %10$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">%3$s. %2$s %4$s, %5$s - %8$s. %7$s %9$s, %10$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s. %2$s %4$s, %5$s - %6$s, %8$s. %7$s %9$s, %10$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s. %2$s %4$s, %5$s - %6$s, %8$s. %7$s %9$s, %10$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s</string>
+    <string name="same_month_md1_md2">%3$s. - %8$s. %2$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+    <string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
+    <string name="same_month_mdy1_mdy2">%3$s. - %8$s. %2$s %9$s</string>
+    <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
 </resources>
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 1243502..1f726fe 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -24,7 +24,7 @@
 namespace android {
 
 typedef void (*audio_error_callback)(status_t err);
-typedef void * audio_io_handle_t;
+typedef int audio_io_handle_t;
 
 class IAudioPolicyService;
 class String8;
@@ -184,8 +184,8 @@
     static status_t getMasterMute(bool* mute);
 
     // set/get stream volume on specified output
-    static status_t setStreamVolume(int stream, float value, void *output);
-    static status_t getStreamVolume(int stream, float* volume, void *output);
+    static status_t setStreamVolume(int stream, float value, int output);
+    static status_t getStreamVolume(int stream, float* volume, int output);
 
     // mute/unmute stream
     static status_t setStreamMute(int stream, bool mute);
@@ -383,7 +383,7 @@
 
         // indicate a change in the configuration of an output or input: keeps the cached
         // values for output/input parameters upto date in client process
-        virtual void ioConfigChanged(int event, void *param1, void *param2);
+        virtual void ioConfigChanged(int event, int ioHandle, void *param2);
     };
 
     class AudioPolicyServiceClient: public IBinder::DeathRecipient
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 26e6972..8018568 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -50,12 +50,12 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                void *output,
+                                int output,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                void *input,
+                                int input,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -66,11 +66,11 @@
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
      */
-    virtual     uint32_t    sampleRate(void *output) const = 0;
-    virtual     int         channelCount(void *output) const = 0;
-    virtual     int         format(void *output) const = 0;
-    virtual     size_t      frameCount(void *output) const = 0;
-    virtual     uint32_t    latency(void *output) const = 0;
+    virtual     uint32_t    sampleRate(int output) const = 0;
+    virtual     int         channelCount(int output) const = 0;
+    virtual     int         format(int output) const = 0;
+    virtual     size_t      frameCount(int output) const = 0;
+    virtual     uint32_t    latency(int output) const = 0;
 
     /* set/get the audio hardware state. This will probably be used by
      * the preference panel, mostly.
@@ -84,10 +84,10 @@
     /* set/get stream type state. This will probably be used by
      * the preference panel, mostly.
      */
-    virtual     status_t    setStreamVolume(int stream, float value, void *output) = 0;
+    virtual     status_t    setStreamVolume(int stream, float value, int output) = 0;
     virtual     status_t    setStreamMute(int stream, bool muted) = 0;
 
-    virtual     float       streamVolume(int stream, void *output) const = 0;
+    virtual     float       streamVolume(int stream, int output) const = 0;
     virtual     bool        streamMute(int stream) const = 0;
 
     // set audio mode
@@ -100,8 +100,8 @@
     // is a music stream active?
     virtual     bool        isMusicActive() const = 0;
 
-    virtual     status_t    setParameters(void *ioHandle, const String8& keyValuePairs) = 0;
-    virtual     String8     getParameters(void *ioHandle, const String8& keys) = 0;
+    virtual     status_t    setParameters(int ioHandle, const String8& keyValuePairs) = 0;
+    virtual     String8     getParameters(int ioHandle, const String8& keys) = 0;
     
     // register a current process for audio output change notifications
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
@@ -109,25 +109,25 @@
     // retrieve the audio recording buffer size
     virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
 
-    virtual void *openOutput(uint32_t *pDevices,
+    virtual int openOutput(uint32_t *pDevices,
                                     uint32_t *pSamplingRate,
                                     uint32_t *pFormat,
                                     uint32_t *pChannels,
                                     uint32_t *pLatencyMs,
                                     uint32_t flags) = 0;
-    virtual void *openDuplicateOutput(void *output1, void *output2) = 0;
-    virtual status_t closeOutput(void *output) = 0;
-    virtual status_t suspendOutput(void *output) = 0;
-    virtual status_t restoreOutput(void *output) = 0;
+    virtual int openDuplicateOutput(int output1, int output2) = 0;
+    virtual status_t closeOutput(int output) = 0;
+    virtual status_t suspendOutput(int output) = 0;
+    virtual status_t restoreOutput(int output) = 0;
 
-    virtual void *openInput(uint32_t *pDevices,
+    virtual int openInput(uint32_t *pDevices,
                                     uint32_t *pSamplingRate,
                                     uint32_t *pFormat,
                                     uint32_t *pChannels,
                                     uint32_t acoustics) = 0;
-    virtual status_t closeInput(void *input) = 0;
+    virtual status_t closeInput(int input) = 0;
 
-    virtual status_t setStreamOutput(uint32_t stream, void *output) = 0;
+    virtual status_t setStreamOutput(uint32_t stream, int output) = 0;
 };
 
 
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index 78142ce3..aa0cdcf 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -32,7 +32,7 @@
     DECLARE_META_INTERFACE(AudioFlingerClient);
 
     // Notifies a change of audio input/output configuration.
-    virtual void ioConfigChanged(int event, void *param1, void *param2) = 0;
+    virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
 
 };
 
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 6f9e934..20db8a5 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -89,7 +89,7 @@
 
 void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
     if (mOutput == 0 || mOutput != out) {
-        LOGW("Attempt to close invalid output stream");
+        mHardwareInterface->closeOutputStream(out);
     }
     else {
         delete mOutput;
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index 87bb014..858e5aa 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -71,9 +71,21 @@
             }
         }
     } else {
-        if (format != 0 && *format != 0) lFormat = *format;
-        if (channels != 0 && *channels != 0) lChannels = *channels;
-        if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+        if (format != 0 && *format != 0) {
+            lFormat = *format;
+        } else {
+            lFormat = AudioSystem::PCM_16_BIT;
+        }
+        if (channels != 0 && *channels != 0) {
+            lChannels = *channels;
+        } else {
+            lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+        }
+        if (sampleRate != 0 && *sampleRate != 0) {
+            lRate = *sampleRate;
+        } else {
+            lRate = 44100;
+        }
         if (status) *status = NO_ERROR;
     }
     LOGV("openOutputStream(), outFinal %p", outFinal);
@@ -93,9 +105,13 @@
         LOGW("Attempt to close invalid output stream");
         return;
     }
+
+    LOGV("closeOutputStream() output %p", out);
+
     dumpOut->standby();
     if (dumpOut->finalStream() != NULL) {
         mFinalInterface->closeOutputStream(dumpOut->finalStream());
+        mFirstHwOutput = true;
     }
 
     mOutputs.remove(dumpOut);
@@ -159,7 +175,7 @@
 
     if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
         mFileName = value;
-        return NO_ERROR;
+        param.remove(String8("test_cmd_file_name"));
     }
     if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
         Mutex::Autolock _l(mLock);
@@ -176,21 +192,35 @@
 String8 AudioDumpInterface::getParameters(const String8& keys)
 {
     AudioParameter param = AudioParameter(keys);
+    AudioParameter response;
     String8 value;
 
 //    LOGV("getParameters %s", keys.string());
-
-    if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
-        return mFileName;
-    }
     if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
         Mutex::Autolock _l(mLock);
+        if (mPolicyCommands.length() != 0) {
+            response = AudioParameter(mPolicyCommands);
+            response.addInt(String8("test_cmd_policy"), 1);
+        } else {
+            response.addInt(String8("test_cmd_policy"), 0);
+        }
+        param.remove(String8("test_cmd_policy"));
 //        LOGV("test_cmd_policy command %s read", mPolicyCommands.string());
-        return mPolicyCommands;
     }
 
-    if (mFinalInterface != 0 ) return mFinalInterface->getParameters(keys);
-    return String8("");
+    if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+        response.add(String8("test_cmd_file_name"), mFileName);
+        param.remove(String8("test_cmd_file_name"));
+    }
+
+    String8 keyValuePairs = response.toString();
+
+    if (param.size() && mFinalInterface != 0 ) {
+        keyValuePairs += ";";
+        keyValuePairs += mFinalInterface->getParameters(param.toString());
+    }
+
+    return keyValuePairs;
 }
 
 
@@ -213,6 +243,7 @@
 
 AudioStreamOutDump::~AudioStreamOutDump()
 {
+    LOGV("AudioStreamOutDump destructor");
     Close();
 }
 
@@ -283,15 +314,55 @@
 }
 status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
 {
-    LOGV("AudioStreamOutDump::setParameters()");
-    if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
-    return NO_ERROR;
+    LOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+    if (mFinalStream != 0 ) {
+        return mFinalStream->setParameters(keyValuePairs);
+    }
+
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 value;
+    int valueInt;
+    status_t status = NO_ERROR;
+
+    if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+        mId = valueInt;
+    }
+
+    if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+        if (mOutFile == 0) {
+            mFormat = valueInt;
+        } else {
+            status = INVALID_OPERATION;
+        }
+    }
+    if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+        if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+            mChannels = valueInt;
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+        if (valueInt > 0 && valueInt <= 48000) {
+            if (mOutFile == 0) {
+                mSampleRate = valueInt;
+            } else {
+                status = INVALID_OPERATION;
+            }
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    return status;
 }
+
 String8 AudioStreamOutDump::getParameters(const String8& keys)
 {
-    String8 result = String8("");
-    if (mFinalStream != 0 ) result = mFinalStream->getParameters(keys);
-    return result;
+    if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
 }
 
 status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
@@ -426,9 +497,10 @@
 
 String8 AudioStreamInDump::getParameters(const String8& keys)
 {
-    String8 result = String8("");
-    if (mFinalStream != 0 ) result = mFinalStream->getParameters(keys);
-    return result;
+    if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
 }
 
 status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 4de4a16..1136ce1 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -57,6 +57,7 @@
     AudioStreamOut*     finalStream() { return mFinalStream; }
     uint32_t            device() { return mDevice; }
 
+    int                 getId()  { return mId; }
 private:
     AudioDumpInterface *mInterface;
     int                  mId;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 232ffb0..d019097 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -115,7 +115,7 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false)
+        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
 
@@ -231,12 +231,12 @@
 
         // dump playback threads
         for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-            mPlaybackThreads[i]->dump(fd, args);
+            mPlaybackThreads.valueAt(i)->dump(fd, args);
         }
 
         // dump record threads
         for (size_t i = 0; i < mRecordThreads.size(); i++) {
-            mRecordThreads[i]->dump(fd, args);
+            mRecordThreads.valueAt(i)->dump(fd, args);
         }
 
         if (mAudioHardware) {
@@ -260,7 +260,7 @@
         int frameCount,
         uint32_t flags,
         const sp<IMemory>& sharedBuffer,
-        void *output,
+        int output,
         status_t *status)
 {
     sp<PlaybackThread::Track> track;
@@ -308,56 +308,56 @@
     return trackHandle;
 }
 
-uint32_t AudioFlinger::sampleRate(void *output) const
+uint32_t AudioFlinger::sampleRate(int output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread == NULL) {
-        LOGW("sampleRate() unknown thread %p", output);
+        LOGW("sampleRate() unknown thread %d", output);
         return 0;
     }
     return thread->sampleRate();
 }
 
-int AudioFlinger::channelCount(void *output) const
+int AudioFlinger::channelCount(int output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread == NULL) {
-        LOGW("channelCount() unknown thread %p", output);
+        LOGW("channelCount() unknown thread %d", output);
         return 0;
     }
     return thread->channelCount();
 }
 
-int AudioFlinger::format(void *output) const
+int AudioFlinger::format(int output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread == NULL) {
-        LOGW("format() unknown thread %p", output);
+        LOGW("format() unknown thread %d", output);
         return 0;
     }
     return thread->format();
 }
 
-size_t AudioFlinger::frameCount(void *output) const
+size_t AudioFlinger::frameCount(int output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread == NULL) {
-        LOGW("frameCount() unknown thread %p", output);
+        LOGW("frameCount() unknown thread %d", output);
         return 0;
     }
     return thread->frameCount();
 }
 
-uint32_t AudioFlinger::latency(void *output) const
+uint32_t AudioFlinger::latency(int output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread == NULL) {
-        LOGW("latency() unknown thread %p", output);
+        LOGW("latency() unknown thread %d", output);
         return 0;
     }
     return thread->latency();
@@ -380,7 +380,7 @@
 
     mMasterVolume = value;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
-       mPlaybackThreads[i]->setMasterVolume(value);
+       mPlaybackThreads.valueAt(i)->setMasterVolume(value);
 
     return NO_ERROR;
 }
@@ -435,7 +435,7 @@
 
     mMasterMute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
-       mPlaybackThreads[i]->setMasterMute(muted);
+       mPlaybackThreads.valueAt(i)->setMasterMute(muted);
 
     return NO_ERROR;
 }
@@ -450,7 +450,7 @@
     return mMasterMute;
 }
 
-status_t AudioFlinger::setStreamVolume(int stream, float value, void *output)
+status_t AudioFlinger::setStreamVolume(int stream, float value, int output)
 {
     // check calling permissions
     if (!settingsAllowed()) {
@@ -495,7 +495,7 @@
 
     if (thread == NULL) {
         for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
-           mPlaybackThreads[i]->setStreamVolume(stream, value);
+           mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
 
     } else {
         thread->setStreamVolume(stream, value);
@@ -518,12 +518,12 @@
 
     mStreamTypes[stream].mute = muted;
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
-       mPlaybackThreads[i]->setStreamMute(stream, muted);
+       mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
 
     return NO_ERROR;
 }
 
-float AudioFlinger::streamVolume(int stream, void *output) const
+float AudioFlinger::streamVolume(int stream, int output) const
 {
     if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return 0.0f;
@@ -562,18 +562,18 @@
 {
     Mutex::Autolock _l(mLock);
     for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (mPlaybackThreads[i]->isMusicActive()) {
+        if (mPlaybackThreads.valueAt(i)->isMusicActive()) {
             return true;
         }
     }
     return false;
 }
 
-status_t AudioFlinger::setParameters(void *ioHandle, const String8& keyValuePairs)
+status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
 {
     status_t result;
 
-    LOGV("setParameters(): io %p, keyvalue %s, tid %d, calling tid %d",
+    LOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
             ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
     // check calling permissions
     if (!settingsAllowed()) {
@@ -604,9 +604,9 @@
     return BAD_VALUE;
 }
 
-String8 AudioFlinger::getParameters(void *ioHandle, const String8& keys)
+String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
 {
-//    LOGV("getParameters() io %p, keys %s, tid %d, calling tid %d",
+//    LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
 //            ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
 
     if (ioHandle == 0) {
@@ -644,11 +644,11 @@
     // the config change is always sent from playback or record threads to avoid deadlock
     // with AudioSystem::gLock
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        mPlaybackThreads[i]->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+        mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
     }
 
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads[i]->sendConfigEvent(AudioSystem::INPUT_OPENED);
+        mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
     }
 }
 
@@ -668,14 +668,33 @@
     }
 }
 
-void AudioFlinger::audioConfigChanged(int event, void *param1, void *param2) {
+void AudioFlinger::audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2) {
     Mutex::Autolock _l(mLock);
-    size_t size = mNotificationClients.size();
-    for (size_t i = 0; i < size; i++) {
-        sp<IBinder> binder = mNotificationClients.itemAt(i);
-        LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
-        sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
-        client->ioConfigChanged(event, param1, param2);
+    int ioHandle = 0;
+
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        if (mPlaybackThreads.valueAt(i) == thread) {
+            ioHandle = mPlaybackThreads.keyAt(i);
+            break;
+        }
+    }
+    if (ioHandle == 0) {
+        for (size_t i = 0; i < mRecordThreads.size(); i++) {
+            if (mRecordThreads.valueAt(i) == thread) {
+                ioHandle = mRecordThreads.keyAt(i);
+                break;
+            }
+        }
+    }
+
+    if (ioHandle != 0) {
+        size_t size = mNotificationClients.size();
+        for (size_t i = 0; i < size; i++) {
+            sp<IBinder> binder = mNotificationClients.itemAt(i);
+            LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+            sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+            client->ioConfigChanged(event, ioHandle, param2);
+        }
     }
 }
 
@@ -691,12 +710,14 @@
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger)
     :   Thread(false),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
-        mFormat(0), mFrameSize(1), mNewParameters(String8("")), mStandby(false)
+        mFormat(0), mFrameSize(1), mStandby(false)
 {
 }
 
 AudioFlinger::ThreadBase::~ThreadBase()
 {
+    mParamCond.broadcast();
+    mNewParameters.clear();
 }
 
 void AudioFlinger::ThreadBase::exit()
@@ -736,20 +757,28 @@
 
 status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
 {
-    status_t result;
+    status_t status;
 
+    LOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
     Mutex::Autolock _l(mLock);
-    mNewParameters = keyValuePairs;
 
+    mNewParameters.add(keyValuePairs);
     mWaitWorkCV.signal();
     mParamCond.wait(mLock);
-
-    return mParamStatus;
+    status = mParamStatus;
+    mWaitWorkCV.signal();
+    return status;
 }
 
 void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
 {
     Mutex::Autolock _l(mLock);
+    sendConfigEvent_l(event, param);
+}
+
+// sendConfigEvent_l() must be called with ThreadBase::mLock held
+void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
+{
     ConfigEvent *configEvent = new ConfigEvent();
     configEvent->mEvent = event;
     configEvent->mParam = param;
@@ -781,7 +810,7 @@
 
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
     :   ThreadBase(audioFlinger),
-        mMixBuffer(0), mSuspended(false), mBytesWritten(0), mOutput(output),
+        mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
 {
     readOutputParameters();
@@ -800,9 +829,6 @@
 AudioFlinger::PlaybackThread::~PlaybackThread()
 {
     delete [] mMixBuffer;
-    if (mType != DUPLICATING) {
-        mAudioFlinger->mAudioHardware->closeOutputStream(mOutput);
-    }
 }
 
 status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
@@ -1435,10 +1461,14 @@
 {
     bool reconfig = false;
 
-    if (mNewParameters != "") {
+    while (!mNewParameters.isEmpty()) {
         status_t status = NO_ERROR;
-        AudioParameter param = AudioParameter(mNewParameters);
+        String8 keyValuePair = mNewParameters[0];
+        AudioParameter param = AudioParameter(keyValuePair);
         int value;
+
+        mNewParameters.removeAt(0);
+
         if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
             reconfig = true;
         }
@@ -1467,12 +1497,12 @@
             }
         }
         if (status == NO_ERROR) {
-            status = mOutput->setParameters(mNewParameters);
+            status = mOutput->setParameters(keyValuePair);
             if (!mStandby && status == INVALID_OPERATION) {
                mOutput->standby();
                mStandby = true;
                mBytesWritten = 0;
-               status = mOutput->setParameters(mNewParameters);
+               status = mOutput->setParameters(keyValuePair);
             }
             if (status == NO_ERROR && reconfig) {
                 delete mAudioMixer;
@@ -1483,12 +1513,12 @@
                     if (name < 0) break;
                     mTracks[i]->mName = name;
                 }
-                sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED);
+                sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
         }
         mParamStatus = status;
-        mNewParameters = "";
         mParamCond.signal();
+        mWaitWorkCV.wait(mLock);
     }
     return reconfig;
 }
@@ -1740,10 +1770,14 @@
 {
     bool reconfig = false;
 
-    if (mNewParameters != "") {
+    while (!mNewParameters.isEmpty()) {
         status_t status = NO_ERROR;
-        AudioParameter param = AudioParameter(mNewParameters);
+        String8 keyValuePair = mNewParameters[0];
+        AudioParameter param = AudioParameter(keyValuePair);
         int value;
+
+        mNewParameters.removeAt(0);
+
         if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
             // do not accept frame count changes if tracks are open as the track buffer
             // size depends on frame count and correct behavior would not be garantied
@@ -1755,21 +1789,21 @@
             }
         }
         if (status == NO_ERROR) {
-            status = mOutput->setParameters(mNewParameters);
+            status = mOutput->setParameters(keyValuePair);
             if (!mStandby && status == INVALID_OPERATION) {
                mOutput->standby();
                mStandby = true;
                mBytesWritten = 0;
-               status = mOutput->setParameters(mNewParameters);
+               status = mOutput->setParameters(keyValuePair);
             }
             if (status == NO_ERROR && reconfig) {
                 readOutputParameters();
-                sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED);
+                sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
         }
         mParamStatus = status;
-        mNewParameters = "";
         mParamCond.signal();
+        mWaitWorkCV.wait(mLock);
     }
     return reconfig;
 }
@@ -2711,7 +2745,7 @@
 
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
-        void *input,
+        int input,
         uint32_t sampleRate,
         int format,
         int channelCount,
@@ -2818,7 +2852,6 @@
 
 AudioFlinger::RecordThread::~RecordThread()
 {
-    mAudioFlinger->mAudioHardware->closeInputStream(mInput);
     delete[] mRsmpInBuffer;
     if (mResampler != 0) {
         delete mResampler;
@@ -3081,13 +3114,17 @@
 {
     bool reconfig = false;
 
-    if (mNewParameters != "") {
+    while (!mNewParameters.isEmpty()) {
         status_t status = NO_ERROR;
-        AudioParameter param = AudioParameter(mNewParameters);
+        String8 keyValuePair = mNewParameters[0];
+        AudioParameter param = AudioParameter(keyValuePair);
         int value;
         int reqFormat = mFormat;
         int reqSamplingRate = mReqSampleRate;
         int reqChannelCount = mReqChannelCount;
+
+        mNewParameters.removeAt(0);
+
         if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
             reqSamplingRate = value;
             reconfig = true;
@@ -3111,10 +3148,10 @@
             }
         }
         if (status == NO_ERROR) {
-            status = mInput->setParameters(mNewParameters);
+            status = mInput->setParameters(keyValuePair);
             if (status == INVALID_OPERATION) {
                mInput->standby();
-               status = mInput->setParameters(mNewParameters);
+               status = mInput->setParameters(keyValuePair);
             }
             if (reconfig) {
                 if (status == BAD_VALUE &&
@@ -3125,13 +3162,13 @@
                 }
                 if (status == NO_ERROR) {
                     readInputParameters();
-                    sendConfigEvent(AudioSystem::INPUT_CONFIG_CHANGED);
+                    sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                 }
             }
         }
-        mNewParameters = "";
         mParamStatus = status;
         mParamCond.signal();
+        mWaitWorkCV.wait(mLock);
     }
     return reconfig;
 }
@@ -3204,7 +3241,7 @@
 
 // ----------------------------------------------------------------------------
 
-void *AudioFlinger::openOutput(uint32_t *pDevices,
+int AudioFlinger::openOutput(uint32_t *pDevices,
                                 uint32_t *pSamplingRate,
                                 uint32_t *pFormat,
                                 uint32_t *pChannels,
@@ -3227,7 +3264,7 @@
             flags);
 
     if (pDevices == NULL || *pDevices == 0) {
-        return NULL;
+        return 0;
     }
     Mutex::Autolock _l(mLock);
 
@@ -3249,12 +3286,12 @@
             (format != AudioSystem::PCM_16_BIT) ||
             (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
             thread = new DirectOutputThread(this, output);
-            LOGV("openOutput() created direct output %p", thread);
+            LOGV("openOutput() created direct output: ID %d thread %p", (mNextThreadId + 1), thread);
         } else {
             thread = new MixerThread(this, output);
-            LOGV("openOutput() created mixer output %p", thread);
+            LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
         }
-        mPlaybackThreads.add(thread);
+        mPlaybackThreads.add(++mNextThreadId, thread);
 
         if (pSamplingRate) *pSamplingRate = samplingRate;
         if (pFormat) *pFormat = format;
@@ -3262,28 +3299,32 @@
         if (pLatencyMs) *pLatencyMs = thread->latency();
     }
 
-    return thread;
+    return mNextThreadId;
 }
 
-void *AudioFlinger::openDuplicateOutput(void *output1, void *output2)
+int AudioFlinger::openDuplicateOutput(int output1, int output2)
 {
     Mutex::Autolock _l(mLock);
+    MixerThread *thread1 = checkMixerThread_l(output1);
+    MixerThread *thread2 = checkMixerThread_l(output2);
 
-    if (checkMixerThread_l(output1) == NULL ||
-        checkMixerThread_l(output2) == NULL) {
-        LOGW("openDuplicateOutput() wrong output mixer type %p or %p", output1, output2);
-        return NULL;
+    if (thread1 == NULL || thread2 == NULL) {
+        LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
+        return 0;
     }
 
-    DuplicatingThread *thread = new DuplicatingThread(this, (MixerThread *)output1);
-    thread->addOutputTrack( (MixerThread *)output2);
-    mPlaybackThreads.add(thread);
-    return thread;
+
+    DuplicatingThread *thread = new DuplicatingThread(this, thread1);
+    thread->addOutputTrack(thread2);
+    mPlaybackThreads.add(++mNextThreadId, thread);
+    return mNextThreadId;
 }
 
-status_t AudioFlinger::closeOutput(void *output)
+status_t AudioFlinger::closeOutput(int output)
 {
-    PlaybackThread *thread;
+    // keep strong reference on the playback thread so that
+    // it is not destroyed while exit() is executed
+    sp <PlaybackThread> thread;
     {
         Mutex::Autolock _l(mLock);
         thread = checkPlaybackThread_l(output);
@@ -3291,24 +3332,27 @@
             return BAD_VALUE;
         }
 
-        LOGV("closeOutput() %p", thread);
+        LOGV("closeOutput() %d", output);
 
         if (thread->type() == PlaybackThread::MIXER) {
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                if (mPlaybackThreads[i]->type() == PlaybackThread::DUPLICATING) {
-                    DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads[i].get();
-                    dupThread->removeOutputTrack((MixerThread *)thread);
+                if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+                    DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
+                    dupThread->removeOutputTrack((MixerThread *)thread.get());
                 }
             }
         }
-        mPlaybackThreads.remove(thread);
+        mPlaybackThreads.removeItem(output);
     }
     thread->exit();
 
+    if (thread->type() != PlaybackThread::DUPLICATING) {
+        mAudioHardware->closeOutputStream(thread->getOutput());
+    }
     return NO_ERROR;
 }
 
-status_t AudioFlinger::suspendOutput(void *output)
+status_t AudioFlinger::suspendOutput(int output)
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -3317,13 +3361,13 @@
         return BAD_VALUE;
     }
 
-    LOGV("suspendOutput() %p", output);
+    LOGV("suspendOutput() %d", output);
     thread->suspend();
 
     return NO_ERROR;
 }
 
-status_t AudioFlinger::restoreOutput(void *output)
+status_t AudioFlinger::restoreOutput(int output)
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -3332,14 +3376,14 @@
         return BAD_VALUE;
     }
 
-    LOGV("restoreOutput() %p", output);
+    LOGV("restoreOutput() %d", output);
 
     thread->restore();
 
     return NO_ERROR;
 }
 
-void *AudioFlinger::openInput(uint32_t *pDevices,
+int AudioFlinger::openInput(uint32_t *pDevices,
                                 uint32_t *pSamplingRate,
                                 uint32_t *pFormat,
                                 uint32_t *pChannels,
@@ -3355,7 +3399,7 @@
     uint32_t reqChannels = channels;
 
     if (pDevices == NULL || *pDevices == 0) {
-        return NULL;
+        return 0;
     }
     Mutex::Autolock _l(mLock);
 
@@ -3392,8 +3436,8 @@
     if (input != 0) {
          // Start record thread
         thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
-        mRecordThreads.add(thread);
-
+        mRecordThreads.add(++mNextThreadId, thread);
+        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
         if (pSamplingRate) *pSamplingRate = reqSamplingRate;
         if (pFormat) *pFormat = format;
         if (pChannels) *pChannels = reqChannels;
@@ -3401,12 +3445,14 @@
         input->standby();
     }
 
-    return thread;
+    return mNextThreadId;
 }
 
-status_t AudioFlinger::closeInput(void *input)
+status_t AudioFlinger::closeInput(int input)
 {
-    RecordThread *thread;
+    // keep strong reference on the record thread so that
+    // it is not destroyed while exit() is executed
+    sp <RecordThread> thread;
     {
         Mutex::Autolock _l(mLock);
         thread = checkRecordThread_l(input);
@@ -3414,27 +3460,29 @@
             return BAD_VALUE;
         }
 
-        LOGV("closeInput() %p", thread);
-        mRecordThreads.remove(thread);
+        LOGV("closeInput() %d", input);
+        mRecordThreads.removeItem(input);
     }
     thread->exit();
 
+    mAudioHardware->closeInputStream(thread->getInput());
+
     return NO_ERROR;
 }
 
-status_t AudioFlinger::setStreamOutput(uint32_t stream, void *output)
+status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
 {
     Mutex::Autolock _l(mLock);
     MixerThread *dstThread = checkMixerThread_l(output);
     if (dstThread == NULL) {
-        LOGW("setStreamOutput() bad output thread %p", output);
+        LOGW("setStreamOutput() bad output id %d", output);
         return BAD_VALUE;
     }
 
-    LOGV("setStreamOutput() stream %d to output %p", stream, dstThread);
+    LOGV("setStreamOutput() stream %d to output %d", stream, output);
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        PlaybackThread *thread = mPlaybackThreads[i].get();
+        PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         if (thread != dstThread &&
             thread->type() != PlaybackThread::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
@@ -3452,22 +3500,17 @@
 }
 
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(void *output) const
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
 {
     PlaybackThread *thread = NULL;
-
-    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (mPlaybackThreads[i] == output) {
-            thread = (PlaybackThread *)output;
-            break;
-        }
+    if (mPlaybackThreads.indexOfKey(output) >= 0) {
+        thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
     }
-
     return thread;
 }
 
 // checkMixerThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(void *output) const
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
 {
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread != NULL) {
@@ -3479,17 +3522,12 @@
 }
 
 // checkRecordThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(void *input) const
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
 {
     RecordThread *thread = NULL;
-
-    for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        if (mRecordThreads[i] == input) {
-            thread = (RecordThread *)input;
-            break;
-        }
+    if (mRecordThreads.indexOfKey(input) >= 0) {
+        thread = (RecordThread *)mRecordThreads.valueFor(input).get();
     }
-
     return thread;
 }
 
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 06c5846..4ba5977 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -73,14 +73,14 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                void *output,
+                                int output,
                                 status_t *status);
 
-    virtual     uint32_t    sampleRate(void *output) const;
-    virtual     int         channelCount(void *output) const;
-    virtual     int         format(void *output) const;
-    virtual     size_t      frameCount(void *output) const;
-    virtual     uint32_t    latency(void *output) const;
+    virtual     uint32_t    sampleRate(int output) const;
+    virtual     int         channelCount(int output) const;
+    virtual     int         format(int output) const;
+    virtual     size_t      frameCount(int output) const;
+    virtual     uint32_t    latency(int output) const;
 
     virtual     status_t    setMasterVolume(float value);
     virtual     status_t    setMasterMute(bool muted);
@@ -88,10 +88,10 @@
     virtual     float       masterVolume() const;
     virtual     bool        masterMute() const;
 
-    virtual     status_t    setStreamVolume(int stream, float value, void *output);
+    virtual     status_t    setStreamVolume(int stream, float value, int output);
     virtual     status_t    setStreamMute(int stream, bool muted);
 
-    virtual     float       streamVolume(int stream, void *output) const;
+    virtual     float       streamVolume(int stream, int output) const;
     virtual     bool        streamMute(int stream) const;
 
     virtual     status_t    setMode(int mode);
@@ -101,37 +101,37 @@
 
     virtual     bool        isMusicActive() const;
 
-    virtual     status_t    setParameters(void *ioHandle, const String8& keyValuePairs);
-    virtual     String8     getParameters(void *ioHandle, const String8& keys);
+    virtual     status_t    setParameters(int ioHandle, const String8& keyValuePairs);
+    virtual     String8     getParameters(int ioHandle, const String8& keys);
 
     virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
 
     virtual     size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
 
-    virtual void *openOutput(uint32_t *pDevices,
+    virtual int openOutput(uint32_t *pDevices,
                                     uint32_t *pSamplingRate,
                                     uint32_t *pFormat,
                                     uint32_t *pChannels,
                                     uint32_t *pLatencyMs,
                                     uint32_t flags);
 
-    virtual void *openDuplicateOutput(void *output1, void *output2);
+    virtual int openDuplicateOutput(int output1, int output2);
 
-    virtual status_t closeOutput(void *output);
+    virtual status_t closeOutput(int output);
 
-    virtual status_t suspendOutput(void *output);
+    virtual status_t suspendOutput(int output);
 
-    virtual status_t restoreOutput(void *output);
+    virtual status_t restoreOutput(int output);
 
-    virtual void *openInput(uint32_t *pDevices,
+    virtual int openInput(uint32_t *pDevices,
                             uint32_t *pSamplingRate,
                             uint32_t *pFormat,
                             uint32_t *pChannels,
                             uint32_t acoustics);
 
-    virtual status_t closeInput(void *input);
+    virtual status_t closeInput(int input);
 
-    virtual status_t setStreamOutput(uint32_t stream, void *output);
+    virtual status_t setStreamOutput(uint32_t stream, int output);
 
     // IBinder::DeathRecipient
     virtual     void        binderDied(const wp<IBinder>& who);
@@ -158,7 +158,7 @@
     // record interface
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                void *input,
+                                int input,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -172,8 +172,6 @@
                                 Parcel* reply,
                                 uint32_t flags);
 
-    void audioConfigChanged(int event, void *param1, void *param2);
-
 private:
                             AudioFlinger();
     virtual                 ~AudioFlinger();
@@ -320,6 +318,7 @@
         virtual     String8     getParameters(const String8& keys) = 0;
         virtual     void        audioConfigChanged(int event, int param = 0) = 0;
                     void        sendConfigEvent(int event, int param = 0);
+                    void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
 
         mutable     Mutex                   mLock;
@@ -343,7 +342,7 @@
                     int                     mFormat;
                     uint32_t                mFrameSize;
                     Condition               mParamCond;
-                    String8                 mNewParameters;
+                    Vector<String8>         mNewParameters;
                     status_t                mParamStatus;
                     Vector<ConfigEvent *>   mConfigEvents;
                     bool                    mStandby;
@@ -503,8 +502,8 @@
                     AudioStreamOut* getOutput() { return mOutput; }
 
         virtual     int         type() const { return mType; }
-                    void        suspend() { mSuspended = true; }
-                    void        restore() { mSuspended = false; }
+                    void        suspend() { mSuspended++; }
+                    void        restore() { if (mSuspended) mSuspended--; }
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged(int event, int param = 0);
 
@@ -521,7 +520,7 @@
     protected:
         int                             mType;
         int16_t*                        mMixBuffer;
-        bool                            mSuspended;
+        int                             mSuspended;
         int                             mBytesWritten;
         bool                            mMasterMute;
         SortedVector< wp<Track> >       mActiveTracks;
@@ -615,10 +614,11 @@
         SortedVector < sp<OutputTrack> >  mOutputTracks;
     };
 
-              PlaybackThread *checkPlaybackThread_l(void *output) const;
-              MixerThread *checkMixerThread_l(void *output) const;
-              RecordThread *checkRecordThread_l(void *input) const;
+              PlaybackThread *checkPlaybackThread_l(int output) const;
+              MixerThread *checkMixerThread_l(int output) const;
+              RecordThread *checkRecordThread_l(int input) const;
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
+              void audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2);
 
     friend class AudioBuffer;
 
@@ -744,14 +744,15 @@
     mutable     int                                 mHardwareStatus;
 
 
-                SortedVector< sp<PlaybackThread> >  mPlaybackThreads;
+                DefaultKeyedVector< int, sp<PlaybackThread> >  mPlaybackThreads;
                 PlaybackThread::stream_type_t       mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
                 float                               mMasterVolume;
                 bool                                mMasterMute;
 
-                SortedVector< sp<RecordThread> >    mRecordThreads;
+                DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;
 
                 SortedVector< sp<IBinder> >         mNotificationClients;
+                int                                 mNextThreadId;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index 37be329..9a4a7f9 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -140,8 +140,8 @@
 // default implementation
 String8 AudioHardwareBase::getParameters(const String8& keys)
 {
-    String8 result = String8("");
-    return result;
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
 }
 
 // default implementation
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 1a03059..ae391ee 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -152,6 +152,12 @@
     return NO_ERROR;
 }
 
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
 // ----------------------------------------------------------------------------
 
 status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
@@ -187,6 +193,12 @@
     return NO_ERROR;
 }
 
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+    AudioParameter param = AudioParameter(keys);
+    return param.toString();
+}
+
 // ----------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 8f43259..583f852 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -40,7 +40,7 @@
     virtual status_t    standby();
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR;}
-    virtual String8     getParameters(const String8& keys) {String8 result = String8(""); return result;}
+    virtual String8     getParameters(const String8& keys);
 };
 
 class AudioStreamInStub : public AudioStreamIn {
@@ -55,7 +55,7 @@
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual status_t    standby() { return NO_ERROR; }
     virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR;}
-    virtual String8     getParameters(const String8& keys) {String8 result = String8(""); return result;}
+    virtual String8     getParameters(const String8& keys);
 };
 
 class AudioHardwareStub : public  AudioHardwareBase
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
index 4b31815..6323859 100644
--- a/libs/audioflinger/AudioPolicyManagerGeneric.cpp
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
@@ -197,8 +197,8 @@
 
 #ifdef AUDIO_POLICY_TEST
     if (mCurOutput != 0) {
-        LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelcount %d, mDirectOutput %d",
-                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannelcount, mDirectOutput);
+        LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
+                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
 
         if (mTestOutputs[mCurOutput] == 0) {
             LOGV("getOutput() opening test output");
@@ -206,7 +206,7 @@
             outputDesc->mDevice = mTestDevice;
             outputDesc->mSamplingRate = mTestSamplingRate;
             outputDesc->mFormat = mTestFormat;
-            outputDesc->mChannels = (mTestChannelcount == 1) ? AudioSystem::CHANNEL_OUT_MONO : AudioSystem::CHANNEL_OUT_STEREO;
+            outputDesc->mChannels = mTestChannels;
             outputDesc->mLatency = mTestLatencyMs;
             outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
             outputDesc->mRefCount[stream] = 0;
@@ -216,7 +216,12 @@
                                             &outputDesc->mChannels,
                                             &outputDesc->mLatency,
                                             outputDesc->mFlags);
-            mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
+            if (mTestOutputs[mCurOutput]) {
+                AudioParameter outputCmd = AudioParameter();
+                outputCmd.addInt(String8("set_id"),mCurOutput);
+                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+                mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
+            }
         }
         return mTestOutputs[mCurOutput];
     }
@@ -224,7 +229,7 @@
     if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
         (format != 0 && !AudioSystem::isLinearPCM(format)) ||
         (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
-        return NULL;
+        return 0;
     }
 
     return mHardwareOutput;
@@ -232,10 +237,10 @@
 
 status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
 {
-    LOGV("startOutput() output %p, stream %d", output, stream);
+    LOGV("startOutput() output %d, stream %d", output, stream);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
-        LOGW("startOutput() unknow output %p", output);
+        LOGW("startOutput() unknow output %d", output);
         return BAD_VALUE;
     }
 
@@ -253,10 +258,10 @@
 
 status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
 {
-    LOGV("stopOutput() output %p, stream %d", output, stream);
+    LOGV("stopOutput() output %d, stream %d", output, stream);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
-        LOGW("stopOutput() unknow output %p", output);
+        LOGW("stopOutput() unknow output %d", output);
         return BAD_VALUE;
     }
 
@@ -272,17 +277,17 @@
         outputDesc->changeRefCount(stream, -1);
         return NO_ERROR;
     } else {
-        LOGW("stopOutput() refcount is already 0 for output %p", output);
+        LOGW("stopOutput() refcount is already 0 for output %d", output);
         return INVALID_OPERATION;
     }
 }
 
 void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
 {
-    LOGV("releaseOutput() %p", output);
+    LOGV("releaseOutput() %d", output);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
-        LOGW("releaseOutput() releasing unknown output %p", output);
+        LOGW("releaseOutput() releasing unknown output %d", output);
         return;
     }
 
@@ -332,7 +337,7 @@
                 samplingRate, format, channels);
         mpClientInterface->closeInput(input);
         delete inputDesc;
-        return NULL;
+        return 0;
     }
     mInputs.add(input, inputDesc);
     return input;
@@ -340,10 +345,10 @@
 
 status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
 {
-    LOGV("startInput() input %p", input);
+    LOGV("startInput() input %d", input);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
-        LOGW("startInput() unknow input %p", input);
+        LOGW("startInput() unknow input %d", input);
         return BAD_VALUE;
     }
     AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
@@ -355,7 +360,7 @@
         // refuse 2 active AudioRecord clients at the same time
         for (size_t i = 0; i < mInputs.size(); i++) {
             if (mInputs.valueAt(i)->mRefCount > 0) {
-                LOGW("startInput() input %p, other input %p already started", input, mInputs.keyAt(i));
+                LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i));
                 return INVALID_OPERATION;
             }
         }
@@ -367,16 +372,16 @@
 
 status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
 {
-    LOGV("stopInput() input %p", input);
+    LOGV("stopInput() input %d", input);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
-        LOGW("stopInput() unknow input %p", input);
+        LOGW("stopInput() unknow input %d", input);
         return BAD_VALUE;
     }
     AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
 
     if (inputDesc->mRefCount == 0) {
-        LOGW("stopInput() input %p already stopped", input);
+        LOGW("stopInput() input %d already stopped", input);
         return INVALID_OPERATION;
     } else {
         inputDesc->mRefCount = 0;
@@ -386,10 +391,10 @@
 
 void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
 {
-    LOGV("releaseInput() %p", input);
+    LOGV("releaseInput() %d", input);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
-        LOGW("releaseInput() releasing unknown input %p", input);
+        LOGW("releaseInput() releasing unknown input %d", input);
         return;
     }
     mpClientInterface->closeInput(input);
@@ -438,7 +443,7 @@
 
         float volume = computeVolume((int)stream, index, device);
 
-        LOGV("setStreamVolume() for output %p stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
+        LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
         mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
     }
     return NO_ERROR;
@@ -495,10 +500,14 @@
     }
 
 #ifdef AUDIO_POLICY_TEST
+    AudioParameter outputCmd = AudioParameter();
+    outputCmd.addInt(String8("set_id"), 0);
+    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+
     mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
     mTestSamplingRate = 44100;
     mTestFormat = AudioSystem::PCM_16_BIT;
-    mTestChannelcount = 2;
+    mTestChannels =  AudioSystem::CHANNEL_OUT_STEREO;
     mTestLatencyMs = 0;
     mCurOutput = 0;
     mDirectOutput = false;
@@ -537,15 +546,23 @@
     LOGV("entering threadLoop()");
     while (!exitPending())
     {
+        String8 command;
+        int valueInt;
+        String8 value;
+
         Mutex::Autolock _l(mLock);
         mWaitWorkCV.waitRelative(mLock, milliseconds(50));
-        String8 command;
+
         command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
-        if (command != "") {
+        AudioParameter param = AudioParameter(command);
+
+        if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+            valueInt != 0) {
             LOGV("Test command %s received", command.string());
-            AudioParameter param = AudioParameter(command);
-            int valueInt;
-            String8 value;
+            String8 target;
+            if (param.get(String8("target"), target) != NO_ERROR) {
+                target = "Manager";
+            }
             if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
                 param.remove(String8("test_cmd_policy_output"));
                 mCurOutput = valueInt;
@@ -565,28 +582,84 @@
 
             if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
                 param.remove(String8("test_cmd_policy_format"));
+                int format = AudioSystem::INVALID_FORMAT;
                 if (value == "PCM 16 bits") {
-                    mTestFormat = AudioSystem::PCM_16_BIT;
+                    format = AudioSystem::PCM_16_BIT;
                 } else if (value == "PCM 8 bits") {
-                    mTestFormat = AudioSystem::PCM_8_BIT;
+                    format = AudioSystem::PCM_8_BIT;
                 } else if (value == "Compressed MP3") {
-                    mTestFormat = AudioSystem::MP3;
+                    format = AudioSystem::MP3;
+                }
+                if (format != AudioSystem::INVALID_FORMAT) {
+                    if (target == "Manager") {
+                        mTestFormat = format;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("format"), format);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
                 }
             }
             if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
                 param.remove(String8("test_cmd_policy_channels"));
+                int channels = 0;
+
                 if (value == "Channels Stereo") {
-                    mTestChannelcount = 2;
+                    channels =  AudioSystem::CHANNEL_OUT_STEREO;
                 } else if (value == "Channels Mono") {
-                    mTestChannelcount = 1;
+                    channels =  AudioSystem::CHANNEL_OUT_MONO;
+                }
+                if (channels != 0) {
+                    if (target == "Manager") {
+                        mTestChannels = channels;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("channels"), channels);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
                 }
             }
             if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
                 param.remove(String8("test_cmd_policy_sampleRate"));
                 if (valueInt >= 0 && valueInt <= 96000) {
-                    mTestSamplingRate = valueInt;
+                    int samplingRate = valueInt;
+                    if (target == "Manager") {
+                        mTestSamplingRate = samplingRate;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("sampling_rate"), samplingRate);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
                 }
             }
+
+            if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_reopen"));
+
+                mpClientInterface->closeOutput(mHardwareOutput);
+                delete mOutputs.valueFor(mHardwareOutput);
+                mOutputs.removeItem(mHardwareOutput);
+
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+                outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+                mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannels,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (mHardwareOutput == 0) {
+                    LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+                            outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+                } else {
+                    AudioParameter outputCmd = AudioParameter();
+                    outputCmd.addInt(String8("set_id"), 0);
+                    mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+                    mOutputs.add(mHardwareOutput, outputDesc);
+                }
+            }
+
+
             mpClientInterface->setParameters(0, String8("test_cmd_policy="));
         }
     }
@@ -657,7 +730,7 @@
 
 void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
 {
-    LOGV("setStreamMute() stream %d, mute %d, output %p", stream, on, output);
+    LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output);
 
     StreamDescriptor &streamDesc = mStreams[stream];
 
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
index ddcb306..d904520 100644
--- a/libs/audioflinger/AudioPolicyManagerGeneric.h
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.h
@@ -180,7 +180,7 @@
         uint32_t        mTestDevice;
         uint32_t        mTestSamplingRate;
         uint32_t        mTestFormat;
-        uint32_t        mTestChannelcount;
+        uint32_t        mTestChannels;
         uint32_t        mTestLatencyMs;
 #endif //AUDIO_POLICY_TEST
 
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
index 7f6c4ed..ae17d76 100644
--- a/libs/audioflinger/AudioPolicyService.cpp
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -201,7 +201,7 @@
                                     AudioSystem::output_flags flags)
 {
     if (mpPolicyManager == NULL) {
-        return NULL;
+        return 0;
     }
     LOGV("getOutput() tid %d", gettid());
     Mutex::Autolock _l(mLock);
@@ -245,7 +245,7 @@
                                     AudioSystem::audio_in_acoustics acoustics)
 {
     if (mpPolicyManager == NULL) {
-        return NULL;
+        return 0;
     }
     Mutex::Autolock _l(mLock);
     return mpPolicyManager->getInput(inputSource, samplingRate, format, channels, acoustics);
@@ -381,7 +381,7 @@
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
         LOGW("openOutput() could not get AudioFlinger");
-        return NULL;
+        return 0;
     }
 
     return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
@@ -392,7 +392,7 @@
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
         LOGW("openDuplicateOutput() could not get AudioFlinger");
-        return NULL;
+        return 0;
     }
     return af->openDuplicateOutput(output1, output2);
 }
@@ -437,7 +437,7 @@
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
         LOGW("openInput() could not get AudioFlinger");
-        return NULL;
+        return 0;
     }
 
     return af->openInput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, acoustics);
@@ -453,7 +453,7 @@
 
 status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output)
 {
-    return mAudioCommandThread->volumeCommand((int)stream, volume, (void *)output);
+    return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output);
 }
 
 status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
@@ -467,7 +467,7 @@
 
 void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
 {
-    mAudioCommandThread->parametersCommand((void *)ioHandle, keyValuePairs);
+    mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs);
 }
 
 String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys)
@@ -547,7 +547,7 @@
                 }break;
             case SET_VOLUME: {
                 VolumeData *data = (VolumeData *)command->mParam;
-                LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %p", data->mStream, data->mVolume, data->mIO);
+                LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
                 mCommandStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
                 mCommandCond.signal();
                 mWaitWorkCV.wait(mLock);
@@ -555,7 +555,7 @@
                 }break;
             case SET_PARAMETERS: {
                  ParametersData *data = (ParametersData *)command->mParam;
-                 LOGV("AudioCommandThread() processing set parameters string %s, io %p", data->mKeyValuePairs.string(), data->mIO);
+                 LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
                  mCommandStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
                  mCommandCond.signal();
                  mWaitWorkCV.wait(mLock);
@@ -599,7 +599,7 @@
     mWaitWorkCV.signal();
 }
 
-status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, void *output)
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output)
 {
     Mutex::Autolock _l(mLock);
     AudioCommand *command = new AudioCommand();
@@ -610,7 +610,7 @@
     data->mIO = output;
     command->mParam = data;
     mAudioCommands.add(command);
-    LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %p", stream, volume, output);
+    LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
     mWaitWorkCV.signal();
     mCommandCond.wait(mLock);
     status_t status =  mCommandStatus;
@@ -618,7 +618,7 @@
     return status;
 }
 
-status_t AudioPolicyService::AudioCommandThread::parametersCommand(void *ioHandle, const String8& keyValuePairs)
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs)
 {
     Mutex::Autolock _l(mLock);
     AudioCommand *command = new AudioCommand();
@@ -628,7 +628,7 @@
     data->mKeyValuePairs = keyValuePairs;
     command->mParam = data;
     mAudioCommands.add(command);
-    LOGV("AudioCommandThread() adding set parameter string %s, io %p", keyValuePairs.string(), ioHandle);
+    LOGV("AudioCommandThread() adding set parameter string %s, io %d", keyValuePairs.string(), ioHandle);
     mWaitWorkCV.signal();
     mCommandCond.wait(mLock);
     status_t status =  mCommandStatus;
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
index 1c46975..3909fa4 100644
--- a/libs/audioflinger/AudioPolicyService.h
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -136,8 +136,8 @@
                     void        exit();
                     void        startToneCommand(int type = 0, int stream = 0);
                     void        stopToneCommand();
-                    status_t    volumeCommand(int stream, float volume, void *output);
-                    status_t    parametersCommand(void *ioHandle, const String8& keyValuePairs);
+                    status_t    volumeCommand(int stream, float volume, int output);
+                    status_t    parametersCommand(int ioHandle, const String8& keyValuePairs);
 
     private:
         // descriptor for requested tone playback event
@@ -157,11 +157,11 @@
         public:
             int mStream;
             float mVolume;
-            void *mIO;
+            int mIO;
         };
         class ParametersData {
         public:
-            void *mIO;
+            int mIO;
             String8 mKeyValuePairs;
         };
 
diff --git a/libs/rs/java/Fall/AndroidManifest.xml b/libs/rs/java/Fall/AndroidManifest.xml
index f4f96a1..f646d0d 100644
--- a/libs/rs/java/Fall/AndroidManifest.xml
+++ b/libs/rs/java/Fall/AndroidManifest.xml
@@ -5,6 +5,7 @@
     <application android:label="FallRS">
 
         <activity
+            android:screenOrientation="portrait"
             android:name="Fall"
             android:theme="@android:style/Theme.NoTitleBar">
 
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
new file mode 100644
index 0000000..1698f28
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index 76847e0..ba9dd25 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -1,11 +1,318 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #pragma version(1)
 #pragma stateVertex(PVBackground)
 #pragma stateFragment(PFBackground)
-#pragma stateFragmentStore(PSBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define RSID_STATE 0
+#define RSID_FRAME_COUNT 0
+#define RSID_WIDTH 1
+#define RSID_HEIGHT 2
+#define RSID_MESH_WIDTH 3
+#define RSID_MESH_HEIGHT 4
+#define RSID_RIPPLE_MAP_SIZE 5
+#define RSID_RIPPLE_INDEX 6
+#define RSID_DROP_X 7
+#define RSID_DROP_Y 8
+#define RSID_RUNNING 9
+    
+#define RSID_TEXTURES 1
+
+#define RSID_RIPPLE_MAP 2
+
+#define RSID_REFRACTION_MAP 3
+
+#define REFRACTION 1.333f
+#define DAMP 3
+
+#define DROP_RADIUS 2
+// The higher, the smaller the ripple
+#define RIPPLE_HEIGHT 10.0f
+
+int offset(int x, int y, int width) {
+    return x + 1 + (y + 1) * (width + 2);
+}
+
+void drop(int x, int y, int r) {
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+
+    if (x < r) x = r;
+    if (y < r) y = r;
+    if (x >= width - r) x = width - r - 1;
+    if (y >= height - r) x = height - r - 1;
+    
+    x = width - x;
+
+    int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
+    int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+    int origin = offset(0, 0, width);
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    int sqr = r * r;
+
+    int h = 0;
+    for ( ; h < r; h++) {
+        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++) {
+            int squ = w * w;
+            if (squ + sqv < sqr) {
+                int v = -sqrtf((sqr - (squ + sqv)) << 16);
+                current[yn + x + w] = v;
+                current[yp + x + w] = v;
+                current[yn + x - w] = v;
+                current[yp + x - w] = v;
+            }
+        }
+    }
+}
+
+void updateRipples() {
+    int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+    int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+    int origin = offset(0, 0, width);
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
+
+    storeI32(RSID_STATE, RSID_RIPPLE_INDEX, 1 - index);
+
+    int a = 1;
+    int b = width + 2;
+    int h = height;
+    while (h) {
+        int w = width;
+        while (w) {
+            int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - next[0];
+            droplet -= (droplet >> DAMP);
+            next[0] = droplet;
+            current++;
+            next++;
+            w--;
+        }
+        current += 2;
+        next += 2;
+        h--;
+    }
+}
+
+int refraction(int d, int wave) {
+    int* map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+    int i = d;
+    if (i < 0) i = -i;
+    if (i > 512) i = 512;
+    int w = (wave + 0x10000) >> 8;
+    w &= ~(w >> 31);
+    int r = (map[i] * w) >> 3;
+    if (d < 0) {
+        return -r;
+    }
+    return r;
+}
+
+void generateRipples() {
+    int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+    int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+    int origin = offset(0, 0, width);
+
+    int b = width + 2;
+
+    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+    float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+
+    int h = height - 1;
+    while (h >= 0) {
+        int w = width - 1;
+        int wave = current[0];
+        int offset = h * width;
+        while (w >= 0) {
+            int nextWave = current[1];
+            int dx = nextWave - wave;
+            int dy = current[b] - wave;
+
+            int offsetx = refraction(dx, wave) >> 16;
+            int u = (width - w) + offsetx;
+            u &= ~(u >> 31);
+            if (u >= width) u = width - 1;
+
+            int offsety = refraction(dy, wave) >> 16;
+            int v = (height - h) + offsety;
+            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;
+
+            // Update Z coordinate of the vertex
+            vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
+            
+            w--;
+            current++;
+            wave = nextWave;
+        }
+        h--;
+        current += 2;
+    }
+
+    // Compute the normals for lighting
+    int y = 0;
+    for ( ; y < height; y++) {
+        int x = 0;
+        int yOffset = y * width;
+        for ( ; x < width; x++) {
+            // V1
+            float v1x = vertices[(yOffset + x) * 8 + 5];
+            float v1y = vertices[(yOffset + x) * 8 + 6];
+            float v1z = vertices[(yOffset + x) * 8 + 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];
+            
+            // 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];
+
+            // N1
+            float n1x = v2x - v1x;
+            float n1y = v2y - v1y;
+            float n1z = v2z - v1z;
+
+            // N2
+            float n2x = v3x - v1x;
+            float n2y = v3y - v1y;
+            float n2z = v3z - v1z;
+
+            // N1 x N2
+            float n3x = n1y * n2z - n1z * n2y;
+            float n3y = n1z * n2x - n1x * n2z;
+            float n3z = n1x * n2y - n1y * n2x;
+
+            // Normalize
+            float len = 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];
+
+            // N1
+            n1x = v2x - v1x;
+            n1y = v2y - v1y;
+            n1z = v2z - v1z;
+
+            // N2
+            n2x = v3x - v1x;
+            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;
+
+            // Normalize
+            len = 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;
+            
+            // reset Z
+            vertices[(yOffset + x) * 8 + 7] = 0.0f;
+        }
+    }
+}
+
+void drawNormals() {
+    int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
+    int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+
+    float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+    
+    bindProgramVertex(NAMED_PVLines);
+    color(1.0f, 0.0f, 0.0f, 1.0f);
+
+    int y = 0;
+    for ( ; y < height; y++) {
+        int yOffset = y * width;
+        int x = 0;
+        for ( ; x < width; x++) {
+            float vx = vertices[(yOffset + x) * 8 + 5];
+            float vy = vertices[(yOffset + x) * 8 + 6];
+            float vz = vertices[(yOffset + x) * 8 + 7];
+            float nx = vertices[(yOffset + x) * 8 + 0];
+            float ny = vertices[(yOffset + x) * 8 + 1];
+            float nz = vertices[(yOffset + x) * 8 + 2];
+            drawLine(vx, vy, vz, vx + nx / 10.0f, vy + ny / 10.0f, vz + nz / 10.0f);
+        }
+    }
+}
 
 int main(int index) {
-    color(1.0f, 0.0f, 0.0f, 1.0f);
-    drawTriangleMesh(NAMED_mesh);    
+    int dropX = loadI32(RSID_STATE, RSID_DROP_X);
+    if (dropX != -1) {
+        int dropY = loadI32(RSID_STATE, RSID_DROP_Y);
+        drop(dropX, dropY, DROP_RADIUS);
+        storeI32(RSID_STATE, RSID_DROP_X, -1);
+        storeI32(RSID_STATE, RSID_DROP_Y, -1);
+    }
+
+    int isRunning = loadI32(RSID_STATE, RSID_RUNNING);
+    if (isRunning) {
+        updateRipples();
+        generateRipples();
+        updateTriangleMesh(NAMED_mesh);
+    }
+
+    bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
+    drawTriangleMesh(NAMED_mesh);
+    
+    ambient(0.0f, 0.0f, 0.0f, 1.0f);
+    diffuse(0.0f, 0.0f, 0.0f, 1.0f);
+    specular(0.44f, 0.44f, 0.44f, 1.0f);
+    shininess(40.0f);
+    bindProgramFragment(NAMED_PFLighting);
+    drawTriangleMesh(NAMED_mesh);
+
+//    bindProgramVertex(NAMED_PVSky);
+//    bindProgramFragment(NAMED_PFSky);
+//    bindProgramFragmentStore(NAMED_PFSSky);
+//    color(1.0f, 1.0f, 1.0f, 0.30f);
+//    bindTexture(NAMED_PFSky, 0, NAMED_TSky);
+//    drawTriangleMesh(NAMED_mesh);
+
+    if (!isRunning) {
+        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 155bb6f..1685a62 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
@@ -25,6 +25,7 @@
 import android.renderscript.Allocation;
 import android.renderscript.Sampler;
 import android.renderscript.Element;
+import android.renderscript.Light;
 import static android.renderscript.Sampler.Value.LINEAR;
 import static android.renderscript.Sampler.Value.CLAMP;
 import static android.renderscript.ProgramStore.DepthFunc.*;
@@ -32,25 +33,36 @@
 import static android.renderscript.ProgramStore.BlendSrcFunc;
 import static android.renderscript.ProgramFragment.EnvMode.*;
 import static android.renderscript.Element.*;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
 
 import java.util.TimeZone;
 
 class FallRS {
-    private static final int MESH_RESOLUTION = 32;
+    private static final int MESH_RESOLUTION = 48;
 
     private static final int RSID_STATE = 0;
     private static final int RSID_STATE_FRAMECOUNT = 0;
     private static final int RSID_STATE_WIDTH = 1;
     private static final int RSID_STATE_HEIGHT = 2;
-
+    private static final int RSID_STATE_MESH_WIDTH = 3;
+    private static final int RSID_STATE_MESH_HEIGHT = 4;
+    private static final int RSID_STATE_RIPPLE_MAP_SIZE = 5;
+    private static final int RSID_STATE_RIPPLE_INDEX = 6;
+    private static final int RSID_STATE_DROP_X = 7;
+    private static final int RSID_STATE_DROP_Y = 8;
+    private static final int RSID_STATE_RUNNING = 9;
+    
     private static final int RSID_TEXTURES = 1;
-    private static final int TEXTURES_COUNT = 0;
+    private static final int TEXTURES_COUNT = 1;
+    private static final int RSID_TEXTURE_RIVERBED = 0;
 
+    private static final int RSID_RIPPLE_MAP = 2;
+
+    private static final int RSID_REFRACTION_MAP = 3;
+
+    private boolean mIsRunning = true;    
+    
     private Resources mResources;
     private RenderScript mRS;
-    private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
 
     private final int mWidth;
     private final int mHeight;
@@ -58,9 +70,12 @@
     private ScriptC mScript;
     private Sampler mSampler;
     private ProgramFragment mPfBackground;
+    private ProgramFragment mPfLighting;
     private ProgramStore mPfsBackground;
     private ProgramVertex mPvBackground;
+    private ProgramVertex mPvLines;
     private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
+    private Light mLight;
 
     private Allocation mTexturesIDs;
     private Allocation[] mTextures;
@@ -68,12 +83,15 @@
 
     private Allocation mState;
     private RenderScript.TriangleMesh mMesh;
+    private int mMeshWidth;
+    private int mMeshHeight;
+
+    private Allocation mRippleMap;
+    private Allocation mRefractionMap;
 
     public FallRS(int width, int height) {
         mWidth = width;
         mHeight = height;
-        mBitmapOptions.inScaled = false;
-        mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
     }
 
     public void init(RenderScript rs, Resources res) {
@@ -96,6 +114,11 @@
         mState.destroy();
         mTextureBufferIDs = null;
         mMesh.destroy();
+        mLight.destroy();
+        mRippleMap.destroy();
+        mRefractionMap.destroy();
+        mPvLines.destroy();
+        mPfLighting.destroy();
     }
 
     @Override
@@ -111,8 +134,9 @@
         createProgramVertex();
         createProgramFragmentStore();
         createProgramFragment();
-        createScriptStructures();
         createMesh();
+        createScriptStructures();
+        loadTextures();
 
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setScript(mResources, R.raw.fall);
@@ -121,16 +145,17 @@
         mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
         mScript.setTimeZone(TimeZone.getDefault().getID());
 
-        loadSkyTextures();
         mScript.bindAllocation(mState, RSID_STATE);
         mScript.bindAllocation(mTexturesIDs, RSID_TEXTURES);
+        mScript.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
+        mScript.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
 
         mRS.contextBindRootScript(mScript);
     }
 
     private void createMesh() {
         final RenderScript rs = mRS;
-        rs.triangleMeshBegin(Element.XYZ_F32, Element.INDEX_16);
+        rs.triangleMeshBegin(Element.NORM_ST_XYZ_F32, Element.INDEX_16);
 
         int wResolution;
         int hResolution;
@@ -146,13 +171,21 @@
             hResolution = MESH_RESOLUTION;
         }
 
-        final float quadWidth = width / (float) wResolution;
-        final float quadHeight = height / (float) hResolution;
+        final float glHeight = 2.0f * height / (float) width;
+        final float quadWidth = 2.0f / (float) wResolution;
+        final float quadHeight = glHeight / (float) hResolution;
 
+        wResolution += 2;
+        hResolution += 2;        
+        
         for (int y = 0; y <= hResolution; y++) {
-            final float yOffset = y * quadHeight;
+            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(x * quadWidth, yOffset, 0.0f);
+                rs.triangleMeshAddVertex_XYZ_ST_NORM(
+                        -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
+                        x / (float) wResolution, t,
+                        0.0f, 0.0f, -1.0f);
             }
         }
 
@@ -167,24 +200,48 @@
 
         mMesh = rs.triangleMeshCreate();
         mMesh.setName("mesh");
+
+        mMeshWidth = wResolution + 1;
+        mMeshHeight = hResolution + 1;
     }
 
     private void createScriptStructures() {
-        final int[] data = new int[3];
+        final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
+
+        final int[] data = new int[10];
         mState = Allocation.createSized(mRS, USER_I32, data.length);
         data[RSID_STATE_FRAMECOUNT] = 0;
         data[RSID_STATE_WIDTH] = mWidth;
         data[RSID_STATE_HEIGHT] = mHeight;
+        data[RSID_STATE_MESH_WIDTH] = mMeshWidth;
+        data[RSID_STATE_MESH_HEIGHT] = mMeshHeight;
+        data[RSID_STATE_RIPPLE_MAP_SIZE] = rippleMapSize;
+        data[RSID_STATE_RIPPLE_INDEX] = 0;
+        data[RSID_STATE_DROP_X] = mMeshWidth / 2;
+        data[RSID_STATE_DROP_Y] = mMeshHeight / 2;
+        data[RSID_STATE_RUNNING] = 1;
         mState.data(data);
+
+        final int[] rippleMap = new int[rippleMapSize * 2];
+        mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+
+        final int[] refractionMap = new int[513];
+        float ir = 1.0f / 1.333f;
+        for (int i = 0; i < refractionMap.length; i++) {
+            float d = (float) Math.tan(Math.asin(Math.sin(Math.atan(i * (1.0f / 256.0f))) * ir));
+            refractionMap[i] = (int) Math.floor(d * (1 << 16) + 0.5f);
+        }
+        mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
+        mRefractionMap.data(refractionMap);
     }
 
-    private void loadSkyTextures() {
+    private void loadTextures() {
         mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
         mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
 
         final Allocation[] textures = mTextures;
-        // TOOD: Load textures
+        textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
 
         final int[] bufferIds = mTextureBufferIDs;
         final int count = textures.length;
@@ -205,52 +262,66 @@
         return allocation;
     }
 
-    private Allocation loadTextureARGB(int id, String name) {
-        // Forces ARGB 32 bits, because pngcrush sometimes optimize our PNGs to
-        // indexed pictures, which are not well supported
-        final Bitmap b = BitmapFactory.decodeResource(mResources, id, mBitmapOptions);
-        final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
-        allocation.setName(name);
-        return allocation;
-    }
-
     private void createProgramFragment() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMin(LINEAR);
-        bs.setMag(LINEAR);
-        bs.setWrapS(CLAMP);
-        bs.setWrapT(CLAMP);
-        mSampler = bs.create();
+        Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
+        sampleBuilder.setMin(LINEAR);
+        sampleBuilder.setMag(LINEAR);
+        sampleBuilder.setWrapS(CLAMP);
+        sampleBuilder.setWrapT(CLAMP);
+        mSampler = sampleBuilder.create();
 
-        ProgramFragment.Builder b;
-        b = new ProgramFragment.Builder(mRS, null, null);
-        b.setTexEnable(true, 0);
-        b.setTexEnvMode(REPLACE, 0);
-        mPfBackground = b.create();
+        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(true, 0);
+        builder.setTexEnvMode(REPLACE, 0);
+        mPfBackground = builder.create();
         mPfBackground.setName("PFBackground");
         mPfBackground.bindSampler(mSampler, 0);
+        
+        builder = new ProgramFragment.Builder(mRS, null, null);
+        builder.setTexEnable(false, 0);
+        mPfLighting = builder.create();
+        mPfLighting.setName("PFLighting");
+        mPfLighting.bindSampler(mSampler, 0);
     }
 
     private void createProgramFragmentStore() {
-        ProgramStore.Builder b;
-        b = new ProgramStore.Builder(mRS, null, null);
-
-        b.setDepthFunc(ALWAYS);
-        b.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        b.setDitherEnable(true);
-        b.setDepthMask(false);
-        mPfsBackground = b.create();
+        ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
+        builder.setDepthFunc(ALWAYS);
+        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+        builder.setDitherEnable(true);
+        builder.setDepthMask(true);
+        mPfsBackground = builder.create();
         mPfsBackground.setName("PFSBackground");
     }
 
     private void createProgramVertex() {
         mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
-        mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
+        mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
 
-        ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
-        pvb.setTextureMatrixEnable(true);
-        mPvBackground = pvb.create();
+        mLight = new Light.Builder(mRS).create();
+        mLight.setPosition(0.0f, 2.0f, -8.0f);
+
+        ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
+        builder.setTextureMatrixEnable(true);
+        builder.addLight(mLight);
+        mPvBackground = builder.create();
         mPvBackground.bindAllocation(mPvOrthoAlloc);
         mPvBackground.setName("PVBackground");
+        
+        builder = new ProgramVertex.Builder(mRS, null, null);
+        mPvLines = builder.create();
+        mPvLines.bindAllocation(mPvOrthoAlloc);
+        mPvLines.setName("PVLines");
+    }
+
+    void addDrop(float x, float y) {
+        mState.subData1D(RSID_STATE_DROP_X, 2, new int[] {
+                (int) ((x / mWidth) * mMeshWidth), (int) ((y / mHeight) * mMeshHeight)
+        });
+    }
+    
+    void togglePause() {
+        mIsRunning = !mIsRunning;
+        mState.subData1D(RSID_STATE_RUNNING, 1, new int[] { mIsRunning ? 1 : 0 });
     }
 }
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
index ebbdba5..d7573be 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
@@ -19,6 +19,8 @@
 
 import android.content.Context;
 import android.view.SurfaceHolder;
+import android.view.MotionEvent;
+import android.view.KeyEvent;
 import android.renderscript.RenderScript;
 import android.renderscript.RSSurfaceView;
 
@@ -27,6 +29,8 @@
 
     public FallView(Context context) {
         super(context);
+        setFocusable(true);
+        setFocusableInTouchMode(true);
     }
 
     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
@@ -41,4 +45,29 @@
     public void surfaceDestroyed(SurfaceHolder holder) {
         if (mRender != null) mRender.destroy();
     }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
+                keyCode == KeyEvent.KEYCODE_MENU) {
+            mRender.togglePause();
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE:
+                mRender.addDrop(event.getX(), event.getY());
+                try {
+                    Thread.sleep(16);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+                break;
+        }
+        return true;
+    }
 }
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
index a32739c..6c17967 100644
--- a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
@@ -123,7 +123,7 @@
         createProgramFragmentStore();
         createProgramFragment();
         createScriptStructures();
-        loadSkyTextures();
+        loadTextures();
 
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setScript(mResources, R.raw.grass);
@@ -172,7 +172,7 @@
         blades[index + BLADE_STRUCT_B] = random(0.65f) + 0.35f;
     }
 
-    private void loadSkyTextures() {
+    private void loadTextures() {
         mTextureBufferIDs = new int[TEXTURES_COUNT];
         mTextures = new Allocation[TEXTURES_COUNT];
         mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index c66e488..6ef5456 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -63,7 +63,7 @@
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     if (mLightCount) {
-        int v = 1;
+        int v = 0;
         glEnable(GL_LIGHTING);
         glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v);
         for (uint32_t ct = 0; ct < mLightCount; ct++) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index b7c66e2..813af5d 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -75,6 +75,25 @@
     return i + offset;
 }
 
+static float* SC_loadTriangleMeshVerticesF(RsTriangleMesh mesh)
+{
+    TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+    void *vp = tm->mVertexData;
+    float *f = static_cast<float *>(vp);
+    return f;
+}
+
+static void SC_updateTriangleMesh(RsTriangleMesh mesh)
+{
+    TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+    glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+    glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);    
+}
 
 static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
 {
@@ -525,6 +544,24 @@
     glDrawArrays(GL_TRIANGLES, 0, count * 3);
 }
 
+static void SC_drawLine(float x1, float y1, float z1,
+                        float x2, float y2, float z2)
+{
+    GET_TLS();
+    rsc->setupCheck();
+
+    float vtx[] = { x1, y1, z1, x2, y2, z2 };
+
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+    glDisableClientState(GL_NORMAL_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+
+    glDrawArrays(GL_LINES, 0, 2);
+}
+
 static void SC_drawQuad(float x1, float y1, float z1,
                         float x2, float y2, float z2,
                         float x3, float y3, float z3,
@@ -584,6 +621,35 @@
     glColor4f(r, g, b, a);
 }
 
+static void SC_ambient(float r, float g, float b, float a)
+{
+    GLfloat params[] = { r, g, b, a };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, params);
+}
+
+static void SC_diffuse(float r, float g, float b, float a)
+{
+    GLfloat params[] = { r, g, b, a };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
+}
+
+static void SC_specular(float r, float g, float b, float a)
+{
+    GLfloat params[] = { r, g, b, a };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, params);
+}
+
+static void SC_emission(float r, float g, float b, float a)
+{
+    GLfloat params[] = { r, g, b, a };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
+}
+
+static void SC_shininess(float s)
+{
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
+}
+
 static void SC_hsb(float h, float s, float b, float a)
 {
     float red = 0.0f;
@@ -637,25 +703,6 @@
     glColor4f(red, green, blue, a);
 }
 
-/*
-extern "C" void materialDiffuse(float r, float g, float b, float a)
-{
-    float v[] = {r, g, b, a};
-    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
-}
-
-extern "C" void materialSpecular(float r, float g, float b, float a)
-{
-    float v[] = {r, g, b, a};
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
-}
-
-extern "C" void materialShininess(float s)
-{
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
-}
-*/
-
 static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
 {
     GET_TLS();
@@ -712,6 +759,10 @@
         "void", "(int, int, float *)" },
     { "storeMatrix", (void *)&SC_storeMatrix,
         "void", "(int, int, float *)" },
+    { "loadTriangleMeshVerticesF", (void *)&SC_loadTriangleMeshVerticesF,
+        "float*", "(int)" },
+    { "updateTriangleMesh", (void *)&SC_updateTriangleMesh,
+        "void", "(int)" },
 
     // math
     { "sinf", (void *)&sinf,
@@ -850,6 +901,8 @@
         "void", "(int mesh)" },
     { "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
         "void", "(int mesh, int start, int count)" },
+    { "drawLine", (void *)&SC_drawLine,
+        "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
 
 
     // misc
@@ -859,6 +912,16 @@
         "void", "(float, float, float, float)" },
     { "hsb", (void *)&SC_hsb,
         "void", "(float, float, float, float)" },
+    { "ambient", (void *)&SC_ambient,
+        "void", "(float, float, float, float)" },
+    { "diffuse", (void *)&SC_diffuse,
+        "void", "(float, float, float, float)" },
+    { "specular", (void *)&SC_specular,
+        "void", "(float, float, float, float)" },
+    { "emission", (void *)&SC_emission,
+        "void", "(float, float, float, float)" },
+    { "shininess", (void *)&SC_shininess,
+        "void", "(float)" },
 
     { "uploadToTexture", (void *)&SC_uploadToTexture,
         "void", "(int, int)" },
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 1f9e3af..9afe6a1 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -25,6 +25,8 @@
 import android.content.BroadcastReceiver;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothClass;
 
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
@@ -219,6 +221,8 @@
     // Forced device usage for communications
     private int mForcedUseForComm;
 
+    private BluetoothDevice mBluetoothDevice = null;
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -243,7 +247,7 @@
         IntentFilter intentFilter =
                 new IntentFilter(Intent.ACTION_HEADSET_PLUG);
         intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
-        intentFilter.addAction(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION);
+        intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
         context.registerReceiver(mReceiver, intentFilter);
     }
 
@@ -756,9 +760,11 @@
     public void setBluetoothScoOn(boolean on){
         if (on) {
             AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
+            AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
             mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
         } else {
             AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+            AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE);
             mForcedUseForComm = AudioSystem.FORCE_NONE;
         }
     }
@@ -1257,8 +1263,9 @@
                     // Restore call state
                     AudioSystem.setPhoneState(mMode);
 
-                    // Restore forced usage for communcations
+                    // Restore forced usage for communcations and record
                     AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
+                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
 
                     // Restore stream volumes
                     int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -1343,31 +1350,61 @@
                 int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
                                                BluetoothA2dp.STATE_DISCONNECTED);
                 String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
-                if (state == BluetoothA2dp.STATE_DISCONNECTED) {
+
+                boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
+                                       ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address));
+
+                if (isConnected &&
+                    state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) {
                     AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                             AudioSystem.DEVICE_STATE_UNAVAILABLE,
                             address);
                     mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
-                } else if (state == BluetoothA2dp.STATE_CONNECTED){
+                } else if (!isConnected &&
+                           (state == BluetoothA2dp.STATE_CONNECTED || state != BluetoothA2dp.STATE_PLAYING)){
                     AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                                                          AudioSystem.DEVICE_STATE_AVAILABLE,
                                                          address);
                     mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address);
                 }
-            } else if (action.equals(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION)) {
-                int state = intent.getIntExtra(BluetoothIntent.HEADSET_AUDIO_STATE,
+            } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
+                int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
                                                BluetoothHeadset.STATE_ERROR);
                 String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
-                if (state == BluetoothHeadset.AUDIO_STATE_DISCONNECTED) {
-                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
+                int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+                if (mBluetoothDevice == null) {
+                    mBluetoothDevice = (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+                }
+                if (mBluetoothDevice != null) {
+                    int btClass = mBluetoothDevice.getRemoteClass(address);
+                    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;
+                        }
+                    }
+                }
+
+                boolean isConnected = (mConnectedDevices.containsKey(device) &&
+                                       ((String)mConnectedDevices.get(device)).equals(address));
+
+                if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) {
+                    AudioSystem.setDeviceConnectionState(device,
                                                          AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                                          address);
-                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
-                } else if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) {
-                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
+                    mConnectedDevices.remove(device);
+                } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) {
+                    AudioSystem.setDeviceConnectionState(device,
                                                          AudioSystem.DEVICE_STATE_AVAILABLE,
                                                          address);
-                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO), address);
+                    mConnectedDevices.put( new Integer(device), address);
                 }
             } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
                 int state = intent.getIntExtra("state", 0);
@@ -1440,6 +1477,4 @@
             }
         }
     }
-
-
 }
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 1fc1024..98b55e9 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -125,7 +125,7 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::setStreamVolume(int stream, float value, void *output)
+status_t AudioSystem::setStreamVolume(int stream, float value, int output)
 {
     if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -143,7 +143,7 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::getStreamVolume(int stream, float* volume, void *output)
+status_t AudioSystem::getStreamVolume(int stream, float* volume, int output)
 {
     if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -234,7 +234,7 @@
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
     if (outputDesc == 0) {
-        LOGV("getOutputSamplingRate() no output descriptor for output %p in gOutputs", output);
+        LOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
         gLock.unlock();
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
@@ -245,7 +245,7 @@
         gLock.unlock();
     }
 
-    LOGV("getOutputSamplingRate() streamType %d, output %p, sampling rate %d", streamType, output, *samplingRate);
+    LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);
 
     return NO_ERROR;
 }
@@ -276,7 +276,7 @@
         gLock.unlock();
     }
 
-    LOGV("getOutputFrameCount() streamType %d, output %p, frameCount %d", streamType, output, *frameCount);
+    LOGV("getOutputFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount);
 
     return NO_ERROR;
 }
@@ -307,7 +307,7 @@
         gLock.unlock();
     }
 
-    LOGV("getOutputLatency() streamType %d, output %p, latency %d", streamType, output, *latency);
+    LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
 
     return NO_ERROR;
 }
@@ -348,13 +348,12 @@
     LOGW("AudioFlinger server died!");
 }
 
-void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, void *param1, void *param2) {
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
     LOGV("ioConfigChanged() event %d", event);
-    audio_io_handle_t ioHandle = (audio_io_handle_t)param1;
     OutputDescriptor *desc;
     uint32_t stream;
 
-    if (param1 == 0) return;
+    if (ioHandle == 0) return;
 
     Mutex::Autolock _l(AudioSystem::gLock);
 
@@ -362,14 +361,14 @@
     case STREAM_CONFIG_CHANGED:
         if (param2 == 0) break;
         stream = *(uint32_t *)param2;
-        LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %p", stream, ioHandle);
+        LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
         if (gStreamOutputMap.indexOfKey(stream) >= 0) {
             gStreamOutputMap.replaceValueFor(stream, ioHandle);
         }
         break;
     case OUTPUT_OPENED: {
         if (gOutputs.indexOfKey(ioHandle) >= 0) {
-            LOGV("ioConfigChanged() opening already existing output! %p", ioHandle);
+            LOGV("ioConfigChanged() opening already existing output! %d", ioHandle);
             break;
         }
         if (param2 == 0) break;
@@ -382,10 +381,10 @@
         } break;
     case OUTPUT_CLOSED: {
         if (gOutputs.indexOfKey(ioHandle) < 0) {
-            LOGW("ioConfigChanged() closing unknow output! %p", ioHandle);
+            LOGW("ioConfigChanged() closing unknow output! %d", ioHandle);
             break;
         }
-        LOGV("ioConfigChanged() output %p closed", ioHandle);
+        LOGV("ioConfigChanged() output %d closed", ioHandle);
 
         gOutputs.removeItem(ioHandle);
         for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) {
@@ -398,13 +397,13 @@
     case OUTPUT_CONFIG_CHANGED: {
         int index = gOutputs.indexOfKey(ioHandle);
         if (index < 0) {
-            LOGW("ioConfigChanged() modifying unknow output! %p", ioHandle);
+            LOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
             break;
         }
         if (param2 == 0) break;
         desc = (OutputDescriptor *)param2;
 
-        LOGV("ioConfigChanged() new config for output %p samplingRate %d, format %d channels %d frameCount %d latency %d",
+        LOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d",
                 ioHandle, desc->samplingRate, desc->format,
                 desc->channels, desc->frameCount, desc->latency);
         OutputDescriptor *outputDesc = gOutputs.valueAt(index);
@@ -524,15 +523,15 @@
                                     uint32_t channels,
                                     output_flags flags)
 {
-    audio_io_handle_t output = NULL;
+    audio_io_handle_t output = 0;
     if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
         Mutex::Autolock _l(gLock);
         output = AudioSystem::gStreamOutputMap.valueFor(stream);
-        LOGV_IF((output != NULL), "getOutput() read %p from cache for stream %d", output, stream);
+        LOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream);
     }
-    if (output == NULL) {
+    if (output == 0) {
         const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-        if (aps == 0) return NULL;
+        if (aps == 0) return 0;
         output = aps->getOutput(stream, samplingRate, format, channels, flags);
         if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
             Mutex::Autolock _l(gLock);
@@ -570,7 +569,7 @@
                                     audio_in_acoustics acoustics)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-    if (aps == 0) return NULL;
+    if (aps == 0) return 0;
     return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
 }
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index b147d25..4b9d272 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -744,7 +744,7 @@
 
         size_t toWrite;
 
-        if (mFormat == AudioSystem::PCM_8_BIT) {
+        if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
             // Divide capacity by 2 to take expansion into account
             toWrite = audioBuffer.size>>1;
             // 8 to 16 bit conversion
@@ -753,7 +753,7 @@
             while(count--) {
                 *dst++ = (int16_t)(*src++^0x80) << 8;
             }
-        }else {
+        } else {
             toWrite = audioBuffer.size;
             memcpy(audioBuffer.i8, src, toWrite);
             src += toWrite;
@@ -840,7 +840,7 @@
         // Divide buffer size by 2 to take into account the expansion
         // due to 8 to 16 bit conversion: the callback must fill only half
         // of the destination buffer
-        if (mFormat == AudioSystem::PCM_8_BIT) {
+        if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
             audioBuffer.size >>= 1;
         }
 
@@ -859,7 +859,7 @@
         }
         if (writtenSize > reqSize) writtenSize = reqSize;
 
-        if (mFormat == AudioSystem::PCM_8_BIT) {
+        if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
             // 8 to 16 bit conversion
             const int8_t *src = audioBuffer.i8 + writtenSize-1;
             int count = writtenSize;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 9385367..fc39a46 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -79,7 +79,7 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                void *output,
+                                int output,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -92,7 +92,7 @@
         data.writeInt32(frameCount);
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("createTrack error: %s", strerror(-lStatus));
@@ -106,7 +106,7 @@
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                void *input,
+                                int input,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
@@ -117,7 +117,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(pid);
-        data.write(&input, sizeof(void *));
+        data.writeInt32(input);
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelCount);
@@ -131,47 +131,47 @@
         return interface_cast<IAudioRecord>(reply.readStrongBinder());
     }
 
-    virtual uint32_t sampleRate(void *output) const
+    virtual uint32_t sampleRate(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(SAMPLE_RATE, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int channelCount(void *output) const
+    virtual int channelCount(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(CHANNEL_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int format(void *output) const
+    virtual int format(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(FORMAT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual size_t frameCount(void *output) const
+    virtual size_t frameCount(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(FRAME_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual uint32_t latency(void *output) const
+    virtual uint32_t latency(int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(LATENCY, data, &reply);
         return reply.readInt32();
     }
@@ -210,13 +210,13 @@
         return reply.readInt32();
     }
 
-    virtual status_t setStreamVolume(int stream, float value, void *output)
+    virtual status_t setStreamVolume(int stream, float value, int output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(stream);
         data.writeFloat(value);
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(SET_STREAM_VOLUME, data, &reply);
         return reply.readInt32();
     }
@@ -231,12 +231,12 @@
         return reply.readInt32();
     }
 
-    virtual float streamVolume(int stream, void *output) const
+    virtual float streamVolume(int stream, int output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(stream);
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(STREAM_VOLUME, data, &reply);
         return reply.readFloat();
     }
@@ -284,21 +284,21 @@
         return reply.readInt32();
     }
 
-    virtual status_t setParameters(void *ioHandle, const String8& keyValuePairs)
+    virtual status_t setParameters(int ioHandle, const String8& keyValuePairs)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&ioHandle, sizeof(void *));
+        data.writeInt32(ioHandle);
         data.writeString8(keyValuePairs);
         remote()->transact(SET_PARAMETERS, data, &reply);
         return reply.readInt32();
     }
 
-    virtual String8 getParameters(void *ioHandle, const String8& keys)
+    virtual String8 getParameters(int ioHandle, const String8& keys)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&ioHandle, sizeof(void *));
+        data.writeInt32(ioHandle);
         data.writeString8(keys);
         remote()->transact(GET_PARAMETERS, data, &reply);
         return reply.readString8();
@@ -323,7 +323,7 @@
         return reply.readInt32();
     }
 
-    virtual void *openOutput(uint32_t *pDevices,
+    virtual int openOutput(uint32_t *pDevices,
                             uint32_t *pSamplingRate,
                             uint32_t *pFormat,
                             uint32_t *pChannels,
@@ -345,8 +345,7 @@
         data.writeInt32(latency);
         data.writeInt32(flags);
         remote()->transact(OPEN_OUTPUT, data, &reply);
-        void *output;
-        reply.read(&output, sizeof(void *));
+        int  output = reply.readInt32();
         LOGV("openOutput() returned output, %p", output);
         devices = reply.readInt32();
         if (pDevices) *pDevices = devices;
@@ -361,50 +360,48 @@
         return output;
     }
 
-    virtual void *openDuplicateOutput(void *output1, void *output2)
+    virtual int openDuplicateOutput(int output1, int output2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output1, sizeof(void *));
-        data.write(&output2, sizeof(void *));
+        data.writeInt32(output1);
+        data.writeInt32(output2);
         remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
-        void *output;
-        reply.read(&output, sizeof(void *));
-        return output;
+        return reply.readInt32();
     }
 
-    virtual status_t closeOutput(void *output)
+    virtual status_t closeOutput(int output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(CLOSE_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual status_t suspendOutput(void *output)
+    virtual status_t suspendOutput(int output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(SUSPEND_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual status_t restoreOutput(void *output)
+    virtual status_t restoreOutput(int output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(RESTORE_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual void *openInput(uint32_t *pDevices,
-                                        uint32_t *pSamplingRate,
-                                        uint32_t *pFormat,
-                                        uint32_t *pChannels,
-                                        uint32_t acoustics)
+    virtual int openInput(uint32_t *pDevices,
+                            uint32_t *pSamplingRate,
+                            uint32_t *pFormat,
+                            uint32_t *pChannels,
+                            uint32_t acoustics)
     {
         Parcel data, reply;
         uint32_t devices = pDevices ? *pDevices : 0;
@@ -419,8 +416,7 @@
         data.writeInt32(channels);
         data.writeInt32(acoustics);
         remote()->transact(OPEN_INPUT, data, &reply);
-        void *input;
-        reply.read(&input, sizeof(void *));
+        int input = reply.readInt32();
         devices = reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
@@ -432,21 +428,21 @@
         return input;
     }
 
-    virtual status_t closeInput(void *input)
+    virtual status_t closeInput(int input)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.write(&input, sizeof(void *));
+        data.writeInt32(input);
         remote()->transact(CLOSE_INPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual status_t setStreamOutput(uint32_t stream, void *output)
+    virtual status_t setStreamOutput(uint32_t stream, int output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(stream);
-        data.write(&output, sizeof(void *));
+        data.writeInt32(output);
         remote()->transact(SET_STREAM_OUTPUT, data, &reply);
         return reply.readInt32();
     }
@@ -470,8 +466,7 @@
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
-            void *output;
-            data.read(&output, sizeof(void *));
+            int output = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     streamType, sampleRate, format,
@@ -483,8 +478,7 @@
         case OPEN_RECORD: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             pid_t pid = data.readInt32();
-            void *input;
-            data.read(&input, sizeof(void *));
+            int input = data.readInt32();
             uint32_t sampleRate = data.readInt32();
             int format = data.readInt32();
             int channelCount = data.readInt32();
@@ -499,37 +493,27 @@
         } break;
         case SAMPLE_RATE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32( sampleRate(output) );
+            reply->writeInt32( sampleRate(data.readInt32()) );
             return NO_ERROR;
         } break;
         case CHANNEL_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32( channelCount(output) );
+            reply->writeInt32( channelCount(data.readInt32()) );
             return NO_ERROR;
         } break;
         case FORMAT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32( format(output) );
+            reply->writeInt32( format(data.readInt32()) );
             return NO_ERROR;
         } break;
         case FRAME_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32( frameCount(output) );
+            reply->writeInt32( frameCount(data.readInt32()) );
             return NO_ERROR;
         } break;
         case LATENCY: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32( latency(output) );
+            reply->writeInt32( latency(data.readInt32()) );
             return NO_ERROR;
         } break;
          case SET_MASTER_VOLUME: {
@@ -556,8 +540,7 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
             float volume = data.readFloat();
-            void *output;
-            data.read(&output, sizeof(void *));
+            int output = data.readInt32();
             reply->writeInt32( setStreamVolume(stream, volume, output) );
             return NO_ERROR;
         } break;
@@ -570,8 +553,7 @@
         case STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
-            void *output;
-            data.read(&output, sizeof(void *));
+            int output = data.readInt32();
             reply->writeFloat( streamVolume(stream, output) );
             return NO_ERROR;
         } break;
@@ -605,16 +587,14 @@
         } break;
         case SET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *ioHandle;
-            data.read(&ioHandle, sizeof(void *));
+            int ioHandle = data.readInt32();
             String8 keyValuePairs(data.readString8());
             reply->writeInt32(setParameters(ioHandle, keyValuePairs));
             return NO_ERROR;
          } break;
         case GET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *ioHandle;
-            data.read(&ioHandle, sizeof(void *));
+            int ioHandle = data.readInt32();
             String8 keys(data.readString8());
             reply->writeString8(getParameters(ioHandle, keys));
             return NO_ERROR;
@@ -642,14 +622,14 @@
             uint32_t channels = data.readInt32();
             uint32_t latency = data.readInt32();
             uint32_t flags = data.readInt32();
-            void *output = openOutput(&devices,
+            int output = openOutput(&devices,
                                      &samplingRate,
                                      &format,
                                      &channels,
                                      &latency,
                                      flags);
             LOGV("OPEN_OUTPUT output, %p", output);
-            reply->write(&output, sizeof(void *));
+            reply->writeInt32(output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
@@ -659,33 +639,24 @@
         } break;
         case OPEN_DUPLICATE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output1;
-            void *output2;
-            data.read(&output1, sizeof(void *));
-            data.read(&output2, sizeof(void *));
-            void *output = openDuplicateOutput(output1, output2);
-            reply->write(&output, sizeof(void *));
+            int output1 = data.readInt32();
+            int output2 = data.readInt32();
+            reply->writeInt32(openDuplicateOutput(output1, output2));
             return NO_ERROR;
         } break;
         case CLOSE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32(closeOutput(output));
+            reply->writeInt32(closeOutput(data.readInt32()));
             return NO_ERROR;
         } break;
         case SUSPEND_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32(suspendOutput(output));
+            reply->writeInt32(suspendOutput(data.readInt32()));
             return NO_ERROR;
         } break;
         case RESTORE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
-            data.read(&output, sizeof(void *));
-            reply->writeInt32(restoreOutput(output));
+            reply->writeInt32(restoreOutput(data.readInt32()));
             return NO_ERROR;
         } break;
         case OPEN_INPUT: {
@@ -696,12 +667,12 @@
             uint32_t channels = data.readInt32();
             uint32_t acoutics = data.readInt32();
 
-            void *input = openInput(&devices,
+            int input = openInput(&devices,
                                      &samplingRate,
                                      &format,
                                      &channels,
                                      acoutics);
-            reply->write(&input, sizeof(void *));
+            reply->writeInt32(input);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
@@ -710,16 +681,13 @@
         } break;
         case CLOSE_INPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *input;
-            data.read(&input, sizeof(void *));
-            reply->writeInt32(closeInput(input));
+            reply->writeInt32(closeInput(data.readInt32()));
             return NO_ERROR;
         } break;
         case SET_STREAM_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            void *output;
             uint32_t stream = data.readInt32();
-            data.read(&output, sizeof(void *));
+            int output = data.readInt32();
             reply->writeInt32(setStreamOutput(stream, output));
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index eaae977..3900de4 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -39,12 +39,12 @@
     {
     }
 
-    void ioConfigChanged(int event, void *param1, void *param2)
+    void ioConfigChanged(int event, int ioHandle, void *param2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
         data.writeInt32(event);
-        data.write(&param1, sizeof(void *));
+        data.writeInt32(ioHandle);
         if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
             uint32_t stream = *(uint32_t *)param2;
             LOGV("ioConfigChanged stream %d", stream);
@@ -72,11 +72,10 @@
     case IO_CONFIG_CHANGED: {
             CHECK_INTERFACE(IAudioFlingerClient, data, reply);
             int event = data.readInt32();
-            void *param1;
+            int ioHandle = data.readInt32();
             void *param2 = 0;
             AudioSystem::OutputDescriptor desc;
             uint32_t stream;
-            data.read(&param1, sizeof(void *));
             if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
                 stream = data.readInt32();
                 param2 = &stream;
@@ -89,7 +88,7 @@
                 desc.latency = data.readInt32();
                 param2 = &desc;
             }
-            ioConfigChanged(event, param1, param2);
+            ioConfigChanged(event, ioHandle, param2);
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 0d8a329..18dd173 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -134,16 +134,14 @@
         data.writeInt32(channels);
         data.writeInt32(static_cast <uint32_t>(flags));
         remote()->transact(GET_OUTPUT, data, &reply);
-        audio_io_handle_t output;
-        reply.read(&output, sizeof(audio_io_handle_t));
-        return output;
+        return static_cast <audio_io_handle_t> (reply.readInt32());
     }
 
     virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&output, sizeof(audio_io_handle_t));
+        data.writeInt32(output);
         data.writeInt32(stream);
         remote()->transact(START_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
@@ -153,7 +151,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&output, sizeof(audio_io_handle_t));
+        data.writeInt32(output);
         data.writeInt32(stream);
         remote()->transact(STOP_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
@@ -163,7 +161,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&output, sizeof(audio_io_handle_t));
+        data.writeInt32(output);
         remote()->transact(RELEASE_OUTPUT, data, &reply);
     }
 
@@ -182,16 +180,14 @@
         data.writeInt32(channels);
         data.writeInt32(static_cast <uint32_t>(acoustics));
         remote()->transact(GET_INPUT, data, &reply);
-        audio_io_handle_t input;
-        reply.read(&input, sizeof(audio_io_handle_t));
-        return input;
+        return static_cast <audio_io_handle_t> (reply.readInt32());
     }
 
     virtual status_t startInput(audio_io_handle_t input)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&input, sizeof(audio_io_handle_t));
+        data.writeInt32(input);
         remote()->transact(START_INPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
@@ -200,7 +196,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&input, sizeof(audio_io_handle_t));
+        data.writeInt32(input);
         remote()->transact(STOP_INPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
@@ -209,7 +205,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.write(&input, sizeof(audio_io_handle_t));
+        data.writeInt32(input);
         remote()->transact(RELEASE_INPUT, data, &reply);
     }
 
@@ -316,14 +312,13 @@
                                                  format,
                                                  channels,
                                                  flags);
-            reply->write(&output, sizeof(audio_io_handle_t));
+            reply->writeInt32(static_cast <int>(output));
             return NO_ERROR;
         } break;
 
         case START_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output;
-            data.read(&output, sizeof(audio_io_handle_t));
+            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
             uint32_t stream = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
             return NO_ERROR;
@@ -331,8 +326,7 @@
 
         case STOP_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output;
-            data.read(&output, sizeof(audio_io_handle_t));
+            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
             uint32_t stream = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
             return NO_ERROR;
@@ -340,8 +334,7 @@
 
         case RELEASE_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output;
-            data.read(&output, sizeof(audio_io_handle_t));
+            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
             releaseOutput(output);
             return NO_ERROR;
         } break;
@@ -358,30 +351,27 @@
                                                format,
                                                channels,
                                                acoustics);
-            reply->write(&input, sizeof(audio_io_handle_t));
+            reply->writeInt32(static_cast <int>(input));
             return NO_ERROR;
         } break;
 
         case START_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input;
-            data.read(&input, sizeof(audio_io_handle_t));
+            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
             reply->writeInt32(static_cast <uint32_t>(startInput(input)));
             return NO_ERROR;
         } break;
 
         case STOP_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input;
-            data.read(&input, sizeof(audio_io_handle_t));
+            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
             reply->writeInt32(static_cast <uint32_t>(stopInput(input)));
             return NO_ERROR;
         } break;
 
         case RELEASE_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input;
-            data.read(&input, sizeof(audio_io_handle_t));
+            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
             releaseInput(input);
             return NO_ERROR;
         } break;
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f74ef3a..84f858c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,49 +7,41 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-    MediaRecorderClient.cpp \
-    MediaPlayerService.cpp \
+    MediaRecorderClient.cpp     \
+    MediaPlayerService.cpp      \
     MetadataRetrieverClient.cpp \
-    TestPlayerStub.cpp \
-    VorbisPlayer.cpp \
+    StagefrightPlayer.cpp       \
+    TestPlayerStub.cpp          \
+    VorbisPlayer.cpp            \
     MidiFile.cpp
 
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
 LOCAL_LDLIBS += -ldl -lpthread
 endif
 
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-	libbinder \
-    libvorbisidec \
-    libsonivox \
-    libopencore_player \
-    libopencore_author \
-    libmedia \
-    libandroid_runtime
+LOCAL_SHARED_LIBRARIES :=     \
+	libcutils             \
+	libutils              \
+	libbinder             \
+	libvorbisidec         \
+	libsonivox            \
+	libopencore_player    \
+	libopencore_author    \
+	libmedia              \
+	libandroid_runtime    \
+	libstagefright        \
+	libstagefright_omx
 
 ifneq ($(TARGET_SIMULATOR),true)
 LOCAL_SHARED_LIBRARIES += libdl
 endif
 
-LOCAL_C_INCLUDES := external/tremor/Tremor \
-	$(call include-path-for, graphics corecg) \
-	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+LOCAL_C_INCLUDES := external/tremor/Tremor                              \
+	$(call include-path-for, graphics corecg)                       \
+	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+	$(TOP)/frameworks/base/media/libstagefright/omx
 
 LOCAL_MODULE:= libmediaplayerservice
 
-ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
-    LOCAL_SRC_FILES += StagefrightPlayer.cpp
-
-    LOCAL_SHARED_LIBRARIES += \
-	libstagefright        \
-	libstagefright_omx
-
-    LOCAL_C_INCLUDES += $(TOP)/frameworks/base/media/libstagefright/omx
-
-    LOCAL_CFLAGS += -DBUILD_WITH_STAGEFRIGHT -DUSE_STAGEFRIGHT
-endif
-
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 95d61cd..eeb4e49 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -58,20 +58,9 @@
 #include "VorbisPlayer.h"
 #include <media/PVPlayer.h>
 #include "TestPlayerStub.h"
-
-//#undef USE_STAGEFRIGHT
-
-#if USE_STAGEFRIGHT
 #include "StagefrightPlayer.h"
-#endif
 
-#ifdef BUILD_WITH_STAGEFRIGHT
 #include <OMX.h>
-#else
-#include <media/IOMX.h>
-#endif
-
-
 
 /* desktop Linux needs a little help with gettid() */
 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -199,10 +188,6 @@
     const player_type playertype;
 } extmap;
 extmap FILE_EXTS [] =  {
-#if USE_STAGEFRIGHT
-        {".mp4", STAGEFRIGHT_PLAYER},
-        {".3gp", STAGEFRIGHT_PLAYER},
-#endif
         {".mid", SONIVOX_PLAYER},
         {".midi", SONIVOX_PLAYER},
         {".smf", SONIVOX_PLAYER},
@@ -289,11 +274,7 @@
 }
 
 sp<IOMX> MediaPlayerService::createOMX() {
-#ifdef BUILD_WITH_STAGEFRIGHT
     return new OMX;
-#else
-    return NULL;
-#endif
 }
 
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
@@ -620,6 +601,16 @@
     IPCThreadState::self()->flushCommands();
 }
 
+static player_type getDefaultPlayerType() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.enable-player", value, NULL)
+        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        return STAGEFRIGHT_PLAYER;
+    }
+
+    return PV_PLAYER;
+}
+
 static player_type getPlayerType(int fd, int64_t offset, int64_t length)
 {
     char buf[20];
@@ -650,12 +641,7 @@
         EAS_Shutdown(easdata);
     }
 
-#if USE_STAGEFRIGHT
-    return STAGEFRIGHT_PLAYER;
-#endif
-
-    // Fall through to PV
-    return PV_PLAYER;
+    return getDefaultPlayerType();
 }
 
 static player_type getPlayerType(const char* url)
@@ -676,12 +662,7 @@
         }
     }
 
-#if USE_STAGEFRIGHT
-    return STAGEFRIGHT_PLAYER;
-#endif
-
-    // Fall through to PV
-    return PV_PLAYER;
+    return getDefaultPlayerType();
 }
 
 static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
@@ -703,17 +684,10 @@
             LOGV(" create VorbisPlayer");
             p = new VorbisPlayer();
             break;
-#if USE_STAGEFRIGHT
         case STAGEFRIGHT_PLAYER:
             LOGV(" create StagefrightPlayer");
             p = new StagefrightPlayer;
             break;
-#else
-        case STAGEFRIGHT_PLAYER:
-            LOG_ALWAYS_FATAL(
-                    "Should not be here, stagefright player not enabled.");
-            break;
-#endif
         case TEST_PLAYER:
             LOGV("Create Test Player stub");
             p = new TestPlayerStub();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0a44762..00ba1ac 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -1,5 +1,3 @@
-ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
-
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -54,4 +52,3 @@
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 2e564e9..ecd3b2e 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -1,5 +1,3 @@
-ifeq ($(BUILD_WITH_STAGEFRIGHT),true)
-
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -27,5 +25,3 @@
 LOCAL_MODULE:= libstagefright_omx
 
 include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index d8867d3..01c0920 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -310,7 +310,8 @@
     public boolean validateMemoryResult (int startPid, int startMemory, Writer output) throws Exception {
         mEndPid = getMediaserverPid();
         mEndMemory = getMediaserverVsize();
-
+        Log.v(TAG, "End Memory " + mEndMemory);
+        output.write("End Memory :" + mEndMemory + "\n");
         //Write the total memory different into the output file
         output.write("The total diff = " + (mEndMemory - startMemory));
         output.write("\n\n");
@@ -337,13 +338,17 @@
     public void testH263VideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true));
         output.write("H263 Video Playback Only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263);
+            if (i == 0) {
+                mStartMemory = getMediaserverVsize();
+                output.write("Start memory : " + mStartMemory + "\n");
+                Log.v(TAG, "first mem : " + mStartMemory);
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -357,13 +362,16 @@
     public void testH264VideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true));
         output.write("H264 Video Playback only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_H264_AMR);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -377,13 +385,16 @@
     public void testWMVVideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File wmvMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut, true));
         output.write("WMV video playback only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_WMV);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -397,7 +408,6 @@
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true));
@@ -405,6 +415,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -418,7 +432,6 @@
     public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true));
@@ -426,6 +439,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -440,7 +457,6 @@
     public void testRecordVidedAudioMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true));
@@ -448,6 +464,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -461,13 +481,16 @@
     public void testRecordAudioOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true));
         output.write("Audio record only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressAudioRecord(MediaNames.RECORDER_OUTPUT);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2b36904..e53171f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -122,7 +122,7 @@
     public void onRestore(BackupDataInput data, int appVersionCode,
             ParcelFileDescriptor newState) throws IOException {
 
-        enableWifi(false);
+
         enableBluetooth(false);
 
         while (data.readNextHeader()) {
@@ -134,11 +134,15 @@
             } else if (KEY_SECURE.equals(key)) {
                 restoreSettings(data, Settings.Secure.CONTENT_URI);
             } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+                int retainedWifiState = enableWifi(false);
                 restoreFile(FILE_WIFI_SUPPLICANT, data);
                 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                         FileUtils.S_IRUSR | FileUtils.S_IWUSR |
                         FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                         Process.myUid(), Process.WIFI_UID);
+                // retain the previous WIFI state.
+                enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
+                        retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
             } else if (KEY_SYNC.equals(key)) {
                 mSettingsHelper.setSyncProviders(data);
             } else if (KEY_LOCALE.equals(key)) {
@@ -257,7 +261,7 @@
     }
 
     /**
-     * Given a cursor sorted by key name and a set of keys sorted by name, 
+     * Given a cursor sorted by key name and a set of keys sorted by name,
      * extract the required keys and values and write them to a byte array.
      * @param sortedCursor
      * @param sortedKeys
@@ -373,11 +377,14 @@
         return result;
     }
 
-    private void enableWifi(boolean enable) {
+    private int enableWifi(boolean enable) {
         WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
         if (wfm != null) {
+            int state = wfm.getWifiState();
             wfm.setWifiEnabled(enable);
+            return state;
         }
+        return WifiManager.WIFI_STATE_UNKNOWN;
     }
 
     private void enableBluetooth(boolean enable) {