summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk6
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/app/ContextImpl.java7
-rw-r--r--core/java/android/content/SharedPreferences.java37
-rw-r--r--core/java/android/hardware/SensorManager.java19
-rw-r--r--core/java/android/provider/MediaStore.java30
-rw-r--r--core/java/android/webkit/WebView.java6
-rw-r--r--core/jni/AndroidRuntime.cpp80
-rw-r--r--core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java5
-rw-r--r--core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java7
-rw-r--r--core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java28
-rw-r--r--core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java87
-rw-r--r--core/tests/coretests/src/android/pim/vcard/VCardVerifier.java25
-rw-r--r--include/media/EffectPresetReverbApi.h3
-rw-r--r--include/media/stagefright/DataSource.h9
-rw-r--r--include/private/surfaceflinger/SharedBufferStack.h18
-rw-r--r--include/surfaceflinger/Surface.h3
-rw-r--r--include/ui/egl/android_natives.h29
-rw-r--r--libs/surfaceflinger_client/SharedBufferStack.cpp46
-rw-r--r--libs/surfaceflinger_client/Surface.cpp22
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp2
-rwxr-xr-xmedia/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp251
-rw-r--r--media/libmedia/fixedfft.cpp2
-rw-r--r--media/libstagefright/AMRExtractor.cpp5
-rw-r--r--media/libstagefright/AwesomePlayer.cpp31
-rw-r--r--media/libstagefright/DataSource.cpp17
-rw-r--r--media/libstagefright/MP3Extractor.cpp32
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp7
-rw-r--r--media/libstagefright/MediaExtractor.cpp7
-rw-r--r--media/libstagefright/OggExtractor.cpp3
-rw-r--r--media/libstagefright/WAVExtractor.cpp3
-rw-r--r--media/libstagefright/id3/ID3.cpp88
-rw-r--r--media/libstagefright/include/AMRExtractor.h4
-rw-r--r--media/libstagefright/include/ID3.h1
-rw-r--r--media/libstagefright/include/MP3Extractor.h6
-rw-r--r--media/libstagefright/include/MPEG2TSExtractor.h4
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h4
-rw-r--r--media/libstagefright/include/OggExtractor.h4
-rw-r--r--media/libstagefright/include/WAVExtractor.h4
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp3
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.h4
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp3
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java182
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java329
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java12
-rw-r--r--services/surfaceflinger/Layer.cpp57
-rw-r--r--services/surfaceflinger/LayerBase.cpp107
-rw-r--r--services/surfaceflinger/LayerBase.h8
-rw-r--r--services/surfaceflinger/LayerBlur.cpp2
-rw-r--r--services/surfaceflinger/LayerBuffer.cpp2
-rw-r--r--services/surfaceflinger/TextureManager.h3
-rw-r--r--tests/CoreTests/android/core/JavaPerformanceTests.java1
-rw-r--r--tests/CoreTests/android/core/StringTest.java951
-rw-r--r--tools/aapt/Android.mk2
-rw-r--r--tools/localize/Android.mk2
-rw-r--r--voip/java/android/net/sip/SipProfile.java41
57 files changed, 1219 insertions, 1446 deletions
diff --git a/Android.mk b/Android.mk
index c1324c9..5f8b235 100644
--- a/Android.mk
+++ b/Android.mk
@@ -348,7 +348,7 @@ framework_docs_LOCAL_JAVA_LIBRARIES := \
framework \
framework_docs_LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
+framework_docs_LOCAL_DROIDDOC_HTML_DIR := $(LOCAL_PATH)/docs/html $(OUT_DOCS)/gen
# The since flag (-since N.xml API_LEVEL) is used to add API Level information
# to the reference documentation. Must be in order of oldest to newest.
framework_docs_LOCAL_DROIDDOC_OPTIONS := \
@@ -539,8 +539,8 @@ LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk
include $(BUILD_DROIDDOC)
-# explicitly specify that online-sdk depends on framework-res.
-$(full_target): framework-res-package-target
+# explicitly specify that online-sdk depends on framework-res and any generated docs
+$(full_target): framework-res-package-target $(ALL_GENERATED_DOCS)
# ==== docs that have all of the stuff that's @hidden =======================
include $(CLEAR_VARS)
diff --git a/api/current.xml b/api/current.xml
index 38756d3..4b0068d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -45115,6 +45115,17 @@
<parameter name="key" type="java.lang.String">
</parameter>
</method>
+<method name="startCommit"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</interface>
<interface name="SharedPreferences.OnSharedPreferenceChangeListener"
abstract="true"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2870c50..7b35e7f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2840,6 +2840,11 @@ class ContextImpl extends Context {
}
}
+ public void startCommit() {
+ // TODO: implement
+ commit();
+ }
+
public boolean commit() {
boolean returnValue;
@@ -2914,7 +2919,7 @@ class ContextImpl extends Context {
public Editor edit() {
return new EditorImpl();
}
-
+
private FileOutputStream createFileOutputStream(File file) {
FileOutputStream str = null;
try {
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index a15e29e..f1b1490 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -151,14 +151,47 @@ public interface SharedPreferences {
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
- *
+ *
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call commit wins.
- *
+ *
+ * <p>If you don't care about the return value and you're
+ * using this from your application's main thread, consider
+ * using {@link #startCommit} instead.
+ *
* @return Returns true if the new values were successfully written
* to persistent storage.
*/
boolean commit();
+
+ /**
+ * Commit your preferences changes back from this Editor to the
+ * {@link SharedPreferences} object it is editing. This atomically
+ * performs the requested modifications, replacing whatever is currently
+ * in the SharedPreferences.
+ *
+ * <p>Note that when two editors are modifying preferences at the same
+ * time, the last one to call commit wins.
+ *
+ * <p>Unlike {@link #commit}, which writes its preferences out
+ * to persistent storage synchronously, {@link #startCommit}
+ * commits its changes to the in-memory
+ * {@link SharedPreferences} immediately but starts an
+ * asynchronous commit to disk and you won't be notified of
+ * any failures. If another editor on this
+ * {@link SharedPreferences} does a regular {@link #commit}
+ * while a {@link #startCommit} is still outstanding, the
+ * {@link #commit} will block until all async commits are
+ * completed as well as the commit itself.
+ *
+ * <p>If you call this from an {@link android.app.Activity},
+ * the base class will wait for any async commits to finish in
+ * its {@link android.app.Activity#onPause}.</p>
+ *
+ * @return Returns true if the new values were successfully written
+ * to persistent storage.
+ */
+ void startCommit();
}
/**
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 97921fe..0068724 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -34,11 +34,19 @@ import java.util.HashMap;
import java.util.List;
/**
+ * <p>
* SensorManager lets you access the device's {@link android.hardware.Sensor
* sensors}. Get an instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String)
* Context.getSystemService()} with the argument
* {@link android.content.Context#SENSOR_SERVICE}.
+ * </p>
+ * <p>
+ * Always make sure to disable sensors you don't need, especially when your
+ * activity is paused. Failing to do so can drain the battery in just a few
+ * hours. Note that the system will <i>not</i> disable sensors automatically when
+ * the screen turns off.
+ * </p>
*
* <pre class="prettyprint">
* public class SensorActivity extends Activity, implements SensorEventListener {
@@ -48,13 +56,22 @@ import java.util.List;
* public SensorActivity() {
* mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
* mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ * }
+ *
+ * protected void onResume() {
+ * super.onResume();
* mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
* }
*
+ * protected void onPause() {
+ * super.onPause();
+ * mSensorManager.unregisterListener(this);
+ * }
+ *
* public void onAccuracyChanged(Sensor sensor, int accuracy) {
* }
*
- * public abstract void onSensorChanged(SensorEvent event) {
+ * public void onSensorChanged(SensorEvent event) {
* }
* }
* </pre>
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 40ed980..d20e89d 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -249,6 +249,8 @@ public final class MediaStore {
private static final int MICRO_KIND = 3;
private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
static final int DEFAULT_GROUP_ID = 0;
+ private static final Object sThumbBufLock = new Object();
+ private static byte[] sThumbBuf;
private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
Bitmap bitmap = null;
@@ -321,11 +323,15 @@ public final class MediaStore {
long magic = thumbFile.getMagic(origId);
if (magic != 0) {
if (kind == MICRO_KIND) {
- byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
- if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
- bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap == null) {
- Log.w(TAG, "couldn't decode byte array.");
+ synchronized (sThumbBufLock) {
+ if (sThumbBuf == null) {
+ sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
+ }
+ if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
+ bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
+ if (bitmap == null) {
+ Log.w(TAG, "couldn't decode byte array.");
+ }
}
}
return bitmap;
@@ -357,11 +363,15 @@ public final class MediaStore {
// Assuming thumbnail has been generated, at least original image exists.
if (kind == MICRO_KIND) {
- byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
- if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
- bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap == null) {
- Log.w(TAG, "couldn't decode byte array.");
+ synchronized (sThumbBufLock) {
+ if (sThumbBuf == null) {
+ sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
+ }
+ if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
+ bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
+ if (bitmap == null) {
+ Log.w(TAG, "couldn't decode byte array.");
+ }
}
}
} else if (kind == MINI_KIND) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3e0187d..f8e60ce 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3338,7 +3338,8 @@ public class WebView extends AbsoluteLayout
setUpSelect();
if (mNativeClass != 0 && nativeWordSelection(x, y)) {
nativeSetExtendSelection();
- getWebChromeClient().onSelectionStart(this);
+ WebChromeClient client = getWebChromeClient();
+ if (client != null) client.onSelectionStart(this);
return true;
}
notifySelectDialogDismissed();
@@ -4126,7 +4127,8 @@ public class WebView extends AbsoluteLayout
*/
public void selectionDone() {
if (mSelectingText) {
- getWebChromeClient().onSelectionDone(this);
+ WebChromeClient client = getWebChromeClient();
+ if (client != null) client.onSelectionDone(this);
invalidate(); // redraw without selection
notifySelectDialogDismissed();
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 407d2e7..62a4495 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -506,7 +506,7 @@ static void blockSigpipe()
static void readLocale(char* language, char* region)
{
char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
-
+
property_get("persist.sys.language", propLang, "");
property_get("persist.sys.country", propRegn, "");
if (*propLang == 0 && *propRegn == 0) {
@@ -710,6 +710,33 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
LOGW("dalvik.vm.gc.overwritefree should be 'true' or 'false'");
}
+ /* enable heap verification before each gc */
+ property_get("dalvik.vm.gc.preverify", propBuf, "false");
+ if (strcmp(propBuf, "true") == 0) {
+ opt.optionString = "-Xgc:preverify";
+ mOptions.add(opt);
+ } else if (strcmp(propBuf, "false") != 0) {
+ LOGW("dalvik.vm.gc.preverify should be 'true' or 'false'");
+ }
+
+ /* enable heap verification after each gc */
+ property_get("dalvik.vm.gc.postverify", propBuf, "false");
+ if (strcmp(propBuf, "true") == 0) {
+ opt.optionString = "-Xgc:postverify";
+ mOptions.add(opt);
+ } else if (strcmp(propBuf, "false") != 0) {
+ LOGW("dalvik.vm.gc.postverify should be 'true' or 'false'");
+ }
+
+ /* enable card table verification for partial gc */
+ property_get("dalvik.vm.gc.verifycardtable", propBuf, "false");
+ if (strcmp(propBuf, "true") == 0) {
+ opt.optionString = "-Xgc:verifycardtable";
+ mOptions.add(opt);
+ } else if (strcmp(propBuf, "false") != 0) {
+ LOGW("dalvik.vm.gc.verifycardtable should be 'true' or 'false'");
+ }
+
/* enable debugging; set suspend=y to pause during VM init */
#ifdef HAVE_ANDROID_OS
/* use android ADB transport */
@@ -757,16 +784,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
}
#if defined(WITH_JIT)
- /* Minimal profile threshold to trigger JIT compilation */
- char jitThresholdBuf[sizeof("-Xjitthreshold:") + PROPERTY_VALUE_MAX];
- property_get("dalvik.vm.jit.threshold", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(jitThresholdBuf, "-Xjitthreshold:");
- strcat(jitThresholdBuf, propBuf);
- opt.optionString = jitThresholdBuf;
- mOptions.add(opt);
- }
-
/* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
property_get("dalvik.vm.jit.op", propBuf, "");
@@ -777,16 +794,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
mOptions.add(opt);
}
- /*
- * Reverse the polarity of dalvik.vm.jit.op and force interpreter-only
- * for non-selected opcodes.
- */
- property_get("dalvik.vm.jit.includeop", propBuf, "");
- if (strlen(propBuf) > 0) {
- opt.optionString = "-Xincludeselectedop";
- mOptions.add(opt);
- }
-
/* Force interpreter-only mode for selected methods */
char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
property_get("dalvik.vm.jit.method", propBuf, "");
@@ -796,37 +803,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
opt.optionString = jitMethodBuf;
mOptions.add(opt);
}
-
- /*
- * Reverse the polarity of dalvik.vm.jit.method and force interpreter-only
- * for non-selected methods.
- */
- property_get("dalvik.vm.jit.includemethod", propBuf, "");
- if (strlen(propBuf) > 0) {
- opt.optionString = "-Xincludeselectedmethod";
- mOptions.add(opt);
- }
-
- /*
- * Enable profile collection on JIT'ed code.
- */
- property_get("dalvik.vm.jit.profile", propBuf, "");
- if (strlen(propBuf) > 0) {
- opt.optionString = "-Xjitprofile";
- mOptions.add(opt);
- }
-
- /*
- * Disable optimizations by setting the corresponding bit to 1.
- */
- char jitOptBuf[sizeof("-Xjitdisableopt:") + PROPERTY_VALUE_MAX];
- property_get("dalvik.vm.jit.disableopt", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(jitOptBuf, "-Xjitdisableopt:");
- strcat(jitOptBuf, propBuf);
- opt.optionString = jitOptBuf;
- mOptions.add(opt);
- }
#endif
if (executionMode == kEMIntPortable) {
diff --git a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java b/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
index 5968e83..951d0d8 100644
--- a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
+++ b/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
@@ -24,6 +24,7 @@ import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
+import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockCursor;
@@ -44,6 +45,10 @@ import java.util.List;
public ContactEntry addInputContactEntry() {
return mProvider.buildInputEntry();
}
+
+ public ExportTestProvider getProvider() {
+ return mProvider;
+ }
}
/* package */ class MockEntityIterator implements EntityIterator {
diff --git a/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java b/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java
index c3f6f79..1563da9 100644
--- a/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java
+++ b/core/tests/coretests/src/android/pim/vcard/ImportTestResolver.java
@@ -19,8 +19,6 @@ import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.net.Uri;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -34,6 +32,9 @@ import android.provider.ContactsContract.CommonDataKinds.Relation;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
@@ -45,10 +46,10 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.Map.Entry;
/* package */ class ImportTestResolver extends MockContentResolver {
final ImportTestProvider mProvider;
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
index 2de0464..2962a92 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
@@ -438,14 +438,26 @@ public class VCardExporterTests extends VCardTestsBase {
.put(Phone.TYPE, Phone.TYPE_CUSTOM)
.put(Phone.LABEL, "invalid");
PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
- elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
- .addExpectedNode("TEL", "2", new TypeSet("MSG"))
- .addExpectedNode("TEL", "3", new TypeSet("BBS"))
- .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
- .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
- .addExpectedNode("TEL", "6", new TypeSet("CELL"))
- .addExpectedNode("TEL", "7", new TypeSet("CELL"))
- .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
+ if (VCardConfig.isV30(vcardType)) {
+ // vCard 3.0 accepts "invalid". Also stop using toUpper()
+ elem.addExpectedNode("TEL", "1", new TypeSet("Modem"))
+ .addExpectedNode("TEL", "2", new TypeSet("MSG"))
+ .addExpectedNode("TEL", "3", new TypeSet("BBS"))
+ .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
+ .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
+ .addExpectedNode("TEL", "6", new TypeSet("CELL"))
+ .addExpectedNode("TEL", "7", new TypeSet("CELL"))
+ .addExpectedNode("TEL", "8", new TypeSet("invalid"));
+ } else {
+ elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
+ .addExpectedNode("TEL", "2", new TypeSet("MSG"))
+ .addExpectedNode("TEL", "3", new TypeSet("BBS"))
+ .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
+ .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
+ .addExpectedNode("TEL", "6", new TypeSet("CELL"))
+ .addExpectedNode("TEL", "7", new TypeSet("CELL"))
+ .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
+ }
}
public void testPhoneTypeHandlingV21() {
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java b/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java
index 416e872..9c6003f 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardTestsBase.java
@@ -16,95 +16,8 @@
package android.pim.vcard;
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
import android.content.ContentValues;
-import android.content.EntityIterator;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.database.CursorWindow;
-import android.database.IBulkCursor;
-import android.database.IContentObserver;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.pim.vcard.VCardConfig;
import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * Almost a dead copy of android.test.mock.MockContentProvider, but different in that this
- * class extends ContentProvider, not implementing IContentProvider,
- * so that MockContentResolver is able to accept this class :(
- */
-class MockContentProvider extends ContentProvider {
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public int bulkInsert(Uri url, ContentValues[] initialValues) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("unused")
- public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder, IContentObserver observer,
- CursorWindow window) throws RemoteException {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- @SuppressWarnings("unused")
- public int delete(Uri url, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public String getType(Uri url) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public Uri insert(Uri url, ContentValues initialValues) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri url, String mode) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @Override
- public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- public IBinder asBinder() {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-}
/**
* BaseClass for vCard unit tests with utility classes.
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java b/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java
index bfc3158..3cb5b9b 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardVerifier.java
@@ -31,6 +31,7 @@ import android.pim.vcard.VCardParser_V30;
import android.pim.vcard.exception.VCardException;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;
+import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -51,6 +52,8 @@ import java.util.Arrays;
}
/* package */ class VCardVerifier {
+ private static final String LOG_TAG = "VCardVerifier";
+
private class VCardVerifierInternal implements VCardComposer.OneEntryHandler {
public boolean onInit(Context context) {
return true;
@@ -267,10 +270,13 @@ import java.util.Arrays;
final ContentResolver resolver,
final Uri uri, final String selection,
final String[] selectionArgs, final String sortOrder) {
- final ContentProvider provider =
- resolver.acquireContentProviderClient(uri).getLocalContentProvider();
- return ((ExportTestProvider)provider).queryEntities(
- uri, selection, selectionArgs, sortOrder);
+ if (ExportTestResolver.class.equals(resolver.getClass())) {
+ return ((ExportTestResolver)resolver).getProvider().queryEntities(
+ uri, selection, selectionArgs, sortOrder);
+ }
+
+ Log.e(LOG_TAG, "Unexpected provider given.");
+ return null;
}
private Method getMockGetEntityIteratorMethod()
@@ -285,18 +291,19 @@ import java.util.Arrays;
composer.addHandler(mLineVerifier);
composer.addHandler(mVCardVerifierInternal);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
- mTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
+ AndroidTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
}
- mTestCase.assertFalse(composer.isAfterLast());
+ AndroidTestCase.assertFalse(composer.isAfterLast());
try {
while (!composer.isAfterLast()) {
try {
final Method mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
- mTestCase.assertTrue(
- composer.createOneEntry(getMockGetEntityIteratorMethod()));
+ AndroidTestCase.assertNotNull(mockGetEntityIteratorMethod);
+ AndroidTestCase.assertTrue(
+ composer.createOneEntry(mockGetEntityIteratorMethod));
} catch (Exception e) {
e.printStackTrace();
- mTestCase.fail();
+ AndroidTestCase.fail();
}
}
} finally {
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
index 53205bb..a3f094c 100644
--- a/include/media/EffectPresetReverbApi.h
+++ b/include/media/EffectPresetReverbApi.h
@@ -43,7 +43,8 @@ typedef enum
REVERB_PRESET_LARGEROOM,
REVERB_PRESET_MEDIUMHALL,
REVERB_PRESET_LARGEHALL,
- REVERB_PRESET_PLATE
+ REVERB_PRESET_PLATE,
+ REVERB_PRESET_LAST = REVERB_PRESET_PLATE
} t_reverb_presets;
#if __cplusplus
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 6f7dc38..9d2cff6 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -28,6 +28,7 @@
namespace android {
+struct AMessage;
class String8;
class DataSource : public RefBase {
@@ -59,10 +60,14 @@ public:
////////////////////////////////////////////////////////////////////////////
- bool sniff(String8 *mimeType, float *confidence);
+ bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
+ // The sniffer can optionally fill in "meta" with an AMessage containing
+ // a dictionary of values that helps the corresponding extractor initialize
+ // its state without duplicating effort already exerted by the sniffer.
typedef bool (*SnifferFunc)(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType,
+ float *confidence, sp<AMessage> *meta);
static void RegisterSniffer(SnifferFunc func);
static void RegisterDefaultSniffers();
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 1eb178e..d016dfa 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -54,11 +54,6 @@ class SharedClient;
// ----------------------------------------------------------------------------
-// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX
-// 4 * (11 + 7 + (1 + 2*7)*16) * 31
-// 1032 * 31
-// = ~27 KiB (31992)
-
class SharedBufferStack
{
friend class SharedClient;
@@ -85,7 +80,7 @@ public:
};
struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
- static const unsigned int NUM_RECT_MAX = 6;
+ static const unsigned int NUM_RECT_MAX = 5;
uint32_t count;
SmallRect rects[NUM_RECT_MAX];
};
@@ -93,13 +88,18 @@ public:
struct BufferData {
FlatRegion dirtyRegion;
SmallRect crop;
+ uint8_t transform;
+ uint8_t reserved[3];
};
SharedBufferStack();
void init(int32_t identity);
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
+ status_t setTransform(int buffer, uint8_t transform);
Region getDirtyRegion(int buffer) const;
+ Rect getCrop(int buffer) const;
+ uint32_t getTransform(int buffer) const;
// these attributes are part of the conditions/updates
volatile int32_t head; // server's current front buffer
@@ -117,7 +117,7 @@ public:
int32_t reserved32[1];
Statistics stats;
int32_t reserved;
- BufferData buffers[NUM_BUFFER_MAX]; // 960 bytes
+ BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes
};
// ----------------------------------------------------------------------------
@@ -206,7 +206,7 @@ public:
bool needNewBuffer(int buffer) const;
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
-
+ status_t setTransform(int buffer, uint32_t transform);
class SetBufferCountCallback {
friend class SharedBufferClient;
@@ -275,6 +275,8 @@ public:
status_t reallocateAllExcept(int buffer);
int32_t getQueuedCount() const;
Region getDirtyRegion(int buffer) const;
+ Rect getCrop(int buffer) const;
+ uint32_t getTransform(int buffer) const;
status_t resize(int newNumBuffers);
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 294c867..7c5a39b 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -216,6 +216,7 @@ private:
int dispatch_crop(va_list args);
int dispatch_set_buffer_count(va_list args);
int dispatch_set_buffers_geometry(va_list args);
+ int dispatch_set_buffers_transform(va_list args);
void setUsage(uint32_t reqUsage);
int connect(int api);
@@ -223,6 +224,7 @@ private:
int crop(Rect const* rect);
int setBufferCount(int bufferCount);
int setBuffersGeometry(int w, int h, int format);
+ int setBuffersTransform(int transform);
/*
* private stuff...
@@ -278,6 +280,7 @@ private:
Rect mSwapRectangle;
int mConnected;
Rect mNextBufferCrop;
+ uint32_t mNextBufferTransform;
BufferInfo mBufferInfo;
// protected by mSurfaceLock. These are also used from lock/unlock
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index ca89b06..d59d72b 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -85,6 +85,7 @@ enum {
NATIVE_WINDOW_SET_CROP,
NATIVE_WINDOW_SET_BUFFER_COUNT,
NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
};
/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -92,6 +93,20 @@ enum {
NATIVE_WINDOW_API_EGL = 1
};
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
+enum {
+ /* flip source image horizontally */
+ NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
+ /* flip source image vertically */
+ NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+ /* rotate source image 90 degrees clock-wise */
+ NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+ /* rotate source image 180 degrees */
+ NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+ /* rotate source image 270 degrees clock-wise */
+ NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+};
+
struct ANativeWindow
{
#ifdef __cplusplus
@@ -196,6 +211,7 @@ struct ANativeWindow
* NATIVE_WINDOW_SET_CROP
* NATIVE_WINDOW_SET_BUFFER_COUNT
* NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
+ * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
*
*/
@@ -298,6 +314,19 @@ static inline int native_window_set_buffers_geometry(
w, h, format);
}
+/*
+ * native_window_set_buffers_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified.
+ */
+static inline int native_window_set_buffers_transform(
+ ANativeWindow* window,
+ int transform)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+ transform);
+}
+
// ---------------------------------------------------------------------------
/* FIXME: this is legacy for pixmaps */
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 156a7db..4ad9f86 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -75,6 +75,14 @@ status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
return NO_ERROR;
}
+status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+ buffers[buffer].transform = transform;
+ return NO_ERROR;
+}
+
status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
@@ -137,6 +145,26 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const
return res;
}
+Rect SharedBufferStack::getCrop(int buffer) const
+{
+ Rect res(-1, -1);
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+ res.left = buffers[buffer].crop.l;
+ res.top = buffers[buffer].crop.t;
+ res.right = buffers[buffer].crop.r;
+ res.bottom = buffers[buffer].crop.b;
+ return res;
+}
+
+uint32_t SharedBufferStack::getTransform(int buffer) const
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return 0;
+ return buffers[buffer].transform;
+}
+
+
// ----------------------------------------------------------------------------
SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
@@ -433,6 +461,12 @@ status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
return stack.setCrop(buf, crop);
}
+status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setTransform(buf, uint8_t(transform));
+}
+
status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
{
SharedBufferStack& stack( *mSharedStack );
@@ -549,6 +583,18 @@ Region SharedBufferServer::getDirtyRegion(int buf) const
return stack.getDirtyRegion(buf);
}
+Rect SharedBufferServer::getCrop(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getCrop(buf);
+}
+
+uint32_t SharedBufferServer::getTransform(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getTransform(buf);
+}
+
/*
* NOTE: this is not thread-safe on the server-side, meaning
* 'head' cannot move during this operation. The client-side
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 5ab72cd..cb76091 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -422,8 +422,10 @@ void Surface::init()
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+ mNextBufferTransform = 0;
mConnected = 0;
mSwapRectangle.makeInvalid();
+ mNextBufferCrop = Rect(0,0);
// two buffers by default
mBuffers.setCapacity(2);
mBuffers.insertAt(0, 2);
@@ -631,6 +633,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+ mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
err = mSharedBufferClient->queue(bufIdx);
@@ -685,6 +688,9 @@ int Surface::perform(int operation, va_list args)
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
res = dispatch_set_buffers_geometry( args );
break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatch_set_buffers_transform( args );
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -719,6 +725,11 @@ int Surface::dispatch_set_buffers_geometry(va_list args) {
return setBuffersGeometry(w, h, f);
}
+int Surface::dispatch_set_buffers_transform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
void Surface::setUsage(uint32_t reqUsage)
{
Mutex::Autolock _l(mSurfaceLock);
@@ -765,6 +776,10 @@ int Surface::disconnect(int api)
int Surface::crop(Rect const* rect)
{
+ // empty/invalid rects are not allowed
+ if (rect->isEmpty())
+ return BAD_VALUE;
+
Mutex::Autolock _l(mSurfaceLock);
// TODO: validate rect size
mNextBufferCrop = *rect;
@@ -804,6 +819,13 @@ int Surface::setBuffersGeometry(int w, int h, int format)
return NO_ERROR;
}
+int Surface::setBuffersTransform(int transform)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mNextBufferTransform = transform;
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
int Surface::getConnectedApi() const
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 798271e..d856eb4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "Bundle"
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#include <cutils/log.h>
#include <assert.h>
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 2043e44..03f1409 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "Reverb"
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#include <cutils/log.h>
#include <assert.h>
@@ -61,42 +61,81 @@ namespace {
/* Preset definitions */
/* */
/************************************************************************************/
-LVM_UINT16 RevPreset_Level[] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
-LVM_UINT16 RevPreset_LPF[] = {1298, 1000, 5012, 3542, 3400, 23999, 2536, 1000, 1000, 1000};
-LVM_UINT16 RevPreset_HPF[] = { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};
-LVM_UINT16 RevPreset_T60[] = {1490, 500, 2310, 4230, 3920, 2910, 7000, 1490, 1490, 170};
-LVM_UINT16 RevPreset_Density[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
-LVM_UINT16 RevPreset_Damping[] = { 54, 10, 64, 59, 70, 100, 33, 54, 21, 10};
-LVM_UINT16 RevPreset_RoomSize[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
-/************************************************************************************/
-/* */
-/* Preset definitions */
-/* */
-/************************************************************************************/
-#define REV_PRESET_BATHROOM 0
-#define REV_PRESET_LIVINGROOM 1
-#define REV_PRESET_STONEROOM 2
-#define REV_PRESET_AUDITORIUM 3
-#define REV_PRESET_CONCERTHALL 4
-#define REV_PRESET_CAVE 5
-#define REV_PRESET_ARENA 6
-#define REV_PRESET_FOREST 7
-#define REV_PRESET_MOUNTAINS 8
-#define REV_PRESET_PADDEDCELL 9
-
-// NXP SW Reverb UUID
-const effect_descriptor_t gReverbDescriptor = {
+const static t_reverb_settings sReverbPresets[] = {
+ // REVERB_PRESET_NONE: values are unused
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ // REVERB_PRESET_SMALLROOM
+ {-1000, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000},
+ // REVERB_PRESET_MEDIUMROOM
+ {-1000, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000},
+ // REVERB_PRESET_LARGEROOM
+ {-1000, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000},
+ // REVERB_PRESET_MEDIUMHALL
+ {-1000, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000},
+ // REVERB_PRESET_LARGEHALL
+ {-1000, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000},
+ // REVERB_PRESET_PLATE
+ {-1000, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
+};
+
+
+// NXP SW auxiliary environmental reverb
+const effect_descriptor_t gAuxEnvReverbDescriptor = {
{ 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
{ 0x4a387fc0, 0x8ab3, 0x11df, 0x8bad, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
EFFECT_API_VERSION,
- (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_INSERT_LAST),
+ EFFECT_FLAG_TYPE_AUXILIARY,
+ 0, // TODO
+ 1,
+ "Auxiliary Environmental Reverb",
+ "NXP Software Ltd.",
+};
+
+// NXP SW insert environmental reverb
+static const effect_descriptor_t gInsertEnvReverbDescriptor = {
+ {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+ {0xc7a511a0, 0xa3bb, 0x11df, 0x860e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
0, // TODO
1,
- "Reverb",
+ "Insert Environmental Reverb",
"NXP Software Ltd.",
};
+// NXP SW auxiliary preset reverb
+static const effect_descriptor_t gAuxPresetReverbDescriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_AUXILIARY,
+ 0, // TODO
+ 1,
+ "Auxiliary Preset Reverb",
+ "NXP Software Ltd.",
+};
+
+// NXP SW insert preset reverb
+static const effect_descriptor_t gInsertPresetReverbDescriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+ 0, // TODO
+ 1,
+ "Insert Preset Reverb",
+ "NXP Software Ltd.",
+};
+
+// gDescriptors contains pointers to all defined effect descriptor in this library
+static const effect_descriptor_t * const gDescriptors[] = {
+ &gAuxEnvReverbDescriptor,
+ &gInsertEnvReverbDescriptor,
+ &gAuxPresetReverbDescriptor,
+ &gInsertPresetReverbDescriptor
+};
+
struct ReverbContext{
const struct effect_interface_s *itfe;
effect_config_t config;
@@ -114,8 +153,14 @@ struct ReverbContext{
FILE *PcmOutPtr;
#endif
LVM_Fs_en SampleRate;
+ bool auxiliary;
+ bool preset;
+ uint16_t curPreset;
+ uint16_t nextPreset;
};
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_MEDIUMROOM
+
//--- local function prototypes
int Reverb_init (ReverbContext *pContext);
void Reverb_free (ReverbContext *pContext);
@@ -125,11 +170,12 @@ int Reverb_getParameter (ReverbContext *pContext,
void *pParam,
size_t *pValueSize,
void *pValue);
+int Reverb_LoadPreset (ReverbContext *pContext);
/* Effect Library Interface Implementation */
extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects){
LOGV("\n\tEffectQueryNumberEffects start");
- *pNumEffects = 1;
+ *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
LOGV("\tEffectQueryNumberEffects creating %d effects", *pNumEffects);
LOGV("\tEffectQueryNumberEffects end\n");
return 0;
@@ -142,11 +188,11 @@ extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescripto
LOGV("\tLVM_ERROR : EffectQueryEffect was passed NULL pointer");
return -EINVAL;
}
- if (index > 0){
+ if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) {
LOGV("\tLVM_ERROR : EffectQueryEffect index out of range %d", index);
return -ENOENT;
}
- memcpy(pDescriptor, &gReverbDescriptor, sizeof(effect_descriptor_t));
+ memcpy(pDescriptor, gDescriptors[index], sizeof(effect_descriptor_t));
LOGV("\tEffectQueryEffect end\n");
return 0;
} /* end EffectQueryEffect */
@@ -157,6 +203,8 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
effect_interface_t *pInterface){
int ret;
int i;
+ int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
+ const effect_descriptor_t *desc;
LOGV("\t\nEffectCreate start");
@@ -165,9 +213,16 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
return -EINVAL;
}
- if (memcmp(uuid, &gReverbDescriptor.uuid, sizeof(effect_uuid_t)) != 0){
- LOGV("\tLVM_ERROR : EffectCreate() invalid UUID");
- return -EINVAL;
+ for (i = 0; i < length; i++) {
+ desc = gDescriptors[i];
+ if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t))
+ == 0) {
+ break;
+ }
+ }
+
+ if (i == length) {
+ return -ENOENT;
}
ReverbContext *pContext = new ReverbContext;
@@ -175,6 +230,19 @@ extern "C" int EffectCreate(effect_uuid_t *uuid,
pContext->itfe = &gReverbInterface;
pContext->hInstance = NULL;
+ pContext->auxiliary = false;
+ if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY){
+ pContext->auxiliary = true;
+ }
+
+ pContext->preset = false;
+ if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
+ pContext->preset = true;
+ // force reloading preset at first call to process()
+ pContext->curPreset = REVERB_PRESET_LAST + 1;
+ pContext->nextPreset = REVERB_DEFAULT_PRESET;
+ }
+
LOGV("\tEffectCreate - Calling Reverb_init");
ret = Reverb_init(pContext);
@@ -288,6 +356,14 @@ void From2iToMono_32( const LVM_INT32 *src,
return;
}
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
//----------------------------------------------------------------------------
// process()
//----------------------------------------------------------------------------
@@ -344,6 +420,9 @@ int process( LVM_INT16 *pIn,
fflush(pContext->PcmInPtr);
#endif
+ if (pContext->preset && pContext->nextPreset != pContext->curPreset) {
+ Reverb_LoadPreset(pContext);
+ }
// Convert to Input 32 bits
for(int i=0; i<frameCount*samplesPerFrame; i++){
InFrames32[i] = (LVM_INT32)pIn[i]<<8;
@@ -359,18 +438,28 @@ int process( LVM_INT16 *pIn,
//frameCount, pContext->config.inputCfg.channels, CHANNEL_MONO,
//pContext->config.outputCfg.channels, CHANNEL_STEREO);
+ if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
+ memset(OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2);
+ } else {
/* Process the samples */
LvmStatus = LVREV_Process(pContext->hInstance, /* Instance handle */
InFrames32, /* Input buffer */
OutFrames32, /* Output buffer */
frameCount); /* Number of samples to read */
+ }
+
+ if (!pContext->auxiliary) {
+ for (int i=0; i<frameCount*2; i++){
+ OutFrames32[i] += InFrames32[i];
+ }
+ }
LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
// Convert to 16 bits
for(int i=0; i<frameCount*2; i++){ // Always stereo
- OutFrames16[i] = (LVM_INT16)(OutFrames32[i]>>8);
+ OutFrames16[i] = clamp16(OutFrames32[i]>>8);
}
#ifdef LVM_PCM
@@ -382,7 +471,7 @@ int process( LVM_INT16 *pIn,
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
//LOGV("\tBuffer access is ACCUMULATE");
for (int i=0; i<frameCount*2; i++){
- pOut[i] += OutFrames16[i];
+ pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
}
}else{
//LOGV("\tBuffer access is WRITE");
@@ -462,6 +551,8 @@ int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){
CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate);
CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format);
+ CHECK_ARG((pContext->auxiliary && pConfig->inputCfg.channels == CHANNEL_MONO) ||
+ ((!pContext->auxiliary) && pConfig->inputCfg.channels == CHANNEL_STEREO));
CHECK_ARG(pConfig->outputCfg.channels == CHANNEL_STEREO);
CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
|| pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
@@ -540,18 +631,8 @@ int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){
int Reverb_init(ReverbContext *pContext){
int status;
- int channel_mode;
- LOGV("\tReverb_init start %d", gReverbDescriptor.flags);
-
- if((gReverbDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT){
- LOGV("\tReverb_init EFFECT_FLAG_TYPE_INSERT");
- channel_mode = CHANNEL_STEREO;
- }
- if((gReverbDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY ){
- LOGV("\tReverb_init EFFECT_FLAG_TYPE_AUXILIARY");
- channel_mode = CHANNEL_MONO;
- }
+ LOGV("\tReverb_init start");
CHECK_ARG(pContext != NULL);
@@ -560,7 +641,12 @@ int Reverb_init(ReverbContext *pContext){
}
pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
- pContext->config.inputCfg.channels = channel_mode;
+ if (pContext->auxiliary) {
+ pContext->config.inputCfg.channels = CHANNEL_MONO;
+ } else {
+ pContext->config.inputCfg.channels = CHANNEL_STEREO;
+ }
+
pContext->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
pContext->config.inputCfg.samplingRate = 44100;
pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
@@ -653,11 +739,11 @@ int Reverb_init(ReverbContext *pContext){
/* Reverb parameters */
params.Level = 0;
params.LPF = 23999;
- params.HPF = RevPreset_HPF[REV_PRESET_MOUNTAINS];
- params.T60 = RevPreset_T60[REV_PRESET_MOUNTAINS];
- params.Density = RevPreset_Density[REV_PRESET_MOUNTAINS];
- params.Damping = RevPreset_Damping[REV_PRESET_MOUNTAINS];
- params.RoomSize = RevPreset_RoomSize[REV_PRESET_MOUNTAINS];
+ params.HPF = 50;
+ params.T60 = 1490;
+ params.Density = 100;
+ params.Damping = 21;
+ params.RoomSize = 100;
/* Saved strength is used to return the exact strength that was used in the set to the get
* because we map the original strength range of 0:1000 to 1:15, and this will avoid
@@ -1294,6 +1380,44 @@ int32_t ReverbGetDensity(ReverbContext *pContext){
}
//----------------------------------------------------------------------------
+// Reverb_LoadPreset()
+//----------------------------------------------------------------------------
+// Purpose:
+// Load a the next preset
+//
+// Inputs:
+// pContext - handle to instance data
+//
+// Outputs:
+//
+// Side Effects:
+//
+//----------------------------------------------------------------------------
+int Reverb_LoadPreset(ReverbContext *pContext)
+{
+ //TODO: add reflections delay, level and reverb delay when early reflections are
+ // implemented
+ pContext->curPreset = pContext->nextPreset;
+
+ if (pContext->curPreset != REVERB_PRESET_NONE) {
+ const t_reverb_settings *preset = &sReverbPresets[pContext->curPreset];
+ ReverbSetRoomLevel(pContext, preset->roomLevel);
+ ReverbSetRoomHfLevel(pContext, preset->roomHFLevel);
+ ReverbSetDecayTime(pContext, preset->decayTime);
+ ReverbSetDecayHfRatio(pContext, preset->decayHFRatio);
+ //reflectionsLevel
+ //reflectionsDelay
+ ReverbSetReverbLevel(pContext, preset->reverbLevel);
+ // reverbDelay
+ ReverbSetDiffusion(pContext, preset->diffusion);
+ ReverbSetDensity(pContext, preset->density);
+ }
+
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------
// Reverb_getParameter()
//----------------------------------------------------------------------------
// Purpose:
@@ -1325,6 +1449,15 @@ int Reverb_getParameter(ReverbContext *pContext,
t_reverb_settings *pProperties;
//LOGV("\tReverb_getParameter start");
+ if (pContext->preset) {
+ if (param != REVERB_PARAM_PRESET || *pValueSize < sizeof(uint16_t)) {
+ return -EINVAL;
+ }
+
+ *(uint16_t *)pValue = pContext->nextPreset;
+ LOGV("get REVERB_PARAM_PRESET, preset %d", pContext->nextPreset);
+ return 0;
+ }
switch (param){
case REVERB_PARAM_ROOM_LEVEL:
@@ -1531,6 +1664,18 @@ int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue){
int32_t param = *pParamTemp++;
//LOGV("\tReverb_setParameter start");
+ if (pContext->preset) {
+ if (param != REVERB_PARAM_PRESET) {
+ return -EINVAL;
+ }
+
+ uint16_t preset = *(uint16_t *)pValue;
+ LOGV("set REVERB_PARAM_PRESET, preset %d", preset);
+ if (preset > REVERB_PRESET_LAST) {
+ return -EINVAL;
+ }
+ pContext->nextPreset = preset;
+ }
switch (param){
case REVERB_PARAM_PROPERTIES:
diff --git a/media/libmedia/fixedfft.cpp b/media/libmedia/fixedfft.cpp
index 28eb05a..9cf05ba 100644
--- a/media/libmedia/fixedfft.cpp
+++ b/media/libmedia/fixedfft.cpp
@@ -26,7 +26,9 @@
#include <stdio.h>
#include <stdint.h>
+#ifdef __ARM_ARCH__
#include <machine/cpu-features.h>
+#endif
#define LOG_FFT_SIZE 10
#define MAX_FFT_SIZE (1 << LOG_FFT_SIZE)
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 70af2da..1b05528 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -87,7 +87,7 @@ AMRExtractor::AMRExtractor(const sp<DataSource> &source)
mInitCheck(NO_INIT) {
String8 mimeType;
float confidence;
- if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
+ if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
return;
}
@@ -276,7 +276,8 @@ status_t AMRSource::read(
////////////////////////////////////////////////////////////////////////////////
bool SniffAMR(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
char header[9];
if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 11fdf56..a0cd5c3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -458,27 +458,34 @@ void AwesomePlayer::onBufferingUpdate() {
return;
}
+ bool eos;
+ size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
+
size_t lowWatermark = 400000;
size_t highWatermark = 1000000;
- off_t size;
- if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
- int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
+ if (eos) {
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+ } else {
+ off_t size;
+ if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
+ int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
- size_t cachedSize = mCachedSource->cachedSize();
- int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+ size_t cachedSize = mCachedSource->cachedSize();
+ int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
- double percentage = (double)cachedDurationUs / mDurationUs;
+ int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+ if (percentage > 100) {
+ percentage = 100;
+ }
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- lowWatermark = 2 * bitrate / 8; // 2 secs
- highWatermark = 10 * bitrate / 8; // 10 secs
+ lowWatermark = 2 * bitrate / 8; // 2 secs
+ highWatermark = 10 * bitrate / 8; // 10 secs
+ }
}
- bool eos;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
-
if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
LOGI("cache is running low (< %d) , pausing.", lowWatermark);
mFlags |= CACHE_UNDERRUN;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 90a596c..49eac62 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -25,6 +25,7 @@
#include "matroska/MatroskaExtractor.h"
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaErrors.h>
@@ -56,19 +57,23 @@ status_t DataSource::getSize(off_t *size) {
Mutex DataSource::gSnifferMutex;
List<DataSource::SnifferFunc> DataSource::gSniffers;
-bool DataSource::sniff(String8 *mimeType, float *confidence) {
+bool DataSource::sniff(
+ String8 *mimeType, float *confidence, sp<AMessage> *meta) {
*mimeType = "";
*confidence = 0.0f;
+ meta->clear();
Mutex::Autolock autoLock(gSnifferMutex);
for (List<SnifferFunc>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
String8 newMimeType;
float newConfidence;
- if ((*it)(this, &newMimeType, &newConfidence)) {
+ sp<AMessage> newMeta;
+ if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
if (newConfidence > *confidence) {
*mimeType = newMimeType;
*confidence = newConfidence;
+ *meta = newMeta;
}
}
}
@@ -92,13 +97,13 @@ void DataSource::RegisterSniffer(SnifferFunc func) {
// static
void DataSource::RegisterDefaultSniffers() {
- RegisterSniffer(SniffMP3);
RegisterSniffer(SniffMPEG4);
- RegisterSniffer(SniffAMR);
- RegisterSniffer(SniffWAV);
- RegisterSniffer(SniffOgg);
RegisterSniffer(SniffMatroska);
+ RegisterSniffer(SniffOgg);
+ RegisterSniffer(SniffWAV);
+ RegisterSniffer(SniffAMR);
RegisterSniffer(SniffMPEG2TS);
+ RegisterSniffer(SniffMP3);
}
// static
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 4058fbc..2e36968 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -22,6 +22,7 @@
#include "include/ID3.h"
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
@@ -456,15 +457,31 @@ private:
MP3Source &operator=(const MP3Source &);
};
-MP3Extractor::MP3Extractor(const sp<DataSource> &source)
+MP3Extractor::MP3Extractor(
+ const sp<DataSource> &source, const sp<AMessage> &meta)
: mDataSource(source),
mFirstFramePos(-1),
mFixedHeader(0),
mByteNumber(0) {
off_t pos = 0;
uint32_t header;
- bool success = Resync(mDataSource, 0, &pos, &header);
- CHECK(success);
+ bool success;
+
+ int64_t meta_offset;
+ uint32_t meta_header;
+ if (meta != NULL
+ && meta->findInt64("offset", &meta_offset)
+ && meta->findInt32("header", (int32_t *)&meta_header)) {
+ // The sniffer has already done all the hard work for us, simply
+ // accept its judgement.
+ pos = (off_t)meta_offset;
+ header = meta_header;
+
+ success = true;
+ } else {
+ success = Resync(mDataSource, 0, &pos, &header);
+ CHECK(success);
+ }
if (success) {
mFirstFramePos = pos;
@@ -759,15 +776,20 @@ sp<MetaData> MP3Extractor::getMetaData() {
}
bool SniffMP3(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType,
+ float *confidence, sp<AMessage> *meta) {
off_t pos = 0;
uint32_t header;
if (!Resync(source, 0, &pos, &header)) {
return false;
}
+ *meta = new AMessage;
+ (*meta)->setInt64("offset", pos);
+ (*meta)->setInt32("header", header);
+
*mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
- *confidence = 0.3f;
+ *confidence = 0.2f;
return true;
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 12a1e6e..ba90407 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1738,7 +1738,7 @@ static bool LegacySniffMPEG4(
|| !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
|| !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
- *confidence = 0.1;
+ *confidence = 0.4;
return true;
}
@@ -1805,13 +1805,14 @@ static bool BetterSniffMPEG4(
}
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
- *confidence = 0.3f;
+ *confidence = 0.4f;
return true;
}
bool SniffMPEG4(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
if (BetterSniffMPEG4(source, mimeType, confidence)) {
return true;
}
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 56e6136..9bc94de 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -27,6 +27,7 @@
#include "matroska/MatroskaExtractor.h"
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
@@ -46,10 +47,12 @@ uint32_t MediaExtractor::flags() const {
// static
sp<MediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
+ sp<AMessage> meta;
+
String8 tmp;
if (mime == NULL) {
float confidence;
- if (!source->sniff(&tmp, &confidence)) {
+ if (!source->sniff(&tmp, &confidence, &meta)) {
LOGV("FAILED to autodetect media content.");
return NULL;
@@ -64,7 +67,7 @@ sp<MediaExtractor> MediaExtractor::Create(
|| !strcasecmp(mime, "audio/mp4")) {
return new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
- return new MP3Extractor(source);
+ return new MP3Extractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
return new AMRExtractor(source);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 9630092..2c1311a 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -804,7 +804,8 @@ sp<MetaData> OggExtractor::getMetaData() {
}
bool SniffOgg(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
char tmp[4];
if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
return false;
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 8d820c0..57c1075 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -404,7 +404,8 @@ status_t WAVSource::read(
////////////////////////////////////////////////////////////////////////////////
bool SniffWAV(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
char header[12];
if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return false;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index ca0c68c..da340f7 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -142,11 +142,22 @@ struct id3_header {
mSize = size;
if (source->readAt(sizeof(header), mData, mSize) != (ssize_t)mSize) {
+ free(mData);
+ mData = NULL;
+
return false;
}
- if (header.flags & 0x80) {
+ if (header.version_major == 4) {
+ if (!removeUnsynchronizationV2_4()) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+ } else if (header.flags & 0x80) {
LOGV("removing unsynchronization");
+
removeUnsynchronization();
}
@@ -243,6 +254,74 @@ void ID3::removeUnsynchronization() {
}
}
+static void WriteSyncsafeInteger(uint8_t *dst, size_t x) {
+ for (size_t i = 0; i < 4; ++i) {
+ dst[3 - i] = (x & 0x7f);
+ x >>= 7;
+ }
+}
+
+bool ID3::removeUnsynchronizationV2_4() {
+ size_t oldSize = mSize;
+
+ size_t offset = 0;
+ while (offset + 10 <= mSize) {
+ if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
+ break;
+ }
+
+ size_t dataSize;
+ if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) {
+ return false;
+ }
+
+ if (offset + dataSize + 10 > mSize) {
+ return false;
+ }
+
+ uint16_t flags = U16_AT(&mData[offset + 8]);
+ uint16_t prevFlags = flags;
+
+ if (flags & 1) {
+ // Strip data length indicator
+
+ memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
+ mSize -= 4;
+ dataSize -= 4;
+
+ flags &= ~1;
+ }
+
+ if (flags & 2) {
+ // Unsynchronization added.
+
+ for (size_t i = 0; i + 1 < dataSize; ++i) {
+ if (mData[offset + 10 + i] == 0xff
+ && mData[offset + 11 + i] == 0x00) {
+ memmove(&mData[offset + 11 + i], &mData[offset + 12 + i],
+ mSize - offset - 12 - i);
+ --mSize;
+ --dataSize;
+ }
+ }
+
+ flags &= ~2;
+ }
+
+ if (flags != prevFlags) {
+ WriteSyncsafeInteger(&mData[offset + 4], dataSize);
+ mData[offset + 8] = flags >> 8;
+ mData[offset + 9] = flags & 0xff;
+ }
+
+ offset += 10 + dataSize;
+ }
+
+ memset(&mData[mSize], 0, oldSize - mSize);
+
+ return true;
+}
+
ID3::Iterator::Iterator(const ID3 &parent, const char *id)
: mParent(parent),
mID(NULL),
@@ -529,10 +608,11 @@ void ID3::Iterator::findFrame() {
uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]);
- if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000e))
+ if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c))
|| (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) {
- // Compression, Encryption or per-Frame unsynchronization
- // are not supported at this time.
+ // Compression or encryption are not supported at this time.
+ // Per-frame unsynchronization and data-length indicator
+ // have already been taken care of.
LOGV("Skipping unsupported frame (compression, encryption "
"or per-frame unsynchronization flagged");
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index db49fe4..1cdf36d 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -22,6 +22,7 @@
namespace android {
+struct AMessage;
class String8;
class AMRExtractor : public MediaExtractor {
@@ -49,7 +50,8 @@ private:
};
bool SniffAMR(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index c6b1a8b..7ddbb41 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -80,6 +80,7 @@ private:
bool parseV1(const sp<DataSource> &source);
bool parseV2(const sp<DataSource> &source);
void removeUnsynchronization();
+ bool removeUnsynchronizationV2_4();
static bool ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x);
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 3ce6df3..0e6ccde 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -22,13 +22,14 @@
namespace android {
+struct AMessage;
class DataSource;
class String8;
class MP3Extractor : public MediaExtractor {
public:
// Extractor assumes ownership of "source".
- MP3Extractor(const sp<DataSource> &source);
+ MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
@@ -52,7 +53,8 @@ private:
};
bool SniffMP3(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *meta);
} // namespace android
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index c96973b..1bf4cd1 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -9,6 +9,7 @@
namespace android {
+struct AMessage;
struct AnotherPacketSource;
struct ATSParser;
struct DataSource;
@@ -47,7 +48,8 @@ private:
};
bool SniffMPEG2TS(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index c8663d5..1c9cc7e 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -23,6 +23,7 @@
namespace android {
+struct AMessage;
class DataSource;
class SampleTable;
class String8;
@@ -75,7 +76,8 @@ private:
};
bool SniffMPEG4(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index 7066669..1eda025 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -22,6 +22,7 @@
namespace android {
+struct AMessage;
class DataSource;
class String8;
@@ -53,7 +54,8 @@ private:
};
bool SniffOgg(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 3e847b9..df6d3e7 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -22,6 +22,7 @@
namespace android {
+struct AMessage;
class DataSource;
class String8;
@@ -58,7 +59,8 @@ private:
};
bool SniffWAV(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 71f6587..7c7d69e 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -579,7 +579,8 @@ sp<MetaData> MatroskaExtractor::getMetaData() {
}
bool SniffMatroska(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
DataSourceReader reader(source);
mkvparser::EBMLHeader ebmlHeader;
long long pos;
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 7471848..fa20b84 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -27,6 +27,7 @@ struct Segment;
namespace android {
+struct AMessage;
class String8;
struct DataSourceReader;
@@ -69,7 +70,8 @@ private:
};
bool SniffMatroska(
- const sp<DataSource> &source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
} // namespace android
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index b287c95..56ca375 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -174,7 +174,8 @@ status_t MPEG2TSExtractor::feedMore() {
////////////////////////////////////////////////////////////////////////////////
bool SniffMPEG2TS(
- const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
#if 0
char header;
if (source->readAt(0, &header, 1) != 1 || header != 0x47) {
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 185d72a..8349fe6 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -47,7 +47,8 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport" translatable="false"></string>
+ <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string>
+
<!-- Default value for whether or not to pulse the notification LED when there is a
pending notification -->
<bool name="def_notification_pulse">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2e95932..81d82de 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -22,6 +22,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import android.app.backup.BackupManager;
import android.content.ContentProvider;
@@ -37,6 +39,7 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.provider.DrmStore;
@@ -56,9 +59,15 @@ public class SettingsProvider extends ContentProvider {
// Cache for settings, access-ordered for acting as LRU.
// Guarded by themselves.
- private static final int MAX_CACHE_ENTRIES = 50;
- private static final SettingsCache sSystemCache = new SettingsCache();
- private static final SettingsCache sSecureCache = new SettingsCache();
+ private static final int MAX_CACHE_ENTRIES = 200;
+ private static final SettingsCache sSystemCache = new SettingsCache("system");
+ private static final SettingsCache sSecureCache = new SettingsCache("secure");
+
+ // The count of how many known (handled by SettingsProvider)
+ // database mutations are currently being handled. Used by
+ // sFileObserver to not reload the database when it's ourselves
+ // modifying it.
+ private static final AtomicInteger sKnownMutationsInFlight = new AtomicInteger(0);
// Over this size we don't reject loading or saving settings but
// we do consider them broken/malicious and don't keep them in
@@ -67,6 +76,10 @@ public class SettingsProvider extends ContentProvider {
private static final Bundle NULL_SETTING = Bundle.forPair("value", null);
+ // Used as a sentinel value in an instance equality test when we
+ // want to cache the existence of a key, but not store its value.
+ private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
+
protected DatabaseHelper mOpenHelper;
private BackupManager mBackupManager;
@@ -201,6 +214,43 @@ public class SettingsProvider extends ContentProvider {
}
}
+ // FileObserver for external modifications to the database file.
+ // Note that this is for platform developers only with
+ // userdebug/eng builds who should be able to tinker with the
+ // sqlite database out from under the SettingsProvider, which is
+ // normally the exclusive owner of the database. But we keep this
+ // enabled all the time to minimize development-vs-user
+ // differences in testing.
+ private static SettingsFileObserver sObserverInstance;
+ private class SettingsFileObserver extends FileObserver {
+ private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
+ private final String mPath;
+
+ public SettingsFileObserver(String path) {
+ super(path, FileObserver.CLOSE_WRITE |
+ FileObserver.CREATE | FileObserver.DELETE |
+ FileObserver.MOVED_TO | FileObserver.MODIFY);
+ mPath = path;
+ }
+
+ public void onEvent(int event, String path) {
+ int modsInFlight = sKnownMutationsInFlight.get();
+ if (modsInFlight > 0) {
+ // our own modification.
+ return;
+ }
+ Log.d(TAG, "external modification to " + mPath + "; event=" + event);
+ if (!mIsDirty.compareAndSet(false, true)) {
+ // already handled. (we get a few update events
+ // during an sqlite write)
+ return;
+ }
+ Log.d(TAG, "updating our caches for " + mPath);
+ fullyPopulateCaches();
+ mIsDirty.set(false);
+ }
+ }
+
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
@@ -210,9 +260,65 @@ public class SettingsProvider extends ContentProvider {
return false;
}
+ // Watch for external modifications to the database file,
+ // keeping our cache in sync.
+ // It's kinda lame to call mOpenHelper.getReadableDatabase()
+ // during onCreate(), but since ensureAndroidIdIsSet has
+ // already done it above and initialized/upgraded the
+ // database, might as well just use it...
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ sObserverInstance = new SettingsFileObserver(db.getPath());
+ sObserverInstance.startWatching();
+ startAsyncCachePopulation();
return true;
}
+ private void startAsyncCachePopulation() {
+ new Thread("populate-settings-caches") {
+ public void run() {
+ fullyPopulateCaches();
+ }
+ }.start();
+ }
+
+ private void fullyPopulateCaches() {
+ fullyPopulateCache("secure", sSecureCache);
+ fullyPopulateCache("system", sSystemCache);
+ }
+
+ // Slurp all values (if sane in number & size) into cache.
+ private void fullyPopulateCache(String table, SettingsCache cache) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor c = db.query(
+ table,
+ new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
+ null, null, null, null, null,
+ "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
+ try {
+ synchronized (cache) {
+ cache.clear();
+ cache.setFullyMatchesDisk(true); // optimistic
+ int rows = 0;
+ while (c.moveToNext()) {
+ rows++;
+ String name = c.getString(0);
+ String value = c.getString(1);
+ cache.populate(name, value);
+ }
+ if (rows > MAX_CACHE_ENTRIES) {
+ // Somewhat redundant, as removeEldestEntry() will
+ // have already done this, but to be explicit:
+ cache.setFullyMatchesDisk(false);
+ Log.d(TAG, "row count exceeds max cache entries for table " + table);
+ }
+ Log.d(TAG, "cache for settings table '" + table + "' fullycached=" +
+ cache.fullyMatchesDisk());
+ }
+ } finally {
+ c.close();
+ }
+ }
+
private boolean ensureAndroidIdIsSet() {
final Cursor c = query(Settings.Secure.CONTENT_URI,
new String[] { Settings.NameValueTable.VALUE },
@@ -262,7 +368,19 @@ public class SettingsProvider extends ContentProvider {
private Bundle lookupValue(String table, SettingsCache cache, String key) {
synchronized (cache) {
if (cache.containsKey(key)) {
- return cache.get(key);
+ Bundle value = cache.get(key);
+ if (value != TOO_LARGE_TO_CACHE_MARKER) {
+ return value;
+ }
+ // else we fall through and read the value from disk
+ } else if (cache.fullyMatchesDisk()) {
+ // Fast path (very common). Don't even try touch disk
+ // if we know we've slurped it all in. Trying to
+ // touch the disk would mean waiting for yaffs2 to
+ // give us access, which could takes hundreds of
+ // milliseconds. And we're very likely being called
+ // from somebody's UI thread...
+ return NULL_SETTING;
}
}
@@ -338,6 +456,7 @@ public class SettingsProvider extends ContentProvider {
checkWritePermissions(args);
SettingsCache cache = SettingsCache.forTable(args.table);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
@@ -350,6 +469,7 @@ public class SettingsProvider extends ContentProvider {
db.setTransactionSuccessful();
} finally {
db.endTransaction();
+ sKnownMutationsInFlight.decrementAndGet();
}
sendNotify(uri);
@@ -449,8 +569,10 @@ public class SettingsProvider extends ContentProvider {
return Uri.withAppendedPath(url, name);
}
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final long rowId = db.insert(args.table, null, initialValues);
+ sKnownMutationsInFlight.decrementAndGet();
if (rowId <= 0) return null;
SettingsCache.populate(cache, initialValues); // before we notify
@@ -471,12 +593,15 @@ public class SettingsProvider extends ContentProvider {
}
checkWritePermissions(args);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.delete(args.table, args.where, args.args);
+ sKnownMutationsInFlight.decrementAndGet();
if (count > 0) {
SettingsCache.wipe(args.table); // before we notify
sendNotify(url);
}
+ startAsyncCachePopulation();
if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
return count;
}
@@ -489,12 +614,15 @@ public class SettingsProvider extends ContentProvider {
}
checkWritePermissions(args);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ sKnownMutationsInFlight.decrementAndGet();
int count = db.update(args.table, initialValues, args.where, args.args);
if (count > 0) {
SettingsCache.wipe(args.table); // before we notify
sendNotify(url);
}
+ startAsyncCachePopulation();
if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
return count;
}
@@ -506,12 +634,12 @@ public class SettingsProvider extends ContentProvider {
* When a client attempts to openFile the default ringtone or
* notification setting Uri, we will proxy the call to the current
* default ringtone's Uri (if it is in the DRM or media provider).
- */
+ */
int ringtoneType = RingtoneManager.getDefaultType(uri);
// Above call returns -1 if the Uri doesn't match a default type
if (ringtoneType != -1) {
Context context = getContext();
-
+
// Get the current value for the default sound
Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
@@ -531,7 +659,7 @@ public class SettingsProvider extends ContentProvider {
throw new FileNotFoundException(e.getMessage());
}
}
-
+
return context.getContentResolver().openFileDescriptor(soundUri, mode);
}
}
@@ -607,13 +735,38 @@ public class SettingsProvider extends ContentProvider {
*/
private static final class SettingsCache extends LinkedHashMap<String, Bundle> {
- public SettingsCache() {
+ private final String mCacheName;
+ private boolean mCacheFullyMatchesDisk = false; // has the whole database slurped.
+
+ public SettingsCache(String name) {
super(MAX_CACHE_ENTRIES, 0.75f /* load factor */, true /* access ordered */);
+ mCacheName = name;
+ }
+
+ /**
+ * Is the whole database table slurped into this cache?
+ */
+ public boolean fullyMatchesDisk() {
+ synchronized (this) {
+ return mCacheFullyMatchesDisk;
+ }
+ }
+
+ public void setFullyMatchesDisk(boolean value) {
+ synchronized (this) {
+ mCacheFullyMatchesDisk = value;
+ }
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > MAX_CACHE_ENTRIES;
+ if (size() <= MAX_CACHE_ENTRIES) {
+ return false;
+ }
+ synchronized (this) {
+ mCacheFullyMatchesDisk = false;
+ }
+ return true;
}
/**
@@ -658,11 +811,15 @@ public class SettingsProvider extends ContentProvider {
return;
}
String value = contentValues.getAsString(Settings.NameValueTable.VALUE);
- synchronized (cache) {
+ cache.populate(name, value);
+ }
+
+ public void populate(String name, String value) {
+ synchronized (this) {
if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
- cache.put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
+ put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
} else {
- cache.remove(name);
+ put(name, TOO_LARGE_TO_CACHE_MARKER);
}
}
}
@@ -678,6 +835,7 @@ public class SettingsProvider extends ContentProvider {
}
synchronized (cache) {
cache.clear();
+ cache.mCacheFullyMatchesDisk = true;
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b37cd89..c316074 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -609,8 +609,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* All currently bound service connections. Keys are the IBinder of
* the client's IServiceConnection.
*/
- final HashMap<IBinder, ConnectionRecord> mServiceConnections
- = new HashMap<IBinder, ConnectionRecord>();
+ final HashMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections
+ = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
/**
* List of services that we have been asked to start,
@@ -7376,12 +7376,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mServiceConnections.size() > 0) {
if (needSep) pw.println(" ");
pw.println(" Connection bindings to services:");
- Iterator<ConnectionRecord> it
+ Iterator<ArrayList<ConnectionRecord>> it
= mServiceConnections.values().iterator();
while (it.hasNext()) {
- ConnectionRecord r = it.next();
- pw.print(" * "); pw.println(r);
- r.dump(pw, " ");
+ ArrayList<ConnectionRecord> r = it.next();
+ for (int i=0; i<r.size(); i++) {
+ pw.print(" * "); pw.println(r.get(i));
+ r.get(i).dump(pw, " ");
+ }
}
needSep = true;
}
@@ -7659,18 +7661,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (it.hasNext()) {
ServiceRecord r = it.next();
if (r.connections.size() > 0) {
- Iterator<ConnectionRecord> jt
+ Iterator<ArrayList<ConnectionRecord>> jt
= r.connections.values().iterator();
while (jt.hasNext()) {
- ConnectionRecord c = jt.next();
- if (c.binding.client != app) {
- try {
- //c.conn.connected(r.className, null);
- } catch (Exception e) {
- // todo: this should be asynchronous!
- Slog.w(TAG, "Exception thrown disconnected servce "
- + r.shortName
- + " from app " + app.processName, e);
+ ArrayList<ConnectionRecord> cl = jt.next();
+ for (int i=0; i<cl.size(); i++) {
+ ConnectionRecord c = cl.get(i);
+ if (c.binding.client != app) {
+ try {
+ //c.conn.connected(r.className, null);
+ } catch (Exception e) {
+ // todo: this should be asynchronous!
+ Slog.w(TAG, "Exception thrown disconnected servce "
+ + r.shortName
+ + " from app " + app.processName, e);
+ }
}
}
}
@@ -7700,7 +7705,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
sr.app = null;
sr.executeNesting = 0;
- mStoppingServices.remove(sr);
+ if (mStoppingServices.remove(sr)) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
+ }
boolean hasClients = sr.bindings.size() > 0;
if (hasClients) {
@@ -7753,6 +7760,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord sr = mStoppingServices.get(i);
if (sr.app == app) {
mStoppingServices.remove(i);
+ if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
}
}
@@ -8016,11 +8024,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.app != null && r.app.persistent) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
}
- for (ConnectionRecord conn : r.connections.values()) {
- if (conn.clientLabel != 0) {
- info.clientPackage = conn.binding.client.info.packageName;
- info.clientLabel = conn.clientLabel;
- break;
+
+ for (ArrayList<ConnectionRecord> connl : r.connections.values()) {
+ for (int i=0; i<connl.size(); i++) {
+ ConnectionRecord conn = connl.get(i);
+ if (conn.clientLabel != 0) {
+ info.clientPackage = conn.binding.client.info.packageName;
+ info.clientLabel = conn.clientLabel;
+ return info;
+ }
}
}
return info;
@@ -8055,9 +8067,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
ServiceRecord r = mServices.get(name);
if (r != null) {
- for (ConnectionRecord conn : r.connections.values()) {
- if (conn.clientIntent != null) {
- return conn.clientIntent;
+ for (ArrayList<ConnectionRecord> conn : r.connections.values()) {
+ for (int i=0; i<conn.size(); i++) {
+ if (conn.get(i).clientIntent != null) {
+ return conn.get(i).clientIntent;
+ }
}
}
}
@@ -8234,8 +8248,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
- if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: "
- + r.name + " " + r.intent + " args=" + si.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+ + r + " " + r.intent + " args=" + si.intent);
if (si.intent == null) {
// If somehow we got a dummy start at the front, then
// just drop it here.
@@ -8248,6 +8262,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
r.packageName, si.intent, si);
}
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r);
bumpServiceExecutingLocked(r);
if (!oomAdjusted) {
oomAdjusted = true;
@@ -8264,6 +8279,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
+ if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
break;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
@@ -8280,9 +8296,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r
+ + " in " + i + ": shouldUnbind=" + i.hasBound);
bumpServiceExecutingLocked(r);
- if (DEBUG_SERVICE) Slog.v(TAG, "Connecting binding " + i
- + ": shouldUnbind=" + i.hasBound);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
if (!rebind) {
i.requested = true;
@@ -8290,6 +8306,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
i.hasBound = true;
i.doRebind = false;
} catch (RemoteException e) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
return false;
}
}
@@ -8316,13 +8333,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent);
bumpServiceExecutingLocked(r);
updateLruProcessLocked(app, true, true);
boolean created = false;
try {
- if (DEBUG_SERVICE) Slog.v(TAG, "Scheduling start service: "
- + r.name + " " + r.intent);
mStringBuilder.setLength(0);
r.intent.getIntent().toShortString(mStringBuilder, false, true);
EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
@@ -8482,8 +8498,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up service " + r.name
- + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
// We are now bringing the service up, so no longer in the
// restarting state.
@@ -8534,27 +8549,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!force) {
// XXX should probably keep a count of the number of auto-create
// connections directly in the service.
- Iterator<ConnectionRecord> it = r.connections.values().iterator();
+ Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
while (it.hasNext()) {
- ConnectionRecord cr = it.next();
- if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
- return;
+ ArrayList<ConnectionRecord> cr = it.next();
+ for (int i=0; i<cr.size(); i++) {
+ if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
+ return;
+ }
}
}
}
// Report to all of the connections that the service is no longer
// available.
- Iterator<ConnectionRecord> it = r.connections.values().iterator();
+ Iterator<ArrayList<ConnectionRecord>> it = r.connections.values().iterator();
while (it.hasNext()) {
- ConnectionRecord c = it.next();
- try {
- // todo: shouldn't be a synchronous call!
- c.conn.connected(r.name, null);
- } catch (Exception e) {
- Slog.w(TAG, "Failure disconnecting service " + r.name +
- " to connection " + c.conn.asBinder() +
- " (in " + c.binding.client.processName + ")", e);
+ ArrayList<ConnectionRecord> c = it.next();
+ for (int i=0; i<c.size(); i++) {
+ try {
+ c.get(i).conn.connected(r.name, null);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failure disconnecting service " + r.name +
+ " to connection " + c.get(i).conn.asBinder() +
+ " (in " + c.get(i).binding.client.processName + ")", e);
+ }
}
}
}
@@ -8568,6 +8586,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ ": hasBound=" + ibr.hasBound);
if (r.app != null && r.app.thread != null && ibr.hasBound) {
try {
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r
+ + " for " + ibr);
bumpServiceExecutingLocked(r);
updateOomAdjLocked(r.app);
ibr.hasBound = false;
@@ -8582,15 +8602,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down service " + r.name
- + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
System.identityHashCode(r), r.shortName,
(r.app != null) ? r.app.pid : -1);
mServices.remove(r.name);
mServicesByIntent.remove(r.intent);
- if (localLOGV) Slog.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r);
@@ -8599,8 +8617,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
for (int i=0; i<N; i++) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
- if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed pending service: " + r.shortName);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
i--;
N--;
}
@@ -8622,8 +8639,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.services.remove(r);
if (r.app.thread != null) {
try {
- if (DEBUG_SERVICE) Slog.v(TAG,
- "Stopping service: " + r.shortName);
+ if (DEBUG_SERVICE) {
+ RuntimeException here = new RuntimeException();
+ here.fillInStackTrace();
+ Slog.v(TAG, ">>> EXECUTING stop of " + r, here);
+ }
bumpServiceExecutingLocked(r);
mStoppingServices.add(r);
updateOomAdjLocked(r.app);
@@ -8636,11 +8656,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
updateServiceForegroundLocked(r.app, false);
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that has no process: " + r.shortName);
+ TAG, "Removed service that has no process: " + r);
}
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that is not running: " + r.shortName);
+ TAG, "Removed service that is not running: " + r);
}
}
@@ -8675,8 +8695,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service);
if (unscheduleServiceRestartLocked(r)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: "
- + r.shortName);
+ if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.startRequested = true;
r.callStart = false;
@@ -8970,7 +8989,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (unscheduleServiceRestartLocked(s)) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
- + s.shortName);
+ + s);
}
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
@@ -8978,7 +8997,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
- s.connections.put(binder, c);
+ ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+ if (clist == null) {
+ clist = new ArrayList<ConnectionRecord>();
+ s.connections.put(binder, clist);
+ }
+ clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
@@ -8987,7 +9011,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activity.connections.add(c);
}
b.client.connections.add(c);
- mServiceConnections.put(binder, c);
+ clist = mServiceConnections.get(binder);
+ if (clist == null) {
+ clist = new ArrayList<ConnectionRecord>();
+ mServiceConnections.put(binder, clist);
+ }
+ clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
@@ -9038,7 +9067,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
- s.connections.remove(binder);
+ ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+ if (clist != null) {
+ clist.remove(c);
+ if (clist.size() == 0) {
+ s.connections.remove(binder);
+ }
+ }
b.connections.remove(c);
if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) {
@@ -9048,7 +9083,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (b.client != skipApp) {
b.client.connections.remove(c);
}
- mServiceConnections.remove(binder);
+ clist = mServiceConnections.get(binder);
+ if (clist != null) {
+ clist.remove(c);
+ if (clist.size() == 0) {
+ mServiceConnections.remove(binder);
+ }
+ }
if (b.connections.size() == 0) {
b.intent.apps.remove(b.client);
@@ -9059,6 +9100,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
+ if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s
+ + " from " + b);
bumpServiceExecutingLocked(s);
updateOomAdjLocked(s.app);
b.intent.hasBound = false;
@@ -9081,8 +9124,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
- ConnectionRecord r = mServiceConnections.get(binder);
- if (r == null) {
+ ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
+ if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
@@ -9090,11 +9133,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
- removeConnectionLocked(r, null, null);
+ while (clist.size() > 0) {
+ ConnectionRecord r = clist.get(0);
+ removeConnectionLocked(r, null, null);
- if (r.binding.service.app != null) {
- // This could have made the service less important.
- updateOomAdjLocked(r.binding.service.app);
+ if (r.binding.service.app != null) {
+ // This could have made the service less important.
+ updateOomAdjLocked(r.binding.service.app);
+ }
}
Binder.restoreCallingIdentity(origId);
@@ -9117,7 +9163,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING SERVICE " + r.name
+ if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
@@ -9128,26 +9174,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
b.requested = true;
b.received = true;
if (r.connections.size() > 0) {
- Iterator<ConnectionRecord> it
+ Iterator<ArrayList<ConnectionRecord>> it
= r.connections.values().iterator();
while (it.hasNext()) {
- ConnectionRecord c = it.next();
- if (!filter.equals(c.binding.intent.intent)) {
- if (DEBUG_SERVICE) Slog.v(
- TAG, "Not publishing to: " + c);
- if (DEBUG_SERVICE) Slog.v(
- TAG, "Bound intent: " + c.binding.intent.intent);
- if (DEBUG_SERVICE) Slog.v(
- TAG, "Published intent: " + intent);
- continue;
- }
- if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
- try {
- c.conn.connected(r.name, service);
- } catch (Exception e) {
- Slog.w(TAG, "Failure sending service " + r.name +
- " to connection " + c.conn.asBinder() +
- " (in " + c.binding.client.processName + ")", e);
+ ArrayList<ConnectionRecord> clist = it.next();
+ for (int i=0; i<clist.size(); i++) {
+ ConnectionRecord c = clist.get(i);
+ if (!filter.equals(c.binding.intent.intent)) {
+ if (DEBUG_SERVICE) Slog.v(
+ TAG, "Not publishing to: " + c);
+ if (DEBUG_SERVICE) Slog.v(
+ TAG, "Bound intent: " + c.binding.intent.intent);
+ if (DEBUG_SERVICE) Slog.v(
+ TAG, "Published intent: " + intent);
+ continue;
+ }
+ if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+ try {
+ c.conn.connected(r.name, service);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failure sending service " + r.name +
+ " to connection " + c.conn.asBinder() +
+ " (in " + c.binding.client.processName + ")", e);
+ }
}
}
}
@@ -9208,9 +9257,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord r = (ServiceRecord)token;
boolean inStopping = mStoppingServices.contains(token);
if (r != null) {
- if (DEBUG_SERVICE) Slog.v(TAG, "DONE EXECUTING SERVICE " + r.name
- + ": nesting=" + r.executeNesting
- + ", inStopping=" + inStopping);
if (r != token) {
Slog.w(TAG, "Done executing service " + r.name
+ " with incorrect token: given " + token
@@ -9267,13 +9313,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
} else {
- Slog.w(TAG, "Done executing unknown service " + r.name
- + " with token " + token);
+ Slog.w(TAG, "Done executing unknown service from pid "
+ + Binder.getCallingPid());
}
}
}
public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+ + ": nesting=" + r.executeNesting
+ + ", inStopping=" + inStopping + ", app=" + r.app);
r.executeNesting--;
if (r.executeNesting <= 0 && r.app != null) {
r.app.executingServices.remove(r);
@@ -9281,6 +9330,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
}
if (inStopping) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r);
mStoppingServices.remove(r);
}
updateOomAdjLocked(r.app);
@@ -11071,61 +11121,64 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
|| schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
- Iterator<ConnectionRecord> kt
+ Iterator<ArrayList<ConnectionRecord>> kt
= s.connections.values().iterator();
while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
- // XXX should compute this based on the max of
- // all connected clients.
- ConnectionRecord cr = kt.next();
- if (cr.binding.client == app) {
- // Binding to ourself is not interesting.
- continue;
- }
- if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
- ProcessRecord client = cr.binding.client;
- int myHiddenAdj = hiddenAdj;
- if (myHiddenAdj > client.hiddenAdj) {
- if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
- myHiddenAdj = client.hiddenAdj;
- } else {
- myHiddenAdj = VISIBLE_APP_ADJ;
- }
+ ArrayList<ConnectionRecord> clist = kt.next();
+ for (int i=0; i<clist.size() && adj > FOREGROUND_APP_ADJ; i++) {
+ // XXX should compute this based on the max of
+ // all connected clients.
+ ConnectionRecord cr = clist.get(i);
+ if (cr.binding.client == app) {
+ // Binding to ourself is not interesting.
+ continue;
}
- int clientAdj = computeOomAdjLocked(
- client, myHiddenAdj, TOP_APP, true);
- if (adj > clientAdj) {
- adj = clientAdj >= VISIBLE_APP_ADJ
- ? clientAdj : VISIBLE_APP_ADJ;
- if (!client.hidden) {
- app.hidden = false;
+ if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ ProcessRecord client = cr.binding.client;
+ int myHiddenAdj = hiddenAdj;
+ if (myHiddenAdj > client.hiddenAdj) {
+ if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
+ myHiddenAdj = client.hiddenAdj;
+ } else {
+ myHiddenAdj = VISIBLE_APP_ADJ;
+ }
+ }
+ int clientAdj = computeOomAdjLocked(
+ client, myHiddenAdj, TOP_APP, true);
+ if (adj > clientAdj) {
+ adj = clientAdj >= VISIBLE_APP_ADJ
+ ? clientAdj : VISIBLE_APP_ADJ;
+ if (!client.hidden) {
+ app.hidden = false;
+ }
+ app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = cr.binding.client;
+ app.adjTarget = s.name;
}
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ }
+ }
+ ActivityRecord a = cr.activity;
+ //if (a != null) {
+ // Slog.i(TAG, "Connection to " + a ": state=" + a.state);
+ //}
+ if (a != null && adj > FOREGROUND_APP_ADJ &&
+ (a.state == ActivityState.RESUMED
+ || a.state == ActivityState.PAUSING)) {
+ adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.hidden = false;
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
- app.adjSource = cr.binding.client;
+ app.adjSource = a;
app.adjTarget = s.name;
}
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- }
- }
- ActivityRecord a = cr.activity;
- //if (a != null) {
- // Slog.i(TAG, "Connection to " + a ": state=" + a.state);
- //}
- if (a != null && adj > FOREGROUND_APP_ADJ &&
- (a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.hidden = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjTarget = s.name;
}
}
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 255fbe3..d5b050b 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -72,8 +72,8 @@ class ServiceRecord extends Binder {
final HashMap<Intent.FilterComparison, IntentBindRecord> bindings
= new HashMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service.
- final HashMap<IBinder, ConnectionRecord> connections
- = new HashMap<IBinder, ConnectionRecord>();
+ final HashMap<IBinder, ArrayList<ConnectionRecord>> connections
+ = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
// IBinder -> ConnectionRecord of all bound clients
ProcessRecord app; // where this service is running or null.
@@ -296,10 +296,12 @@ class ServiceRecord extends Binder {
}
if (connections.size() > 0) {
pw.print(prefix); pw.println("All Connections:");
- Iterator<ConnectionRecord> it = connections.values().iterator();
+ Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
while (it.hasNext()) {
- ConnectionRecord c = it.next();
- pw.print(prefix); pw.print(" "); pw.println(c);
+ ArrayList<ConnectionRecord> c = it.next();
+ for (int i=0; i<c.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(c.get(i));
+ }
}
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 629d993..695cbfa 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -162,9 +162,13 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
const uint32_t hwFlags = hw.getFlags();
mFormat = format;
- mReqFormat = format;
mWidth = w;
mHeight = h;
+
+ mReqFormat = format;
+ mReqWidth = w;
+ mReqHeight = h;
+
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
@@ -196,12 +200,16 @@ void Layer::reloadTexture(const Region& dirty)
} else {
slowpath:
GGLSurface t;
- status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
- LOGE_IF(res, "error %d (%s) locking buffer %p",
- res, strerror(res), buffer.get());
- if (res == NO_ERROR) {
- mBufferManager.loadTexture(dirty, t);
- buffer->unlock();
+ if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) {
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ mBufferManager.loadTexture(dirty, t);
+ buffer->unlock();
+ }
+ } else {
+ // we can't do anything
}
}
}
@@ -300,16 +308,22 @@ sp<GraphicBuffer> Layer::requestBuffer(int index,
uint32_t w, h, f;
{ // scope for the lock
Mutex::Autolock _l(mLock);
- const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight);
- const bool formatChanged = mReqFormat != reqFormat;
- mReqWidth = reqWidth;
- mReqHeight = reqHeight;
- mReqFormat = reqFormat;
- mFixedSize = reqWidth && reqHeight;
- w = reqWidth ? reqWidth : mWidth;
- h = reqHeight ? reqHeight : mHeight;
- f = reqFormat ? reqFormat : mFormat;
- if (fixedSizeChanged || formatChanged) {
+
+ // zero means default
+ if (!reqFormat) reqFormat = mFormat;
+ if (!reqWidth) reqWidth = mWidth;
+ if (!reqHeight) reqHeight = mHeight;
+
+ w = reqWidth;
+ h = reqHeight;
+ f = reqFormat;
+
+ if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) ||
+ (reqFormat != mReqFormat)) {
+ mReqWidth = reqWidth;
+ mReqHeight = reqHeight;
+ mReqFormat = reqFormat;
+
lcblk->reallocateAllExcept(index);
}
}
@@ -473,9 +487,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
return;
}
- // get the dirty region
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
+ // get the dirty region
// compute the posted region
const Region dirty(lcblk->getDirtyRegion(buf));
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
@@ -511,6 +525,13 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
+
+ // get the crop region
+ setBufferCrop( lcblk->getCrop(buf) );
+
+ // get the transformation
+ setBufferTransform( lcblk->getTransform(buf) );
+
} else {
// this should not happen unless we ran out of memory while
// allocating the buffer. we're hoping that things will get back
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 91ac915..6fc5010 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -54,6 +54,8 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
+ mBufferCrop.makeInvalid();
+ mBufferTransform = 0;
}
LayerBase::~LayerBase()
@@ -345,6 +347,14 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
clearWithOpenGL(clip,0,0,0,0);
}
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+ T t(a);
+ a = b;
+ b = t;
+}
+
void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
@@ -378,38 +388,73 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
}
}
- Region::const_iterator it = clip.begin();
- Region::const_iterator const end = clip.end();
- const GLfloat texCoords[4][2] = {
- { 0, 0 },
- { 0, 1 },
- { 1, 1 },
- { 1, 0 }
+ /*
+ * compute texture coordinates
+ * here, we handle NPOT, cropping and buffer transformations
+ */
+
+ GLfloat cl, ct, cr, cb;
+ if (!mBufferCrop.isEmpty()) {
+ // source is cropped
+ const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
+ const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
+ cl = mBufferCrop.left * us;
+ ct = mBufferCrop.top * vs;
+ cr = mBufferCrop.right * us;
+ cb = mBufferCrop.bottom * vs;
+ } else {
+ cl = 0;
+ ct = 0;
+ cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
+ cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
+ }
+
+ struct TexCoords {
+ GLfloat u;
+ GLfloat v;
+ };
+
+ enum {
+ // name of the corners in the texture map
+ LB = 0, // left-bottom
+ LT = 1, // left-top
+ RT = 2, // right-top
+ RB = 3 // right-bottom
};
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
+ // vertices in screen space
+ int vLT = LB;
+ int vLB = LT;
+ int vRB = RT;
+ int vRT = RB;
// the texture's source is rotated
- switch (texture.transform) {
- case HAL_TRANSFORM_ROT_90:
- glTranslatef(0, 1, 0);
- glRotatef(-90, 0, 0, 1);
- break;
- case HAL_TRANSFORM_ROT_180:
- glTranslatef(1, 1, 0);
- glRotatef(-180, 0, 0, 1);
- break;
- case HAL_TRANSFORM_ROT_270:
- glTranslatef(1, 0, 0);
- glRotatef(-270, 0, 0, 1);
- break;
+ uint32_t transform = mBufferTransform;
+ if (transform & HAL_TRANSFORM_ROT_90) {
+ vLT = RB;
+ vLB = LB;
+ vRB = LT;
+ vRT = RT;
}
-
- if (texture.NPOTAdjust) {
- glScalef(texture.wScale, texture.hScale, 1.0f);
+ if (transform & HAL_TRANSFORM_FLIP_V) {
+ swap(vLT, vLB);
+ swap(vRB, vRT);
+ }
+ if (transform & HAL_TRANSFORM_FLIP_H) {
+ swap(vLT, vRB);
+ swap(vLB, vRT);
}
+ TexCoords texCoords[4];
+ texCoords[vLT].u = cl;
+ texCoords[vLT].v = ct;
+ texCoords[vLB].u = cl;
+ texCoords[vLB].v = cb;
+ texCoords[vRB].u = cr;
+ texCoords[vRB].v = cb;
+ texCoords[vRT].u = cr;
+ texCoords[vRT].v = ct;
+
if (needsDithering()) {
glEnable(GL_DITHER);
} else {
@@ -420,6 +465,8 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
while (it != end) {
const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
@@ -429,6 +476,16 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
+void LayerBase::setBufferCrop(const Rect& crop) {
+ if (!crop.isEmpty()) {
+ mBufferCrop = crop;
+ }
+}
+
+void LayerBase::setBufferTransform(uint32_t transform) {
+ mBufferTransform = transform;
+}
+
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 22bf857..8cba287 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -226,9 +226,17 @@ protected:
void clearWithOpenGL(const Region& clip) const;
void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ // these must be called from the post/drawing thread
+ void setBufferCrop(const Rect& crop);
+ void setBufferTransform(uint32_t transform);
+
sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
+ // post/drawing thread
+ Rect mBufferCrop;
+ uint32_t mBufferTransform;
+
// cached during validateVisibility()
bool mNeedsFiltering;
int32_t mOrientation;
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
index 64a43c7..2ee21b9 100644
--- a/services/surfaceflinger/LayerBlur.cpp
+++ b/services/surfaceflinger/LayerBlur.cpp
@@ -241,6 +241,8 @@ void LayerBlur::onDraw(const Region& clip) const
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
}
}
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index 5f83636..0240748 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -485,7 +485,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
mTextureManager.loadTexture(&mTexture, dirty, t);
}
- mTexture.transform = mBufferHeap.transform;
+ mLayer.setBufferTransform(mBufferHeap.transform);
mLayer.drawWithOpenGL(clip, mTexture);
}
diff --git a/services/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h
index c7c14e7..18c4348 100644
--- a/services/surfaceflinger/TextureManager.h
+++ b/services/surfaceflinger/TextureManager.h
@@ -40,12 +40,11 @@ class GraphicBuffer;
struct Image {
enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
- transform(0), dirty(1), target(TEXTURE_2D) { }
+ dirty(1), target(TEXTURE_2D) { }
GLuint name;
EGLImageKHR image;
GLuint width;
GLuint height;
- uint32_t transform;
unsigned dirty : 1;
unsigned target : 1;
};
diff --git a/tests/CoreTests/android/core/JavaPerformanceTests.java b/tests/CoreTests/android/core/JavaPerformanceTests.java
index fbe70cc..95075ea 100644
--- a/tests/CoreTests/android/core/JavaPerformanceTests.java
+++ b/tests/CoreTests/android/core/JavaPerformanceTests.java
@@ -23,7 +23,6 @@ public class JavaPerformanceTests {
public static String[] children() {
return new String[] {
- StringTest.class.getName(),
HashMapPerformanceTest.class.getName(),
ArrayListPerformanceTest.class.getName(),
TreeMapPerformanceTest.class.getName(),
diff --git a/tests/CoreTests/android/core/StringTest.java b/tests/CoreTests/android/core/StringTest.java
deleted file mode 100644
index 128531c..0000000
--- a/tests/CoreTests/android/core/StringTest.java
+++ /dev/null
@@ -1,951 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import java.util.Locale;
-
-import android.test.PerformanceTestBase;
-import android.test.PerformanceTestCase;
-
-public class StringTest extends PerformanceTestBase {
- public static final int ITERATIONS = 1000;
- public static final String STATIC_STRING_01 = "Hello Android";
- public static final String STATIC_STRING_02 =
- "Remember, today is the tomorrow you worried about yesterday";
- public static final char[] STATIC_CHAR_ARRAY =
- {'N', 'A', 'N', 'D', 'R', 'O', 'I', 'D'};
- public static StringBuffer STATIC_SBUF = new StringBuffer(STATIC_STRING_02);
-
- @Override
- public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
- intermediates.setInternalIterations(ITERATIONS);
- return 0;
- }
-
- /** Create an empty String object* */
-
- public void testStringCreate() {
- String rString;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- rString = new String();
- }
- }
-
- /** Create an initialised String object* */
-
- public void testStringCreate1() {
- String rString, str = STATIC_STRING_01;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str);
- rString = new String(str); // 10
- }
- }
-
- /** equals() with for loop* */
- public void testStringEquals() {
- String mString = new String(STATIC_STRING_01);
- String str = STATIC_STRING_01;
- boolean result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- result = mString.equals(str);
- }
- }
-
- /**
- * ContentEquals- Comparing the content of a String with that of a String
- * Buffer*
- */
-
- public void testStringContentEquals() {
- StringBuffer sBuf = new StringBuffer(STATIC_STRING_01);
- String str = STATIC_STRING_01;
- boolean result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- result = str.contentEquals(sBuf);
- }
- }
-
- /** Compare string objects lexicographically using compareTo() with for loop* */
-
- public void testStringCompareTo() {
- String str1 = new String(STATIC_STRING_01);
- String str2 = STATIC_STRING_01;
- int result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- result = str1.compareTo(str2);
- }
-
- }
-
- /** Compare string objects using compareToIgnorecase() with for loop* */
-
- public void testStringCompareToIgnoreCase() {
- String mString = new String(STATIC_STRING_01);
- String str2 = STATIC_STRING_01;
- int result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- result = mString.compareToIgnoreCase(str2);
- }
- }
-
- /** startsWith * */
-
- public void testStringstartsWith() {
- boolean result;
- String str1 = STATIC_STRING_02, str2 = "Rem";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- result = str1.startsWith(str2);
- }
- }
-
- /** startsWith(String seq, int begin) * */
-
- public void testStringstartsWith1() {
- String str1 = STATIC_STRING_02, str2 = "tom";
- int pos = 10;
- boolean result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- result = str1.startsWith(str2, pos);
- }
- }
-
- /** endsWith * */
-
- public void testStringendsWith() {
- String str = STATIC_STRING_02, str1 = "day";
- boolean result;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- result = str.endsWith(str1);
- }
- }
-
- /**
- * indexOf to determine whether a string contains a substring
- */
- public void testStringindexOf() {
- boolean result;
- String str = STATIC_STRING_02, str1 = "tomo";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- result = str.indexOf(str1) > 0;
- }
- }
-
- /** indexOf()* */
-
- public void testStringindexOf1() {
- int index;
- String str = STATIC_STRING_02;
- char c = 't';
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- index = str.indexOf(c);
- }
-
- }
-
- /** indexOf(char c, int start)* */
- public void testStringindexOf2() {
- int index, pos = 12;
- String str = STATIC_STRING_02, str1 = "tom";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- index = str.indexOf(str1, pos);
- }
- }
-
- /** lastIndexOf()* */
-
- public void testStringlastIndexOf() {
- int index;
- char c = 't';
- String str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- index = str.lastIndexOf(c);
- }
- }
-
- /** lastIndexOf()* */
-
- public void testStringlastIndexOf1() {
- int index, pos = 36;
- String str = STATIC_STRING_02, str1 = "tom";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- index = str.lastIndexOf(str1, pos);
- }
- }
-
- /**
- * contains() to determine whether a string contains a substring
- */
-
- public void testStringcontains() {
- boolean result;
- String str = STATIC_STRING_02, str1 = "tomo";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- result = str.contains(str1);
- }
- }
-
- /** substring(int start) */
-
- public void testStringsubstring() {
- String rString;
- String str = STATIC_STRING_02;
- int index = 10;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- rString = str.substring(index);
- }
- }
-
- /** substring(int start, int end) in a for loop* */
-
- public void testStringsubstring1() {
- String rString;
- String str = STATIC_STRING_02;
- int start = 10, end = 48;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- rString = str.substring(start, end);
- }
- }
-
- /**
- * valueOf(char[] cArray) String representation of a character array
- */
- public void testStringvalueOf() {
- String rString;
- char[] cArray = STATIC_CHAR_ARRAY;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- rString = String.valueOf(cArray);
- }
- }
-
- /** valueOf(char[] cArray, int offset, int count)* */
-
- public void testStringvalueOf1() {
- String rString;
- char[] cArray = STATIC_CHAR_ARRAY;
- int start = 1, end = 7;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- rString = String.valueOf(cArray, start, end);
- }
- }
-
- /** Convert a string to a char Array* */
-
- public void testStringtoCharArray() {
- char[] cArray;
- String str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- cArray = str.toCharArray();
- }
- }
-
- /** length()* */
-
- public void testStringlength() {
- int len;
- String str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- len = str.length();
- }
- }
-
- /** hashcode()* */
-
- public void testStringhashCode() {
- int index;
- String str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- index = str.hashCode();
- }
- }
-
- /** replace()* */
-
- public void testStringreplace() {
- String rString;
- String str = STATIC_STRING_02;
- char c1 = ' ', c2 = ' ';
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- rString = str.replace(c1, c2);
- }
- }
-
- public void testStringreplaceAll() {
- String rString;
- String str = STATIC_STRING_02, str1 = " ", str2 = "/";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- rString = str.replaceAll(str1, str2);
- }
- }
-
- /** Convert a StringBuffer to a String* */
-
- public void testStringtoString() {
- StringBuffer sBuf = new StringBuffer(STATIC_STRING_02);
-
- String rString;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- rString = sBuf.toString();
- }
- }
-
- /** Split a string into an array of strings* */
-
- public void testStringsplit() {
- String[] strings;
- String str1 = STATIC_STRING_02, str = " ";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
- strings = str1.split(str);
-
- }
- }
-
- /** Split a string into an array of strings* */
-
- public void testStringsplit1() {
- String str = STATIC_STRING_02, str1 = " ";
- String[] strings;
- int pos = 8;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- strings = str.split(str1, pos);
- }
- }
-
- public void testStringgetBytes() {
- byte[] bytes;
- String str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- bytes = str.getBytes();
- }
- }
-
- /** copyValueOf(char[] data) * */
-
- public void testStringcopyValueOf() {
- String rString;
- char[] cArray = STATIC_CHAR_ARRAY;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- rString = String.copyValueOf(cArray);
- }
- }
-
- /** copyValueOf(char[] data, int index, int count)* */
-
- public void testStringcopyValueOf1() {
- String rString;
- int start = 1, end = 7;
- char[] cArray = STATIC_CHAR_ARRAY;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- rString = String.copyValueOf(cArray, start, end);
- }
- }
-
- /** trim()* */
-
- public void testStringtrim() {
- String mString =
- new String(
- " HELLO ANDROID ");
- String rString;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- rString = mString.trim();
- }
- }
-
- /** getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)* */
-
- public void testStringgetChars() {
- char[] cArray = STATIC_CHAR_ARRAY;
- String str = STATIC_STRING_01;
- int value1 = 7, value2 = 12, value3 = 1;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- str.getChars(value1, value2, cArray, value3);
- }
- }
-
- /** toUpperCase()* */
-
- public void testStringtoUpperCase() {
- String rString, str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- rString = str.toUpperCase();
- }
- }
-
- /** toUpperCase() with locale* */
-
- public void testStringtoUpperCase1() {
- Locale locale = new Locale("tr");
- String str = STATIC_STRING_02;
- String rString;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- rString = str.toUpperCase(locale);
- }
- }
-
- /** toLowerCase* */
-
- public void StringtoLowerCase() {
- String rString, str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- rString = str.toLowerCase();
- }
- }
-
- /** toLowerCase with locale* */
-
- public void testStringtoLowerCase1() {
- Locale locale = new Locale("tr");
- String rString, str = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- rString = str.toLowerCase(locale);
- }
- }
-
- /** charAt()* */
-
- public void testStringcharAt() {
- String str = STATIC_STRING_02;
- int index, pos = 21;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- index = str.charAt(pos);
- }
- }
-
- public void testStringConcat() {
- String mString, str1 = STATIC_STRING_01, str2 = STATIC_STRING_02;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- mString = str1.concat(str2);
- }
- }
-
- public void testStringBufferAppend() {
- StringBuffer sBuf = new StringBuffer(" ");
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- sBuf.append(i);
- }
- }
-
- public void testStringBufferInsert() {
- StringBuffer sBuf = new StringBuffer(" ");
- int index = sBuf.length();
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- sBuf.insert(index, i);
- }
- }
-
- public void testStringBufferReverse() {
- StringBuffer sBuf = STATIC_SBUF;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- sBuf.reverse();
- }
- }
-
- public void testStringBufferSubstring() {
- StringBuffer sBuf = STATIC_SBUF;
- String rString;
- int index = 0;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- rString = sBuf.substring(index);
- }
- }
-
- public void testStringBufferSubstring1() {
- StringBuffer sBuf = STATIC_SBUF;
- String rString;
- int start = 5, end = 25;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- rString = sBuf.substring(start, end);
- }
- }
-
- public void testStringBufferReplace() {
- StringBuffer sBuf = STATIC_SBUF;
- int start = 3, end = 6;
- String str = "ind";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- sBuf.replace(start, end, str);
- }
- }
-
- public void testStringBufferIndexOf() {
- StringBuffer sBuf = STATIC_SBUF;
- String str = "t";
- int index;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- index = sBuf.indexOf(str);
- }
- }
-
- public void testStringBufferIndexOf1() {
- StringBuffer sBuf = STATIC_SBUF;
- String str = "tom";
- int index, pos = 12;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- index = sBuf.indexOf(str, pos);
- }
-
- }
-
- public void testStringBufferLastIndexOf() {
- StringBuffer sBuf = STATIC_SBUF;
- String str = "t";
- int index;
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- index = sBuf.lastIndexOf(str);
- }
- }
-
- public void testStringBufferLastIndexOf1() {
- StringBuffer sBuf = STATIC_SBUF;
- int index, pos = 36;
- String str = "tom";
- for (int i = ITERATIONS - 1; i >= 0; i--) {
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- index = sBuf.lastIndexOf(str, pos);
- }
- }
-}
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index b339a2c..094b7db 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -41,7 +41,7 @@ LOCAL_STATIC_LIBRARIES := \
libpng
ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt
+LOCAL_LDLIBS += -lrt -lpthread
endif
# Statically link libz for MinGW (Win SDK under Linux),
diff --git a/tools/localize/Android.mk b/tools/localize/Android.mk
index ab79f8d..f284e86 100644
--- a/tools/localize/Android.mk
+++ b/tools/localize/Android.mk
@@ -34,7 +34,7 @@ LOCAL_STATIC_LIBRARIES := \
libcutils
ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt
+LOCAL_LDLIBS += -lrt -lpthread
endif
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index e71c293..ec8d0ed 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -35,7 +35,7 @@ import javax.sip.address.URI;
* Class containing a SIP account, domain and server information.
* @hide
*/
-public class SipProfile implements Parcelable, Serializable {
+public class SipProfile implements Parcelable, Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private static final int DEFAULT_PORT = 5060;
private Address mAddress;
@@ -46,6 +46,7 @@ public class SipProfile implements Parcelable, Serializable {
private String mProfileName;
private boolean mSendKeepAlive = false;
private boolean mAutoRegistration = true;
+ private boolean mAllowOutgoingCall = false;
/** @hide */
public static final Parcelable.Creator<SipProfile> CREATOR =
@@ -79,6 +80,23 @@ public class SipProfile implements Parcelable, Serializable {
}
/**
+ * Creates a builder based on the given profile.
+ */
+ public Builder(SipProfile profile) {
+ if (profile == null) throw new NullPointerException();
+ try {
+ mProfile = (SipProfile) profile.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("should not occur", e);
+ }
+ mProfile.mAddress = null;
+ mUri = profile.getUri();
+ mUri.setUserPassword(profile.getPassword());
+ mDisplayName = profile.getDisplayName();
+ mProxyAddress = profile.getProxyAddress();
+ }
+
+ /**
* Constructor.
*
* @param uriString the URI string as "sip:<user_name>@<domain>"
@@ -226,6 +244,18 @@ public class SipProfile implements Parcelable, Serializable {
}
/**
+ * Sets the allow-outgoing-call flag.
+ *
+ * @param flag true if allowing to make outgoing call on the profile;
+ * false otherwise
+ * @return this builder object
+ */
+ public Builder setOutgoingCallAllowed(boolean flag) {
+ mProfile.mAllowOutgoingCall = flag;
+ return this;
+ }
+
+ /**
* Builds and returns the SIP profile object.
*
* @return the profile object created
@@ -262,6 +292,7 @@ public class SipProfile implements Parcelable, Serializable {
mProfileName = in.readString();
mSendKeepAlive = (in.readInt() == 0) ? false : true;
mAutoRegistration = (in.readInt() == 0) ? false : true;
+ mAllowOutgoingCall = (in.readInt() == 0) ? false : true;
}
/** @hide */
@@ -274,6 +305,7 @@ public class SipProfile implements Parcelable, Serializable {
out.writeString(mProfileName);
out.writeInt(mSendKeepAlive ? 1 : 0);
out.writeInt(mAutoRegistration ? 1 : 0);
+ out.writeInt(mAllowOutgoingCall ? 1 : 0);
}
/** @hide */
@@ -398,4 +430,11 @@ public class SipProfile implements Parcelable, Serializable {
public boolean getAutoRegistration() {
return mAutoRegistration;
}
+
+ /**
+ * Returns true if allowing to make outgoing calls on this profile.
+ */
+ public boolean isOutgoingCallAllowed() {
+ return mAllowOutgoingCall;
+ }
}