Merge "add mouse up/down/click support in DumpRenderTree" into gingerbread
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 9a55a6f..1d1b4dc 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1248,8 +1248,9 @@
         
         case IS_USER_A_MONKEY_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            reply.writeInt(isUserAMonkey() ? 1 : 0);
+            boolean areThey = isUserAMonkey();
             reply.writeNoException();
+            reply.writeInt(areThey ? 1 : 0);
             return true;
         }
         
@@ -1263,8 +1264,9 @@
         case IS_IMMERSIVE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            reply.writeInt(isImmersive(token) ? 1 : 0);
+            boolean isit = isImmersive(token);
             reply.writeNoException();
+            reply.writeInt(isit ? 1 : 0);
             return true;
         }
 
@@ -1279,8 +1281,9 @@
         
         case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            reply.writeInt(isTopActivityImmersive() ? 1 : 0);
+            boolean isit = isTopActivityImmersive();
             reply.writeNoException();
+            reply.writeInt(isit ? 1 : 0);
             return true;
         }
 
@@ -1295,6 +1298,40 @@
             return true;
         }
 
+        case NEW_URI_PERMISSION_OWNER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String name = data.readString();
+            IBinder perm = newUriPermissionOwner(name);
+            reply.writeNoException();
+            reply.writeStrongBinder(perm);
+            return true;
+        }
+
+        case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder owner = data.readStrongBinder();
+            int fromUid = data.readInt();
+            String targetPkg = data.readString();
+            Uri uri = Uri.CREATOR.createFromParcel(data);
+            int mode = data.readInt();
+            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode);
+            reply.writeNoException();
+            return true;
+        }
+
+        case REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder owner = data.readStrongBinder();
+            Uri uri = null;
+            if (data.readInt() != 0) {
+                Uri.CREATOR.createFromParcel(data);
+            }
+            int mode = data.readInt();
+            revokeUriPermissionFromOwner(owner, uri, mode);
+            reply.writeNoException();
+            return true;
+        }
+
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2841,8 +2878,8 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         mRemote.transact(IS_IMMERSIVE_TRANSACTION, data, reply, 0);
-        boolean res = reply.readInt() == 1;
         reply.readException();
+        boolean res = reply.readInt() == 1;
         data.recycle();
         reply.recycle();
         return res;
@@ -2854,8 +2891,8 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         mRemote.transact(IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION, data, reply, 0);
-        boolean res = reply.readInt() == 1;
         reply.readException();
+        boolean res = reply.readInt() == 1;
         data.recycle();
         reply.recycle();
         return res;
@@ -2875,6 +2912,55 @@
         data.recycle();
         reply.recycle();
     }
+
+    public IBinder newUriPermissionOwner(String name)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(name);
+        mRemote.transact(NEW_URI_PERMISSION_OWNER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        IBinder res = reply.readStrongBinder();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
+    public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
+            Uri uri, int mode) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(owner);
+        data.writeInt(fromUid);
+        data.writeString(targetPkg);
+        uri.writeToParcel(data, 0);
+        data.writeInt(mode);
+        mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
+            int mode) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(owner);
+        if (uri != null) {
+            data.writeInt(1);
+            uri.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        data.writeInt(mode);
+        mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 416f289..664cf18 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -318,6 +318,12 @@
     public void crashApplication(int uid, int initialPid, String packageName,
             String message) throws RemoteException;
     
+    public IBinder newUriPermissionOwner(String name) throws RemoteException;
+    public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
+            Uri uri, int mode) throws RemoteException;
+    public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
+            int mode) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -524,4 +530,7 @@
     int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
     int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
     int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
+    int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
+    int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115;
+    int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116;
 }
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index e5985c1..194c013 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -348,6 +348,7 @@
     public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
         synchronized (mConstructorArgs) {
             final AttributeSet attrs = Xml.asAttributeSet(parser);
+            Context lastContext = (Context)mConstructorArgs[0];
             mConstructorArgs[0] = mContext;
             View result = root;
 
@@ -432,6 +433,10 @@
                         + ": " + e.getMessage());
                 ex.initCause(e);
                 throw ex;
+            } finally {
+                // Don't retain static reference on context.
+                mConstructorArgs[0] = lastContext;
+                mConstructorArgs[1] = null;
             }
 
             return result;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 402443c..7b6991f 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1138,22 +1138,24 @@
 
         final View captureView = findView(root, parameter);
         Bitmap b = performViewCapture(captureView, false);
-       
-        if (b != null) {
-            BufferedOutputStream out = null;
-            try {
-                out = new BufferedOutputStream(clientStream, 32 * 1024);
-                b.compress(Bitmap.CompressFormat.PNG, 100, out);
-                out.flush();
-            } finally {
-                if (out != null) {
-                    out.close();
-                }
-                b.recycle();
-            }
-        } else {
+
+        if (b == null) {
             Log.w("View", "Failed to create capture bitmap!");
-            clientStream.close();
+            // Send an empty one so that it doesn't get stuck waiting for
+            // something.
+            b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        }
+
+        BufferedOutputStream out = null;
+        try {
+            out = new BufferedOutputStream(clientStream, 32 * 1024);
+            b.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+            b.recycle();
         }
     }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index e36d9fe..a15b84e 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1569,9 +1569,9 @@
                 // The idea here is to avoid having two or more samples with the
                 // same timestamp in the output file.
                 if (mTimeScale >= 1000000LL) {
-                    timestampUs += 1;
+                    timestampUs = lastTimestampUs + 1;
                 } else {
-                    timestampUs += (1000000LL + (mTimeScale >> 1)) / mTimeScale;
+                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
                 }
 #endif
             }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index c7f461e..46135ff 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -27,7 +27,9 @@
 import com.android.mediaframeworktest.functional.MediaAudioManagerTest;
 import com.android.mediaframeworktest.functional.MediaAudioEffectTest;
 import com.android.mediaframeworktest.functional.MediaBassBoostTest;
+import com.android.mediaframeworktest.functional.MediaEnvReverbTest;
 import com.android.mediaframeworktest.functional.MediaEqualizerTest;
+import com.android.mediaframeworktest.functional.MediaPresetReverbTest;
 import com.android.mediaframeworktest.functional.MediaVirtualizerTest;
 import com.android.mediaframeworktest.functional.MediaVisualizerTest;
 import junit.framework.TestSuite;
@@ -62,7 +64,9 @@
         suite.addTestSuite(MediaAudioManagerTest.class);
         suite.addTestSuite(MediaAudioEffectTest.class);
         suite.addTestSuite(MediaBassBoostTest.class);
+        suite.addTestSuite(MediaEnvReverbTest.class);
         suite.addTestSuite(MediaEqualizerTest.class);
+        suite.addTestSuite(MediaPresetReverbTest.class);
         suite.addTestSuite(MediaVirtualizerTest.class);
         suite.addTestSuite(MediaVisualizerTest.class);
         return suite;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java
