Merge "Unhide new AAC-ELD audio record type." into jb-dev
diff --git a/api/current.txt b/api/current.txt
index f6db5b1..2ddf096 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11076,15 +11076,20 @@
method public boolean hasCacheReachedEndOfStream();
method public int readSampleData(java.nio.ByteBuffer, int);
method public final void release();
- method public void seekTo(long);
+ method public void seekTo(long, int);
method public void selectTrack(int);
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
method public final void setDataSource(java.lang.String);
method public final void setDataSource(java.io.FileDescriptor);
method public final void setDataSource(java.io.FileDescriptor, long, long);
+ method public void unselectTrack(int);
field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
+ field public static final int SEEK_TO_CLOSEST = 3; // 0x3
+ field public static final int SEEK_TO_CLOSEST_SYNC = 2; // 0x2
+ field public static final int SEEK_TO_NEXT_SYNC = 1; // 0x1
+ field public static final int SEEK_TO_PREVIOUS_SYNC = 0; // 0x0
}
public class MediaMetadataRetriever {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7d41e64..018785b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5411,8 +5411,9 @@
/**
* The phone number's E164 representation. This value can be omitted in which
- * case the provider will try to automatically infer it. If present, {@link #NUMBER}
- * has to be set as well (it will be ignored otherwise).
+ * case the provider will try to automatically infer it. (It'll be left null if the
+ * provider fails to infer.)
+ * If present, {@link #NUMBER} has to be set as well (it will be ignored otherwise).
* <P>Type: TEXT</P>
*/
public static final String NORMALIZED_NUMBER = DATA4;
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 05b3e64..4d6094d 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -2598,7 +2598,8 @@
*/
@Override
public boolean isPrivateBrowsingEnabled() {
- return getSettings().isPrivateBrowsingEnabled();
+ WebSettingsClassic settings = getSettings();
+ return (settings != null) ? settings.isPrivateBrowsingEnabled() : false;
}
private void startPrivateBrowsing() {
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index a91b16e..98e45fb 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -457,7 +457,16 @@
public void parse() {
Editable editable = (Editable) mTextView.getText();
// Iterate over the newly added text and schedule new SpellCheckSpans
- final int start = editable.getSpanStart(mRange);
+ final int start;
+ if (mIsSentenceSpellCheckSupported) {
+ // TODO: Find the start position of the sentence.
+ // Set span with the context
+ start = Math.max(
+ 0, editable.getSpanStart(mRange) - MIN_SENTENCE_LENGTH);
+ } else {
+ start = editable.getSpanStart(mRange);
+ }
+
final int end = editable.getSpanEnd(mRange);
int wordIteratorWindowEnd = Math.min(end, start + WORD_ITERATOR_INTERVAL);
@@ -512,9 +521,7 @@
return;
}
// TODO: Find the start position of the sentence.
- // Set span with the context
- final int spellCheckStart = Math.max(
- 0, Math.min(wordStart, regionEnd - MIN_SENTENCE_LENGTH));
+ final int spellCheckStart = wordStart;
if (regionEnd <= spellCheckStart) {
return;
}
diff --git a/data/fonts/DroidNaskh-Regular-Shift.ttf b/data/fonts/DroidNaskh-Regular-Shift.ttf
index bb9c70c..de475ca 100644
--- a/data/fonts/DroidNaskh-Regular-Shift.ttf
+++ b/data/fonts/DroidNaskh-Regular-Shift.ttf
Binary files differ
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 41d5c32..012e095 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -47,7 +47,6 @@
private final Context mContext;
private long mVolumeKeyUpTime;
- private int mVolumeControlStream = -1;
private final boolean mUseMasterVolume;
private static String TAG = "AudioManager";
@@ -304,13 +303,6 @@
public static final int FLAG_VIBRATE = 1 << 4;
/**
- * forces use of specified stream
- * @hide
- */
- public static final int FLAG_FORCE_STREAM = 1 << 5;
-
-
- /**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
*
@@ -458,10 +450,6 @@
: ADJUST_LOWER,
flags);
} else {
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
- }
adjustSuggestedStreamVolume(
keyCode == KeyEvent.KEYCODE_VOLUME_UP
? ADJUST_RAISE
@@ -500,10 +488,6 @@
}
} else {
int flags = FLAG_PLAY_SOUND;
- if (mVolumeControlStream != -1) {
- stream = mVolumeControlStream;
- flags |= FLAG_FORCE_STREAM;
- }
adjustSuggestedStreamVolume(
ADJUST_SAME,
stream,
@@ -943,7 +927,12 @@
* @hide
*/
public void forceVolumeControlStream(int streamType) {
- mVolumeControlStream = streamType;
+ IAudioService service = getService();
+ try {
+ service.forceVolumeControlStream(streamType, mICallBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in forceVolumeControlStream", e);
+ }
}
/**
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 48d3712..dcf72cc 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -149,6 +149,7 @@
private int mMode;
// protects mRingerMode
private final Object mSettingsLock = new Object();
+
private boolean mMediaServerOk;
private SoundPool mSoundPool;
@@ -343,6 +344,14 @@
// Keyguard manager proxy
private KeyguardManager mKeyguardManager;
+ // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
+ // is controlled by Vol keys.
+ private int mVolumeControlStream = -1;
+ private final Object mForceControlStreamLock = new Object();
+ // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
+ // server process so in theory it is not necessary to monitor the client death.
+ // However it is good to be ready for future evolutions.
+ private ForceControlStreamClient mForceControlStreamClient = null;
///////////////////////////////////////////////////////////////////////////
// Construction
@@ -538,8 +547,8 @@
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
int streamType;
- if ((flags & AudioManager.FLAG_FORCE_STREAM) != 0) {
- streamType = suggestedStreamType;
+ if (mVolumeControlStream != -1) {
+ streamType = mVolumeControlStream;
} else {
streamType = getActiveStreamType(suggestedStreamType);
}
@@ -682,6 +691,57 @@
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
+ /** @see AudioManager#forceVolumeControlStream(int) */
+ public void forceVolumeControlStream(int streamType, IBinder cb) {
+ synchronized(mForceControlStreamLock) {
+ mVolumeControlStream = streamType;
+ if (mVolumeControlStream == -1) {
+ if (mForceControlStreamClient != null) {
+ mForceControlStreamClient.release();
+ mForceControlStreamClient = null;
+ }
+ } else {
+ mForceControlStreamClient = new ForceControlStreamClient(cb);
+ }
+ }
+ }
+
+ private class ForceControlStreamClient implements IBinder.DeathRecipient {
+ private IBinder mCb; // To be notified of client's death
+
+ ForceControlStreamClient(IBinder cb) {
+ if (cb != null) {
+ try {
+ cb.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ // Client has died!
+ Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
+ cb = null;
+ }
+ }
+ mCb = cb;
+ }
+
+ public void binderDied() {
+ synchronized(mForceControlStreamLock) {
+ Log.w(TAG, "SCO client died");
+ if (mForceControlStreamClient != this) {
+ Log.w(TAG, "unregistered control stream client died");
+ } else {
+ mForceControlStreamClient = null;
+ mVolumeControlStream = -1;
+ }
+ }
+ }
+
+ public void release() {
+ if (mCb != null) {
+ mCb.unlinkToDeath(this, 0);
+ mCb = null;
+ }
+ }
+ }
+
private int findVolumeDelta(int direction, int volume) {
int delta = 0;
if (direction == AudioManager.ADJUST_RAISE) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index b775095..0311c59 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -115,4 +115,6 @@
void startBluetoothSco(IBinder cb);
void stopBluetoothSco(IBinder cb);
+
+ void forceVolumeControlStream(int streamType, IBinder cb);
}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 9fdb81f..5fe58a8 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -191,17 +191,33 @@
/** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
* {@link #getSampleTime} only retrieve information for the subset of tracks
- * selected by the call below.
- * Selecting the same track multiple times has no effect, the track
+ * selected.
+ * Selecting the same track multiple times has no effect, the track is
* only selected once.
- * Media data will be returned in the order of their timestamps.
*/
public native void selectTrack(int index);
- /** All selected tracks seek near the requested time. The next sample
- * returned for each selected track will be a sync sample.
+ /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
+ * {@link #getSampleTime} only retrieve information for the subset of tracks
+ * selected.
*/
- public native void seekTo(long timeUs);
+ public native void unselectTrack(int index);
+
+ /** If possible, seek to a sync sample at or before the specified time */
+ public static final int SEEK_TO_PREVIOUS_SYNC = 0;
+ /** If possible, seek to a sync sample at or after the specified time */
+ public static final int SEEK_TO_NEXT_SYNC = 1;
+ /** If possible, seek to the sync sample closest to the specified time */
+ public static final int SEEK_TO_CLOSEST_SYNC = 2;
+ /** If possible, seek to a sample closest to the specified time, which may
+ * NOT be a sync sample!
+ */
+ public static final int SEEK_TO_CLOSEST = 3;
+
+ /** All selected tracks seek near the requested time according to the
+ * specified mode.
+ */
+ public native void seekTo(long timeUs, int mode);
/** Advance to the next sample. Returns false if no more sample data
* is available (end of stream).
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 0518331..9e1920c 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -96,8 +96,13 @@
return mImpl->selectTrack(index);
}
-status_t JMediaExtractor::seekTo(int64_t timeUs) {
- return mImpl->seekTo(timeUs);
+status_t JMediaExtractor::unselectTrack(size_t index) {
+ return mImpl->unselectTrack(index);
+}
+
+status_t JMediaExtractor::seekTo(
+ int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
+ return mImpl->seekTo(timeUs, mode);
}
status_t JMediaExtractor::advance() {
@@ -281,8 +286,8 @@
}
}
-static void android_media_MediaExtractor_seekTo(
- JNIEnv *env, jobject thiz, jlong timeUs) {
+static void android_media_MediaExtractor_unselectTrack(
+ JNIEnv *env, jobject thiz, jint index) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
if (extractor == NULL) {
@@ -290,7 +295,30 @@
return;
}
- extractor->seekTo(timeUs);
+ status_t err = extractor->unselectTrack(index);
+
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+}
+
+static void android_media_MediaExtractor_seekTo(
+ JNIEnv *env, jobject thiz, jlong timeUs, jint mode) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (mode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC
+ || mode > MediaSource::ReadOptions::SEEK_CLOSEST) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ extractor->seekTo(timeUs, (MediaSource::ReadOptions::SeekMode)mode);
}
static jboolean android_media_MediaExtractor_advance(
@@ -648,7 +676,10 @@
{ "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack },
- { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo },
+ { "unselectTrack", "(I)V",
+ (void *)android_media_MediaExtractor_unselectTrack },
+
+ { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo },
{ "advance", "()Z", (void *)android_media_MediaExtractor_advance },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index ef0c48b..2d4627e 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -18,6 +18,7 @@
#define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -43,8 +44,9 @@
status_t getTrackFormat(size_t index, jobject *format) const;
status_t selectTrack(size_t index);
+ status_t unselectTrack(size_t index);
- status_t seekTo(int64_t timeUs);
+ status_t seekTo(int64_t timeUs, MediaSource::ReadOptions::SeekMode mode);
status_t advance();
status_t readSampleData(jobject byteBuf, size_t offset, size_t *sampleSize);
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
index 07d7c34..1ecccf6 100644
--- a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
@@ -186,6 +186,13 @@
assertRaisesException("testController.foo()");
}
+ public void testUncaughtJavaExceptionRaisesJavaException() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public void method() { throw new RuntimeException("foo"); }
+ }, "testObject");
+ assertRaisesException("testObject.method()");
+ }
+
// Note that this requires that we can pass a JavaScript string to Java.
public void testTypeOfStaticMethod() throws Throwable {
injectObjectAndReload(new ObjectWithStaticMethod(), "testObject");
@@ -394,7 +401,6 @@
assertEquals("", mTestController.waitForStringValue());
}
- // java.lang.reflect only allows access to public methods and fields. See b/6386557.
public void testReflectPublicMethod() throws Throwable {
injectObjectAndReload(new Object() {
public String method() { return "foo"; }
@@ -404,7 +410,6 @@
".toString()"));
}
- // java.lang.reflect only allows access to public methods and fields. See b/6386557.
public void testReflectPublicField() throws Throwable {
injectObjectAndReload(new Object() {
public String field = "foo";
@@ -412,4 +417,26 @@
assertEquals("foo", executeJavaScriptAndGetStringResult(
"testObject.getClass().getField('field').get(testObject).toString()"));
}
+
+ public void testReflectPrivateMethodRaisesException() throws Throwable {
+ injectObjectAndReload(new Object() {
+ private void method() {};
+ }, "testObject");
+ assertRaisesException("testObject.getClass().getMethod('method', null)");
+ // getDeclaredMethod() is able to access a private method, but invoke()
+ // throws a Java exception.
+ assertRaisesException(
+ "testObject.getClass().getDeclaredMethod('method', null).invoke(testObject, null)");
+ }
+
+ public void testReflectPrivateFieldRaisesException() throws Throwable {
+ injectObjectAndReload(new Object() {
+ private int field;
+ }, "testObject");
+ assertRaisesException("testObject.getClass().getField('field')");
+ // getDeclaredField() is able to access a private field, but getInt()
+ // throws a Java exception.
+ assertRaisesException(
+ "testObject.getClass().getDeclaredField('field').getInt(testObject)");
+ }
}