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;