new file mode 100644
index 0000000..d339e06
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/EnergyProbe.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import android.media.Visualizer;
+import android.util.Log;
+
+/**
+ * The EnergyProbe class provides audio signal energy measurements based on the FFT returned
+ * by the Visualizer class. The measure is qualitative and not quantitative in that the returned
+ * value has no unit and is just proportional to the amount of energy present around the
+ * specified frequency.
+ */
+
+public class EnergyProbe {
+    private String TAG = "EnergyProbe";
+
+    private static int CAPTURE_SIZE = 1024;
+    private static int MEASURE_COUNT = 5;
+    private static int AVERAGE_COUNT = 3;
+
+    private Visualizer mVisualizer = null;
+    private int mMaxFrequency = 0;
+    private int mCapturePeriodMs;
+    private byte[] mFft = new byte[CAPTURE_SIZE];
+
+    public EnergyProbe(int session) {
+        try {
+            mVisualizer = new Visualizer(session);
+            if (mVisualizer != null) {
+                mVisualizer.setCaptureSize(CAPTURE_SIZE);
+                mMaxFrequency = mVisualizer.getSamplingRate() / 2000;
+                mCapturePeriodMs = 1000000 / mVisualizer.getMaxCaptureRate();
+            }
+        } catch (UnsupportedOperationException e) {
+            Log.e(TAG, "Error creating visualizer");
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Error configuring visualizer");
+        }
+    }
+
+    public int capture(int freq) throws InterruptedException {
+        int energy = 0;
+        int count = 0;
+
+        if (freq > mMaxFrequency) {
+            return 0;
+        }
+
+        if (mVisualizer != null) {
+            try {
+                mVisualizer.setEnabled(true);
+                for (int i = 0; i < MEASURE_COUNT; i++) {
+                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
+                        if (freq == mMaxFrequency) {
+                            energy += (int)mFft[0] * (int)mFft[0];
+                        } else {
+                            int bin = 2 * (freq * CAPTURE_SIZE / mMaxFrequency / 2);
+                            if (bin < 2) bin = 2;
+                            int tmp = 0;
+                            int j;
+                            for (j = 0;
+                                 (j < AVERAGE_COUNT) && ((bin + 2 * j) < CAPTURE_SIZE);
+                                 j++) {
+                                tmp += (int)mFft[bin + 2 * j] * (int)mFft[bin + 2 * j] +
+                                       (int)mFft[bin + 2 * j + 1] * (int)mFft[bin + 2 * j + 1];
+                            }
+                            // j is always != 0
+                            energy += tmp/j;
+                        }
+                        count++;
+                    }
+                    Thread.sleep(mCapturePeriodMs);
+                }
+                mVisualizer.setEnabled(false);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Error capturing audio");
+            }
+        }
+        if (count == 0) {
+            return 0;
+        }
+        return energy/count;
+    }
+
+    public void release() {
+        if (mVisualizer != null) {
+            mVisualizer.release();
+            mVisualizer = null;
+        }
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java
index 8a68c5e..aca729e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java
@@ -43,7 +43,7 @@
  */
 public class MediaBassBoostTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
     private String TAG = "MediaBassBoostTest";
-    private final static int MIN_ENERGY_RATIO_2 = 4;
+    private final static int MIN_ENERGY_RATIO_2 = 3;
     private final static short TEST_STRENGTH = 500;
 
     private BassBoost mBassBoost = null;
@@ -259,52 +259,6 @@
     // private methods
     //----------------------------------
 
-    private class EnergyProbe {
-        Visualizer mVisualizer = null;
-        private byte[] mFft = new byte[1024];
-
-        public EnergyProbe(int session) {
-            mVisualizer = new Visualizer(session);
-            mVisualizer.setCaptureSize(1024);
-        }
-
-        public int capture(int freq) throws InterruptedException {
-            int energy = 0;
-            int count = 0;
-            if (mVisualizer != null) {
-                mVisualizer.setEnabled(true);
-                for (int i = 0; i < 10; i++) {
-                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
-                        // TODO: check speex FFT as it seems to return only the number of points
-                        // correspondong to valid part of the spectrum (< Fs).
-                        // e.g., if the number of points is 1024, it covers the frequency range
-                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
-                        int bin = freq / (22050 / 1024);
-                        int tmp = 0;
-                        for (int j = bin-2; j < bin+3; j++) {
-                            tmp += (int)mFft[j] * (int)mFft[j];
-                        }
-                        energy += tmp/5;
-                        count++;
-                    }
-                    Thread.sleep(50);
-                }
-                mVisualizer.setEnabled(false);
-            }
-            if (count == 0) {
-                return 0;
-            }
-            return energy/count;
-        }
-
-        public void release() {
-            if (mVisualizer != null) {
-                mVisualizer.release();
-                mVisualizer = null;
-            }
-        }
-    }
-
     private void getBassBoost(int session) {
          if (mBassBoost == null || session != mSession) {
              if (session != mSession && mBassBoost != null) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java
new file mode 100644
index 0000000..db0db70
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.EnvironmentalReverb;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaEnvReverbTest";
+    // allow +/- 100 millibel difference between set and get gains
+    private final static int MILLIBEL_TOLERANCE = 100;
+    // allow +/- 5% tolerance between set and get delays
+    private final static float DELAY_TOLERANCE = 1.05f;
+    // allow +/- 5% tolerance between set and get ratios
+    private final static float RATIO_TOLERANCE = 1.05f;
+
+    private EnvironmentalReverb mReverb = null;
+    private int mSession = -1;
+
+    public MediaEnvReverbTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseReverb();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // ENVIRONMENTAL REVEB TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        EnvironmentalReverb reverb = null;
+         try {
+            reverb = new EnvironmentalReverb(0, 0);
+            assertNotNull(msg + ": could not create EnvironmentalReverb", reverb);
+            try {
+                assertTrue(msg +": invalid effect ID", (reverb.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": EnvironmentalReverb not initialized");
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": EnvironmentalReverb not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (reverb != null) {
+                reverb.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test room level and room HF level
+    @LargeTest
+    public void test1_0Room() throws Exception {
+        boolean result = false;
+        String msg = "test1_0Room()";
+        getReverb(0);
+        try {
+            mReverb.setRoomLevel((short)0);
+            short level = mReverb.getRoomLevel();
+            assertTrue(msg +": got incorrect room level",
+                    (level > (0 - MILLIBEL_TOLERANCE)) &&
+                    (level < (0 + MILLIBEL_TOLERANCE)));
+
+            mReverb.setRoomHFLevel((short)-6);
+            level = mReverb.getRoomHFLevel();
+            assertTrue(msg +": got incorrect room HF level",
+                    (level > (-6 - MILLIBEL_TOLERANCE)) &&
+                    (level < (-6 + MILLIBEL_TOLERANCE)));
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test decay time and ratio
+    @LargeTest
+    public void test1_1Decay() throws Exception {
+        boolean result = false;
+        String msg = "test1_1Decay()";
+        getReverb(0);
+        try {
+            mReverb.setDecayTime(500);
+            int time = mReverb.getDecayTime();
+            assertTrue(msg +": got incorrect decay time",
+                    ((float)time > (float)(500 / DELAY_TOLERANCE)) &&
+                    ((float)time < (float)(500 * DELAY_TOLERANCE)));
+
+            mReverb.setDecayHFRatio((short)1000);
+            short ratio = mReverb.getDecayHFRatio();
+            assertTrue(msg +": got incorrect decay HF ratio",
+                    ((float)ratio > (float)(1000 / RATIO_TOLERANCE)) &&
+                    ((float)ratio < (float)(1000 * RATIO_TOLERANCE)));
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.2: test reflections
+    @LargeTest
+    public void test1_2Reflections() throws Exception {
+        // TODO: uncomment when early reflections are implemented
+//        boolean result = false;
+//        String msg = "test1_2Reflections()";
+//        getReverb(0);
+//        try {
+//            mReverb.setReflectionsLevel((short)0);
+//            short level = mReverb.getReflectionsLevel();
+//            assertTrue(msg +": got incorrect reflections level",
+//                    (level > (0 - MILLIBEL_TOLERANCE)) &&
+//                    (level < (0 + MILLIBEL_TOLERANCE)));
+//
+//            mReverb.setReflectionsDelay(30);
+//            int delay = mReverb.getReflectionsDelay();
+//            assertTrue(msg +": got incorrect reflections delay",
+//                    ((float)delay > (float)(30 / DELAY_TOLERANCE)) &&
+//                    ((float)delay < (float)(30 * DELAY_TOLERANCE)));
+//
+//            result = true;
+//        } catch (IllegalArgumentException e) {
+//            msg = msg.concat(": Bad parameter value");
+//            loge(msg, "Bad parameter value");
+//        } catch (UnsupportedOperationException e) {
+//            msg = msg.concat(": get parameter() rejected");
+//            loge(msg, "get parameter() rejected");
+//        } catch (IllegalStateException e) {
+//            msg = msg.concat("get parameter() called in wrong state");
+//            loge(msg, "get parameter() called in wrong state");
+//        } finally {
+//            releaseReverb();
+//        }
+//        assertTrue(msg, result);
+    }
+
+    //Test case 1.3: test reverb
+    @LargeTest
+    public void test1_3Reverb() throws Exception {
+        boolean result = false;
+        String msg = "test1_3Reverb()";
+        getReverb(0);
+        try {
+            mReverb.setReverbLevel((short)0);
+            short level = mReverb.getReverbLevel();
+            assertTrue(msg +": got incorrect reverb level",
+                    (level > (0 - MILLIBEL_TOLERANCE)) &&
+                    (level < (0 + MILLIBEL_TOLERANCE)));
+
+            // TODO: change delay when early reflections are implemented
+            mReverb.setReverbDelay(0);
+            int delay = mReverb.getReverbDelay();
+            assertTrue(msg +": got incorrect reverb delay", delay < 5);
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.4: test diffusion and density
+    @LargeTest
+    public void test1_4DiffusionAndDensity() throws Exception {
+        boolean result = false;
+        String msg = "test1_4DiffusionAndDensity()";
+        getReverb(0);
+        try {
+            mReverb.setDiffusion((short)500);
+            short diffusion = mReverb.getDiffusion();
+            assertTrue(msg +": got incorrect diffusion",
+                    ((float)diffusion > (float)(500 / RATIO_TOLERANCE)) &&
+                    ((float)diffusion < (float)(500 * RATIO_TOLERANCE)));
+
+            mReverb.setDensity((short)500);
+            short density = mReverb.getDensity();
+            assertTrue(msg +": got incorrect density",
+                    ((float)density > (float)(500 / RATIO_TOLERANCE)) &&
+                    ((float)density < (float)(500 * RATIO_TOLERANCE)));
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.5: test properties
+    @LargeTest
+    public void test1_5Properties() throws Exception {
+        boolean result = false;
+        String msg = "test1_5Properties()";
+        getReverb(0);
+        try {
+            EnvironmentalReverb.Settings settings = mReverb.getProperties();
+            short newRoomLevel = 0;
+            if (settings.roomLevel == 0) {
+                newRoomLevel = -1000;
+            }
+            String str = settings.toString();
+            settings = new EnvironmentalReverb.Settings(str);
+            settings.roomLevel = newRoomLevel;
+            mReverb.setProperties(settings);
+            settings = mReverb.getProperties();
+            assertTrue(msg +": setProperties failed",
+                    (settings.roomLevel > (newRoomLevel - MILLIBEL_TOLERANCE)) &&
+                    (settings.roomLevel < (newRoomLevel + MILLIBEL_TOLERANCE)));
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect action
+    //----------------------------------
+
+    //Test case 2.0: test actual auxiliary reverb influence on sound
+    @LargeTest
+    public void test2_0AuxiliarySoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_0AuxiliarySoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+        getReverb(0);
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            mp.attachAuxEffect(mReverb.getId());
+            mp.setAuxEffectSendLevel(1.0f);
+            mReverb.setRoomLevel((short)0);
+            mReverb.setReverbLevel((short)0);
+            mReverb.setDecayTime(2000);
+            mReverb.setEnabled(true);
+            mp.prepare();
+            mp.start();
+            Thread.sleep(1000);
+            mp.stop();
+            Thread.sleep(300);
+            // measure energy around 1kHz after media player was stopped for 300 ms
+            int energy1000 = probe.capture(1000);
+            assertTrue(msg + ": reverb has no effect", energy1000 > 0);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseReverb();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 2.1: test actual insert reverb influence on sound
+    @LargeTest
+    public void test2_1InsertSoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_1InsertSoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getReverb(mp.getAudioSessionId());
+            mReverb.setRoomLevel((short)0);
+            mReverb.setReverbLevel((short)0);
+            mReverb.setDecayTime(2000);
+            mReverb.setEnabled(true);
+            mp.prepare();
+            mp.start();
+            Thread.sleep(1000);
+            mp.stop();
+            Thread.sleep(300);
+            // measure energy around 1kHz after media player was stopped for 300 ms
+            int energy1000 = probe.capture(1000);
+            assertTrue(msg + ": reverb has no effect", energy1000 > 0);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseReverb();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getReverb(int session) {
+         if (mReverb == null || session != mSession) {
+             if (session != mSession && mReverb != null) {
+                 mReverb.release();
+                 mReverb = null;
+             }
+             try {
+                mReverb = new EnvironmentalReverb(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getReverb() EnvironmentalReverb not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mReverb", mReverb);
+    }
+
+    private void releaseReverb() {
+        if (mReverb != null) {
+            mReverb.release();
+            mReverb = null;
+        }
+   }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java
index e46887b..7b3945d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java
@@ -322,52 +322,6 @@
     // private methods
     //----------------------------------
 
-    private class EnergyProbe {
-        Visualizer mVisualizer = null;
-        private byte[] mFft = new byte[1024];
-
-        public EnergyProbe(int session) {
-            mVisualizer = new Visualizer(session);
-            mVisualizer.setCaptureSize(1024);
-        }
-
-        public int capture(int freq) throws InterruptedException {
-            int energy = 0;
-            int count = 0;
-            if (mVisualizer != null) {
-                mVisualizer.setEnabled(true);
-                for (int i = 0; i < 10; i++) {
-                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
-                        // TODO: check speex FFT as it seems to return only the number of points
-                        // correspondong to valid part of the spectrum (< Fs).
-                        // e.g., if the number of points is 1024, it covers the frequency range
-                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
-                        int bin = freq / (22050 / 1024);
-                        int tmp = 0;
-                        for (int j = bin-2; j < bin+3; j++) {
-                            tmp += (int)mFft[j] * (int)mFft[j];
-                        }
-                        energy += tmp/5;
-                        count++;
-                    }
-                    Thread.sleep(50);
-                }
-                mVisualizer.setEnabled(false);
-            }
-            if (count == 0) {
-                return 0;
-            }
-            return energy/count;
-        }
-
-        public void release() {
-            if (mVisualizer != null) {
-                mVisualizer.release();
-                mVisualizer = null;
-            }
-        }
-    }
-
     private void getEqualizer(int session) {
          if (mEqualizer == null || session != mSession) {
              if (session != mSession && mEqualizer != null) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java
new file mode 100644
index 0000000..c14319a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.PresetReverb;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaPresetReverbTest";
+
+    private PresetReverb mReverb = null;
+    private int mSession = -1;
+
+    public MediaPresetReverbTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseReverb();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // PRESET REVEB TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        PresetReverb reverb = null;
+         try {
+            reverb = new PresetReverb(0, 0);
+            assertNotNull(msg + ": could not create PresetReverb", reverb);
+            try {
+                assertTrue(msg +": invalid effect ID", (reverb.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": PresetReverb not initialized");
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": PresetReverb not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (reverb != null) {
+                reverb.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test preset
+    @LargeTest
+    public void test1_0Preset() throws Exception {
+        boolean result = false;
+        String msg = "test1_0Preset()";
+        getReverb(0);
+        try {
+            mReverb.setPreset((short)PresetReverb.PRESET_LARGEROOM);
+            short preset = mReverb.getPreset();
+            assertEquals(msg +": got incorrect preset",
+                         (short)PresetReverb.PRESET_LARGEROOM,
+                         preset);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test properties
+    @LargeTest
+    public void test1_1Properties() throws Exception {
+        boolean result = false;
+        String msg = "test1_1Properties()";
+        getReverb(0);
+        try {
+            PresetReverb.Settings settings = mReverb.getProperties();
+            short newPreset = (short)PresetReverb.PRESET_LARGEROOM;
+            if (settings.preset == (short)PresetReverb.PRESET_LARGEROOM) {
+                newPreset = (short)PresetReverb.PRESET_SMALLROOM;
+            }
+            String str = settings.toString();
+            settings = new PresetReverb.Settings(str);
+            settings.preset = newPreset;
+            mReverb.setProperties(settings);
+            settings = mReverb.getProperties();
+            assertEquals(msg +": setProperties failed", newPreset, settings.preset);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect action
+    //----------------------------------
+
+    //Test case 2.0: test actual auxiliary reverb influence on sound
+    @LargeTest
+    public void test2_0AuxiliarySoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_0AuxiliarySoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+        getReverb(0);
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            mp.attachAuxEffect(mReverb.getId());
+            mp.setAuxEffectSendLevel(1.0f);
+            mReverb.setPreset((short)PresetReverb.PRESET_PLATE);
+            mReverb.setEnabled(true);
+            mp.prepare();
+            mp.start();
+            Thread.sleep(1000);
+            mp.stop();
+            Thread.sleep(200);
+            // measure energy around 1kHz after media player was stopped for 200 ms
+            int energy1000 = probe.capture(1000);
+            assertTrue(msg + ": reverb has no effect", energy1000 > 0);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseReverb();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 2.1: test actual insert reverb influence on sound
+    @LargeTest
+    public void test2_1InsertSoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_1InsertSoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getReverb(mp.getAudioSessionId());
+            mReverb.setPreset((short)PresetReverb.PRESET_PLATE);
+            mReverb.setEnabled(true);
+            mp.prepare();
+            mp.start();
+            Thread.sleep(1000);
+            mp.stop();
+            Thread.sleep(200);
+            // measure energy around 1kHz after media player was stopped for 200 ms
+            int energy1000 = probe.capture(1000);
+            assertTrue(msg + ": reverb has no effect", energy1000 > 0);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseReverb();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getReverb(int session) {
+         if (mReverb == null || session != mSession) {
+             if (session != mSession && mReverb != null) {
+                 mReverb.release();
+                 mReverb = null;
+             }
+             try {
+                mReverb = new PresetReverb(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getReverb() PresetReverb not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mReverb", mReverb);
+    }
+
+    private void releaseReverb() {
+        if (mReverb != null) {
+            mReverb.release();
+            mReverb = null;
+        }
+   }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java
index 6b8ae44..517d575 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java
@@ -43,7 +43,7 @@
  */
 public class MediaVirtualizerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
     private String TAG = "MediaVirtualizerTest";
-    private final static int MIN_ENERGY_RATIO_2 = 4;
+    private final static int MIN_ENERGY_RATIO_2 = 3;
     private final static short TEST_STRENGTH = 500;
 
     private Virtualizer mVirtualizer = null;
@@ -224,7 +224,7 @@
             int energy200 = probe.capture(200);
             int energy1000 = probe.capture(1000);
             // verify that the energy ration between low and high frequencies is at least
-            // four times higher with virtualizer on.
+            // MIN_ENERGY_RATIO_2 times higher with virtualizer on.
             // NOTE: this is what is observed with current virtualizer implementation and the test
             // audio file but is not the primary effect of the virtualizer. A better way would
             // be to have a stereo PCM capture and check that a strongly paned input is centered
@@ -264,52 +264,6 @@
     // private methods
     //----------------------------------
 
-    private class EnergyProbe {
-        Visualizer mVisualizer = null;
-        private byte[] mFft = new byte[1024];
-
-        public EnergyProbe(int session) {
-            mVisualizer = new Visualizer(session);
-            mVisualizer.setCaptureSize(1024);
-        }
-
-        public int capture(int freq) throws InterruptedException {
-            int energy = 0;
-            int count = 0;
-            if (mVisualizer != null) {
-                mVisualizer.setEnabled(true);
-                for (int i = 0; i < 10; i++) {
-                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
-                        // TODO: check speex FFT as it seems to return only the number of points
-                        // correspondong to valid part of the spectrum (< Fs).
-                        // e.g., if the number of points is 1024, it covers the frequency range
-                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
-                        int bin = freq / (22050 / 1024);
-                        int tmp = 0;
-                        for (int j = bin-2; j < bin+3; j++) {
-                            tmp += (int)mFft[j] * (int)mFft[j];
-                        }
-                        energy += tmp/5;
-                        count++;
-                    }
-                    Thread.sleep(50);
-                }
-                mVisualizer.setEnabled(false);
-            }
-            if (count == 0) {
-                return 0;
-            }
-            return energy/count;
-        }
-
-        public void release() {
-            if (mVisualizer != null) {
-                mVisualizer.release();
-                mVisualizer = null;
-            }
-        }
-    }
-
     private void getVirtualizer(int session) {
          if (mVirtualizer == null || session != mSession) {
              if (session != mSession && mVirtualizer != null) {
diff --git a/opengl/java/android/opengl/GLWallpaperService.java b/opengl/java/android/opengl/GLWallpaperService.java
new file mode 100644
index 0000000..c954fed
--- /dev/null
+++ b/opengl/java/android/opengl/GLWallpaperService.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.opengl;
+
+/**
+ * reserve this namespace for future use
+ * (making sure external developers don't use it)
+ * @hide
+ */
+class GLWallpaperService {
+}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 4d35bec..c61baad 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -77,9 +77,12 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 /**
  * This class provides a system service that manages input methods.
@@ -463,14 +466,19 @@
         screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
 
+        mStatusBar = statusBar;
+        statusBar.setIconVisibility("ime", false);
+
         buildInputMethodListLocked(mMethodList, mMethodMap);
 
         final String enabledStr = Settings.Secure.getString(
                 mContext.getContentResolver(),
                 Settings.Secure.ENABLED_INPUT_METHODS);
         Slog.i(TAG, "Enabled input methods: " + enabledStr);
-        if (enabledStr == null) {
-            Slog.i(TAG, "Enabled input methods has not been set, enabling all");
+        final String defaultIme = Settings.Secure.getString(mContext
+                .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+        if (enabledStr == null || TextUtils.isEmpty(defaultIme)) {
+            Slog.i(TAG, "Enabled input methods or default IME has not been set, enabling all");
             InputMethodInfo defIm = null;
             StringBuilder sb = new StringBuilder(256);
             final int N = mMethodList.size();
@@ -504,9 +512,6 @@
             }
         }
 
-        mStatusBar = statusBar;
-        statusBar.setIconVisibility("ime", false);
-
         mSettingsObserver = new SettingsObserver(mHandler);
         updateFromSettingsLocked();
     }
@@ -978,7 +983,7 @@
     void setInputMethodLocked(String id) {
         InputMethodInfo info = mMethodMap.get(id);
         if (info == null) {
-            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+            throw new IllegalArgumentException("Unknown id: " + id);
         }
 
         if (id.equals(mCurMethodId)) {
@@ -1476,7 +1481,7 @@
 
         String defaultIme = Settings.Secure.getString(mContext
                 .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (!map.containsKey(defaultIme)) {
+        if (!TextUtils.isEmpty(defaultIme) && !map.containsKey(defaultIme)) {
             if (chooseNewDefaultIMELocked()) {
                 updateFromSettingsLocked();
             }
@@ -1506,21 +1511,22 @@
             hideInputMethodMenuLocked();
 
             int N = immis.size();
-    
-            mItems = new CharSequence[N];
-            mIms = new InputMethodInfo[N];
-    
-            int j = 0;
+
+            final Map<CharSequence, InputMethodInfo> imMap =
+                new TreeMap<CharSequence, InputMethodInfo>(Collator.getInstance());
+
             for (int i = 0; i < N; ++i) {
                 InputMethodInfo property = immis.get(i);
                 if (property == null) {
                     continue;
                 }
-                mItems[j] = property.loadLabel(pm);
-                mIms[j] = property;
-                j++;
+                imMap.put(property.loadLabel(pm), property);
             }
-    
+
+            N = imMap.size();
+            mItems = imMap.keySet().toArray(new CharSequence[N]);
+            mIms = imMap.values().toArray(new InputMethodInfo[N]);
+
             int checkedItem = 0;
             for (int i = 0; i < N; ++i) {
                 if (mIms[i].getId().equals(lastInputMethodId)) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 421d1c4..9b9d950 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -4808,6 +4808,8 @@
         Parcel data = null;
         Parcel reply = null;
 
+        BufferedWriter out = null;
+
         // Any uncaught exception will crash the system process
         try {
             // Find the hashcode of the window
@@ -4845,6 +4847,12 @@
 
             reply.readException();
 
+            if (!client.isOutputShutdown()) {
+                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
+                out.write("DONE\n");
+                out.flush();
+            }
+
         } catch (Exception e) {
             Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
             success = false;
@@ -4855,6 +4863,13 @@
             if (reply != null) {
                 reply.recycle();
             }
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+
+                }
+            }
         }
 
         return success;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c316074..d535343 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4294,12 +4294,10 @@
                         + " when granting permission to uri " + uri);
             }
             if (targetPkg == null) {
-                Slog.w(TAG, "grantUriPermission: null target");
-                return;
+                throw new IllegalArgumentException("null target");
             }
             if (uri == null) {
-                Slog.w(TAG, "grantUriPermission: null uri");
-                return;
+                throw new IllegalArgumentException("null uri");
             }
 
             grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
@@ -4451,6 +4449,56 @@
         }
     }
 
+    @Override
+    public IBinder newUriPermissionOwner(String name) {
+        synchronized(this) {
+            UriPermissionOwner owner = new UriPermissionOwner(this, name);
+            return owner.getExternalTokenLocked();
+        }
+    }
+
+    @Override
+    public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
+            Uri uri, int modeFlags) {
+        synchronized(this) {
+            UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+            if (owner == null) {
+                throw new IllegalArgumentException("Unknown owner: " + token);
+            }
+            if (fromUid != Binder.getCallingUid()) {
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    // Only system code can grant URI permissions on behalf
+                    // of other users.
+                    throw new SecurityException("nice try");
+                }
+            }
+            if (targetPkg == null) {
+                throw new IllegalArgumentException("null target");
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("null uri");
+            }
+
+            grantUriPermissionLocked(fromUid, targetPkg, uri, modeFlags, owner);
+        }
+    }
+
+    @Override
+    public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode) {
+        synchronized(this) {
+            UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+            if (owner == null) {
+                throw new IllegalArgumentException("Unknown owner: " + token);
+            }
+
+            if (uri == null) {
+                owner.removeUriPermissionsLocked(mode);
+            } else {
+                owner.removeUriPermissionLocked(uri, mode);
+            }
+        }
+    }
+
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
         synchronized (this) {
             ProcessRecord app =
@@ -8260,7 +8308,7 @@
                 si.deliveryCount++;
                 if (si.targetPermissionUid >= 0) {
                     grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
-                            r.packageName, si.intent, si);
+                            r.packageName, si.intent, si.getUriPermissionsLocked());
                 }
                 if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r);
                 bumpServiceExecutingLocked(r);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 80a41b7..62be918 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -44,7 +44,7 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-class ActivityRecord extends IApplicationToken.Stub implements UriPermissionOwner {
+class ActivityRecord extends IApplicationToken.Stub {
     final ActivityManagerService service; // owner
     final ActivityStack stack; // owner
     final ActivityInfo info; // all about me
@@ -78,8 +78,7 @@
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
     ArrayList newIntents;   // any pending new intents for single-top mode
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
-    HashSet<UriPermission> readUriPermissions; // special access to reading uris.
-    HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
+    UriPermissionOwner uriPermissions; // current special URI access perms.
     ProcessRecord app;  // if non-null, hosting application
     Bitmap thumbnail;       // icon representation of paused screen
     CharSequence description; // textual description of paused screen
@@ -141,11 +140,15 @@
         if (pendingResults != null) {
             pw.print(prefix); pw.print("pendingResults="); pw.println(pendingResults);
         }
-        if (readUriPermissions != null) {
-            pw.print(prefix); pw.print("readUriPermissions="); pw.println(readUriPermissions);
-        }
-        if (writeUriPermissions != null) {
-            pw.print(prefix); pw.print("writeUriPermissions="); pw.println(writeUriPermissions);
+        if (uriPermissions != null) {
+            if (uriPermissions.readUriPermissions != null) {
+                pw.print(prefix); pw.print("readUriPermissions=");
+                        pw.println(uriPermissions.readUriPermissions);
+            }
+            if (uriPermissions.writeUriPermissions != null) {
+                pw.print(prefix); pw.print("writeUriPermissions=");
+                        pw.println(uriPermissions.writeUriPermissions);
+            }
         }
         pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
                 pw.print(" haveState="); pw.print(haveState);
@@ -301,6 +304,13 @@
         }
     }
 
+    UriPermissionOwner getUriPermissionsLocked() {
+        if (uriPermissions == null) {
+            uriPermissions = new UriPermissionOwner(service, this);
+        }
+        return uriPermissions;
+    }
+
     void addResultLocked(ActivityRecord from, String resultWho,
             int requestCode, int resultCode,
             Intent resultData) {
@@ -350,7 +360,7 @@
                 intent = new Intent(intent);
                 ar.add(intent);
                 service.grantUriPermissionFromIntentLocked(callingUid, packageName,
-                        intent, this);
+                        intent, getUriPermissionsLocked());
                 app.thread.scheduleNewIntent(ar, this);
                 sent = true;
             } catch (RemoteException e) {
@@ -367,27 +377,9 @@
     }
 
     void removeUriPermissionsLocked() {
-        if (readUriPermissions != null) {
-            for (UriPermission perm : readUriPermissions) {
-                perm.readOwners.remove(this);
-                if (perm.readOwners.size() == 0 && (perm.globalModeFlags
-                        &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
-                    perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                    service.removeUriPermissionIfNeededLocked(perm);
-                }
-            }
-            readUriPermissions = null;
-        }
-        if (writeUriPermissions != null) {
-            for (UriPermission perm : writeUriPermissions) {
-                perm.writeOwners.remove(this);
-                if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
-                        &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
-                    perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-                    service.removeUriPermissionIfNeededLocked(perm);
-                }
-            }
-            writeUriPermissions = null;
+        if (uriPermissions != null) {
+            uriPermissions.removeUriPermissionsLocked();
+            uriPermissions = null;
         }
     }
 
@@ -578,38 +570,6 @@
                 state == ActivityState.RESUMED;
      }
     
-    @Override
-    public void addReadPermission(UriPermission perm) {
-        if (readUriPermissions == null) {
-            readUriPermissions = new HashSet<UriPermission>();
-        }
-        readUriPermissions.add(perm);
-    }
-
-    @Override
-    public void addWritePermission(UriPermission perm) {
-        if (writeUriPermissions == null) {
-            writeUriPermissions = new HashSet<UriPermission>();
-        }
-        writeUriPermissions.add(perm);
-    }
-
-    @Override
-    public void removeReadPermission(UriPermission perm) {
-        readUriPermissions.remove(perm);
-        if (readUriPermissions.size() == 0) {
-            readUriPermissions = null;
-        }
-    }
-
-    @Override
-    public void removeWritePermission(UriPermission perm) {
-        writeUriPermissions.remove(perm);
-        if (writeUriPermissions.size() == 0) {
-            writeUriPermissions = null;
-        }
-    }
-    
     public String toString() {
         if (stringName != null) {
             return stringName;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a5f7e96..a99b48c 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2327,12 +2327,12 @@
         if (grantedUriPermissions != null && callingUid > 0) {
             for (int i=0; i<grantedUriPermissions.length; i++) {
                 mService.grantUriPermissionLocked(callingUid, r.packageName,
-                        grantedUriPermissions[i], grantedMode, r);
+                        grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
             }
         }
 
         mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                intent, r);
+                intent, r.getUriPermissionsLocked());
 
         if (newTask) {
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
@@ -2557,7 +2557,7 @@
 
         if (callingUid > 0) {
             mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                    data, r);
+                    data, r.getUriPermissionsLocked());
         }
 
         if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
@@ -2885,7 +2885,7 @@
                     + " res=" + resultCode + " data=" + resultData);
             if (r.info.applicationInfo.uid > 0) {
                 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
-                        r.packageName, resultData, r);
+                        r.packageName, resultData, r.getUriPermissionsLocked());
             }
             resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
                                      resultData);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index d5b050b..f35a68e 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -96,7 +96,7 @@
 
     String stringName;      // caching of toString
     
-    static class StartItem implements UriPermissionOwner {
+    static class StartItem {
         final ServiceRecord sr;
         final int id;
         final Intent intent;
@@ -104,12 +104,10 @@
         long deliveredTime;
         int deliveryCount;
         int doneExecutingCount;
+        UriPermissionOwner uriPermissions;
 
         String stringName;      // caching of toString
 
-        HashSet<UriPermission> readUriPermissions; // special access to reading uris.
-        HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
-
         StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
             sr = _sr;
             id = _id;
@@ -117,60 +115,17 @@
             targetPermissionUid = _targetPermissionUid;
         }
 
+        UriPermissionOwner getUriPermissionsLocked() {
+            if (uriPermissions == null) {
+                uriPermissions = new UriPermissionOwner(sr.ams, this);
+            }
+            return uriPermissions;
+        }
+
         void removeUriPermissionsLocked() {
-            if (readUriPermissions != null) {
-                for (UriPermission perm : readUriPermissions) {
-                    perm.readOwners.remove(this);
-                    if (perm.readOwners.size() == 0 && (perm.globalModeFlags
-                            &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
-                        perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                        sr.ams.removeUriPermissionIfNeededLocked(perm);
-                    }
-                }
-                readUriPermissions = null;
-            }
-            if (writeUriPermissions != null) {
-                for (UriPermission perm : writeUriPermissions) {
-                    perm.writeOwners.remove(this);
-                    if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
-                            &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
-                        perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-                        sr.ams.removeUriPermissionIfNeededLocked(perm);
-                    }
-                }
-                writeUriPermissions = null;
-            }
-        }
-
-        @Override
-        public void addReadPermission(UriPermission perm) {
-            if (readUriPermissions == null) {
-                readUriPermissions = new HashSet<UriPermission>();
-            }
-            readUriPermissions.add(perm);
-        }
-
-        @Override
-        public void addWritePermission(UriPermission perm) {
-            if (writeUriPermissions == null) {
-                writeUriPermissions = new HashSet<UriPermission>();
-            }
-            writeUriPermissions.add(perm);
-        }
-
-        @Override
-        public void removeReadPermission(UriPermission perm) {
-            readUriPermissions.remove(perm);
-            if (readUriPermissions.size() == 0) {
-                readUriPermissions = null;
-            }
-        }
-
-        @Override
-        public void removeWritePermission(UriPermission perm) {
-            writeUriPermissions.remove(perm);
-            if (writeUriPermissions.size() == 0) {
-                writeUriPermissions = null;
+            if (uriPermissions != null) {
+                uriPermissions.removeUriPermissionsLocked();
+                uriPermissions = null;
             }
         }
 
@@ -218,13 +173,15 @@
                 pw.print(prefix); pw.print("  targetPermissionUid=");
                         pw.println(si.targetPermissionUid);
             }
-            if (si.readUriPermissions != null) {
-                pw.print(prefix); pw.print("  readUriPermissions=");
-                        pw.println(si.readUriPermissions);
-            }
-            if (si.writeUriPermissions != null) {
-                pw.print(prefix); pw.print("  writeUriPermissions=");
-                        pw.println(si.writeUriPermissions);
+            if (si.uriPermissions != null) {
+                if (si.uriPermissions.readUriPermissions != null) {
+                    pw.print(prefix); pw.print("  readUriPermissions=");
+                            pw.println(si.uriPermissions.readUriPermissions);
+                }
+                if (si.uriPermissions.writeUriPermissions != null) {
+                    pw.print(prefix); pw.print("  writeUriPermissions=");
+                            pw.println(si.uriPermissions.writeUriPermissions);
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 93c59cc..c95546e 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -22,13 +22,14 @@
 import java.io.PrintWriter;
 import java.util.HashSet;
 
-interface UriPermissionOwner {
-    void addReadPermission(UriPermission perm);
-    void addWritePermission(UriPermission perm);
-    void removeReadPermission(UriPermission perm);
-    void removeWritePermission(UriPermission perm);
-}
-
+/**
+ * Description of a permission granted to an app to access a particular URI.
+ *
+ * CTS tests for this functionality can be run with "runtest cts-appsecurity".
+ *
+ * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert
+ *      /src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+ */
 class UriPermission {
     final int uid;
     final Uri uri;
diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/java/com/android/server/am/UriPermissionOwner.java
new file mode 100644
index 0000000..99c82e6
--- /dev/null
+++ b/services/java/com/android/server/am/UriPermissionOwner.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+class UriPermissionOwner {
+    final ActivityManagerService service;
+    final Object owner;
+
+    Binder externalToken;
+
+    HashSet<UriPermission> readUriPermissions; // special access to reading uris.
+    HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
+
+    class ExternalToken extends Binder {
+        UriPermissionOwner getOwner() {
+            return UriPermissionOwner.this;
+        }
+    }
+
+    UriPermissionOwner(ActivityManagerService _service, Object _owner) {
+        service = _service;
+        owner = _owner;
+    }
+
+    Binder getExternalTokenLocked() {
+        if (externalToken != null) {
+            externalToken = new ExternalToken();
+        }
+        return externalToken;
+    }
+
+    static UriPermissionOwner fromExternalToken(IBinder token) {
+        if (token instanceof ExternalToken) {
+            return ((ExternalToken)token).getOwner();
+        }
+        return null;
+    }
+
+    void removeUriPermissionsLocked() {
+        removeUriPermissionsLocked(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+    }
+
+    void removeUriPermissionsLocked(int mode) {
+        if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
+                && readUriPermissions != null) {
+            for (UriPermission perm : readUriPermissions) {
+                perm.readOwners.remove(this);
+                if (perm.readOwners.size() == 0 && (perm.globalModeFlags
+                        &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
+                    perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                    service.removeUriPermissionIfNeededLocked(perm);
+                }
+            }
+            readUriPermissions = null;
+        }
+        if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
+                && writeUriPermissions != null) {
+            for (UriPermission perm : writeUriPermissions) {
+                perm.writeOwners.remove(this);
+                if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
+                        &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
+                    perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                    service.removeUriPermissionIfNeededLocked(perm);
+                }
+            }
+            writeUriPermissions = null;
+        }
+    }
+
+    void removeUriPermissionLocked(Uri uri, int mode) {
+        if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
+                && readUriPermissions != null) {
+            Iterator<UriPermission> it = readUriPermissions.iterator();
+            while (it.hasNext()) {
+                UriPermission perm = it.next();
+                if (uri.equals(perm.uri)) {
+                    perm.readOwners.remove(this);
+                    if (perm.readOwners.size() == 0 && (perm.globalModeFlags
+                            &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
+                        perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                        service.removeUriPermissionIfNeededLocked(perm);
+                    }
+                    it.remove();
+                }
+            }
+            if (readUriPermissions.size() == 0) {
+                readUriPermissions = null;
+            }
+        }
+        if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
+                && writeUriPermissions != null) {
+            Iterator<UriPermission> it = writeUriPermissions.iterator();
+            while (it.hasNext()) {
+                UriPermission perm = it.next();
+                if (uri.equals(perm.uri)) {
+                    perm.writeOwners.remove(this);
+                    if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
+                            &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
+                        perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                        service.removeUriPermissionIfNeededLocked(perm);
+                    }
+                    it.remove();
+                }
+            }
+            if (writeUriPermissions.size() == 0) {
+                writeUriPermissions = null;
+            }
+        }
+    }
+
+    public void addReadPermission(UriPermission perm) {
+        if (readUriPermissions == null) {
+            readUriPermissions = new HashSet<UriPermission>();
+        }
+        readUriPermissions.add(perm);
+    }
+
+    public void addWritePermission(UriPermission perm) {
+        if (writeUriPermissions == null) {
+            writeUriPermissions = new HashSet<UriPermission>();
+        }
+        writeUriPermissions.add(perm);
+    }
+
+    public void removeReadPermission(UriPermission perm) {
+        readUriPermissions.remove(perm);
+        if (readUriPermissions.size() == 0) {
+            readUriPermissions = null;
+        }
+    }
+
+    public void removeWritePermission(UriPermission perm) {
+        writeUriPermissions.remove(perm);
+        if (writeUriPermissions.size() == 0) {
+            writeUriPermissions = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return owner.toString();
+    }
+}
diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java
index 1142136..3dcaff6 100644
--- a/services/java/com/android/server/sip/SipService.java
+++ b/services/java/com/android/server/sip/SipService.java
@@ -32,6 +32,7 @@
 import android.net.sip.SipSessionAdapter;
 import android.net.sip.SipSessionState;
 import android.net.wifi.WifiManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -97,6 +98,7 @@
     }
 
     public void open(SipProfile localProfile) {
+        localProfile.setCallingUid(Binder.getCallingUid());
         if (localProfile.getAutoRegistration()) {
             openToReceiveCalls(localProfile);
         } else {
@@ -119,6 +121,7 @@
 
     public synchronized void open3(SipProfile localProfile,
             String incomingCallBroadcastAction, ISipSessionListener listener) {
+        localProfile.setCallingUid(Binder.getCallingUid());
         if (TextUtils.isEmpty(incomingCallBroadcastAction)) {
             throw new RuntimeException(
                     "empty broadcast action for incoming call");
@@ -165,6 +168,7 @@
 
     public synchronized ISipSession createSession(SipProfile localProfile,
             ISipSessionListener listener) {
+        localProfile.setCallingUid(Binder.getCallingUid());
         if (!mConnected) return null;
         try {
             SipSessionGroupExt group = createGroup(localProfile);
@@ -362,16 +366,7 @@
 
         private SipProfile duplicate(SipProfile p) {
             try {
-                return new SipProfile.Builder(p.getUserName(), p.getSipDomain())
-                        .setProfileName(p.getProfileName())
-                        .setPassword("*")
-                        .setPort(p.getPort())
-                        .setProtocol(p.getProtocol())
-                        .setOutboundProxy(p.getProxyAddress())
-                        .setSendKeepAlive(p.getSendKeepAlive())
-                        .setAutoRegistration(p.getAutoRegistration())
-                        .setDisplayName(p.getDisplayName())
-                        .build();
+                return new SipProfile.Builder(p).setPassword("*").build();
             } catch (Exception e) {
                 Log.wtf(TAG, "duplicate()", e);
                 throw new RuntimeException("duplicate profile", e);
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 980affa..12df44e 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -691,8 +691,8 @@
      * Stop the playing DTMF tone. Ignored if there is no playing DTMF
      * tone or no active call.
      */
-    public void stopDtmf(Phone phone) {
-        phone.stopDtmf();
+    public void stopDtmf() {
+        if (hasActiveFgCall()) getFgPhone().stopDtmf();
     }
 
     /**
@@ -709,7 +709,7 @@
      * @param onComplete is the callback message when the action is processed by BP
      *
      */
-    public boolean sendBurstDtmf(Phone phone, String dtmfString, int on, int off, Message onComplete) {
+    public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
         if (hasActiveFgCall()) {
             getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
             return true;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 35124aa..b0f086b 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -141,9 +141,9 @@
     if (bundle->getVerbose()) {
         printf("Archive:  %s\n", zipFileName);
         printf(
-            " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n");
+            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
         printf(
-            "--------  ------  ------- -----   ----   ----   ------    ----\n");
+            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
     }
 
     totalUncLen = totalCompLen = 0;
@@ -159,12 +159,13 @@
             strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
                 localtime(&when));
 
-            printf("%8ld  %-7.7s %7ld %3d%%  %s  %08lx  %s\n",
+            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
                 (long) entry->getUncompressedLen(),
                 compressionName(entry->getCompressionMethod()),
                 (long) entry->getCompressedLen(),
                 calcPercent(entry->getUncompressedLen(),
                             entry->getCompressedLen()),
+                (size_t) entry->getLFHOffset(),
                 dateBuf,
                 entry->getCRC32(),
                 entry->getFileName());
diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h
index 7f721b4..c2f3227 100644
--- a/tools/aapt/ZipEntry.h
+++ b/tools/aapt/ZipEntry.h
@@ -72,6 +72,11 @@
     off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
 
     /*
+     * Return the offset of the local file header.
+     */
+    off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+    /*
      * Return the absolute file offset of the start of the compressed or
      * uncompressed data.
      */
@@ -186,11 +191,6 @@
     void setModWhen(time_t when);
 
     /*
-     * Return the offset of the local file header.
-     */
-    off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
-
-    /*
      * Set the offset of the local file header, relative to the start of
      * the current file.
      */
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index b8ac6d7..5789cd4 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -36,6 +36,7 @@
 import android.net.sip.SipProfile;
 import android.net.sip.SipSessionAdapter;
 import android.net.sip.SipSessionState;
+import android.net.wifi.WifiManager;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.Vibrator;
@@ -84,10 +85,13 @@
     private ToneGenerator mRingbackTone;
 
     private SipProfile mPendingCallRequest;
+    private WifiManager mWm;
+    private WifiManager.WifiLock mWifiHighPerfLock;
 
     public SipAudioCallImpl(Context context, SipProfile localProfile) {
         mContext = context;
         mLocalProfile = localProfile;
+        mWm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     }
 
     public void setListener(SipAudioCall.Listener listener) {
@@ -422,6 +426,28 @@
         }
     }
 
+    private void grabWifiHighPerfLock() {
+        if (mWifiHighPerfLock == null) {
+            Log.v(TAG, "acquire wifi high perf lock");
+            mWifiHighPerfLock = ((WifiManager)
+                    mContext.getSystemService(Context.WIFI_SERVICE))
+                    .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG);
+            mWifiHighPerfLock.acquire();
+        }
+    }
+
+    private void releaseWifiHighPerfLock() {
+        if (mWifiHighPerfLock != null) {
+            Log.v(TAG, "release wifi high perf lock");
+            mWifiHighPerfLock.release();
+            mWifiHighPerfLock = null;
+        }
+    }
+
+    private boolean isWifiOn() {
+        return (mWm.getConnectionInfo().getBSSID() == null) ? false : true;
+    }
+
     private SessionDescription createContinueSessionDescription() {
         return createSdpBuilder(true, mCodec).build();
     }
@@ -556,7 +582,7 @@
 
     private void startCall(SdpSessionDescription peerSd) {
         stopCall(DONT_RELEASE_SOCKET);
-
+        if (isWifiOn()) grabWifiHighPerfLock();
         mPeerSd = peerSd;
         String peerMediaAddress = peerSd.getPeerMediaAddress(AUDIO);
         // TODO: handle multiple media fields
@@ -623,6 +649,7 @@
 
     private void stopCall(boolean releaseSocket) {
         Log.d(TAG, "stop audiocall");
+        releaseWifiHighPerfLock();
         if (mAudioStream != null) {
             mAudioStream.join(null);
 
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index ec8d0ed..6c99141 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -47,6 +47,7 @@
     private boolean mSendKeepAlive = false;
     private boolean mAutoRegistration = true;
     private boolean mAllowOutgoingCall = false;
+    private int mCallingUid = -1;
 
     /** @hide */
     public static final Parcelable.Creator<SipProfile> CREATOR =
@@ -293,6 +294,7 @@
         mSendKeepAlive = (in.readInt() == 0) ? false : true;
         mAutoRegistration = (in.readInt() == 0) ? false : true;
         mAllowOutgoingCall = (in.readInt() == 0) ? false : true;
+        mCallingUid = in.readInt();
     }
 
     /** @hide */
@@ -306,6 +308,7 @@
         out.writeInt(mSendKeepAlive ? 1 : 0);
         out.writeInt(mAutoRegistration ? 1 : 0);
         out.writeInt(mAllowOutgoingCall ? 1 : 0);
+        out.writeInt(mCallingUid);
     }
 
     /** @hide */
@@ -437,4 +440,20 @@
     public boolean isOutgoingCallAllowed() {
         return mAllowOutgoingCall;
     }
+
+    /**
+     * Sets the calling process's Uid in the sip service.
+     * @hide
+     */
+    public void setCallingUid(int uid) {
+        mCallingUid = uid;
+    }
+
+    /**
+     * Gets the calling process's Uid in the sip settings.
+     * @hide
+     */
+    public int getCallingUid() {
+        return mCallingUid;
+    }
 }
diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk
index 3bd85aa..a364355 100644
--- a/voip/jni/rtp/Android.mk
+++ b/voip/jni/rtp/Android.mk
@@ -32,11 +32,10 @@
 	libutils \
 	libmedia
 
-LOCAL_STATIC_LIBRARIES := libspeex
+LOCAL_STATIC_LIBRARIES :=
 
 LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	external/speex/include
+	$(JNI_H_INCLUDE)
 
 LOCAL_CFLAGS += -fvisibility=hidden
 
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index b5a4e22..bb45a9a 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -40,8 +40,6 @@
 #include <media/AudioTrack.h>
 #include <media/mediarecorder.h>
 
-#include <speex/speex_echo.h>
-
 #include "jni.h"
 #include "JNIHelp.h"
 
@@ -447,8 +445,6 @@
     int mDeviceSocket;
     AudioTrack mTrack;
     AudioRecord mRecord;
-    
-    SpeexEchoState *mEchoState;
 
     bool networkLoop();
     bool deviceLoop();
@@ -510,7 +506,6 @@
     mEventQueue = -1;
     mDtmfEvent = -1;
     mDeviceSocket = -1;
-    mEchoState = NULL;
     mNetworkThread = new NetworkThread(this);
     mDeviceThread = new DeviceThread(this);
 }
@@ -523,9 +518,6 @@
     mRecord.stop();
     close(mEventQueue);
     close(mDeviceSocket);
-    if (mEchoState) {
-        speex_echo_state_destroy(mEchoState);
-    }
     while (mChain) {
         AudioStream *next = mChain->mNext;
         delete mChain;
@@ -574,8 +566,7 @@
     }
     LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
 
-    // Initialize echo canceller.
-    mEchoState = speex_echo_state_init(sampleCount, sampleRate);
+    // TODO: initialize echo canceler here.
 
     // Create device socket.
     int pair[2];
@@ -642,7 +633,6 @@
     if (mode == MUTED) {
         mRecord.stop();
     } else {
-        speex_echo_state_reset(mEchoState);
         mRecord.start();
     }
 
@@ -803,7 +793,7 @@
 
             status_t status = mRecord.obtainBuffer(&buffer, 1);
             if (status == NO_ERROR) {
-                int count = ((int)buffer.frameCount < toRead) ?
+                int count = (buffer.frameCount < toRead) ?
                         buffer.frameCount : toRead;
                 memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
                 toRead -= count;
@@ -827,9 +817,8 @@
         if (mMode == NORMAL) {
             send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
         } else {
-            int16_t result[mSampleCount];
-            speex_echo_cancellation(mEchoState, input, output, result);
-            send(mDeviceSocket, result, sizeof(result), MSG_DONTWAIT);
+            // TODO: Echo canceller runs here.
+            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
         }
     }
     return true;