Merge change I53e3a20e into eclair-mr2
* changes:
move SubscribedFeeds to GSF
diff --git a/Android.mk b/Android.mk
index 732b486..127693f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -442,6 +442,7 @@
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
$(web_docs_sample_code_flags) \
+ -offlinemode \
-title "Android SDK" \
-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
-todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \
diff --git a/api/current.xml b/api/current.xml
index fed1e45..12c2eee 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -167061,6 +167061,39 @@
visibility="public"
>
</field>
+<field name="BRIGHTNESS_OVERRIDE_FULL"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="1.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BRIGHTNESS_OVERRIDE_NONE"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="-1.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BRIGHTNESS_OVERRIDE_OFF"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="0.0f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CREATOR"
type="android.os.Parcelable.Creator"
transient="false"
@@ -167917,6 +167950,16 @@
visibility="public"
>
</field>
+<field name="buttonBrightness"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dimAmount"
type="float"
transient="false"
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 8c25d85..a31a5c0 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -19,13 +19,13 @@
#include <binder/ProcessState.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/MediaPlayerInterface.h>
@@ -105,7 +105,7 @@
sp<MediaSource> source;
sp<MediaExtractor> extractor =
- MediaExtractor::Create(new MmapSource(filename));
+ MediaExtractor::Create(new FileSource(filename));
size_t num_tracks = extractor->countTracks();
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d26e558..76ec54b 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -24,15 +24,14 @@
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
@@ -52,9 +51,6 @@
static void playSource(OMXClient *client, const sp<MediaSource> &source) {
sp<MetaData> meta = source->getFormat();
- int64_t durationUs;
- CHECK(meta->findInt64(kKeyDuration, &durationUs));
-
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -74,6 +70,9 @@
rawSource->start();
if (gReproduceBug >= 3 && gReproduceBug <= 5) {
+ int64_t durationUs;
+ CHECK(meta->findInt64(kKeyDuration, &durationUs));
+
status_t err;
MediaBuffer *buffer;
MediaSource::ReadOptions options;
@@ -368,7 +367,7 @@
dataSource = new HTTPDataSource(filename);
dataSource = new CachingDataSource(dataSource, 64 * 1024, 10);
} else {
- dataSource = new MmapSource(filename);
+ dataSource = new FileSource(filename);
}
bool isJPEG = false;
diff --git a/common/Android.mk b/common/Android.mk
index 349bb86..76091eb 100644
--- a/common/Android.mk
+++ b/common/Android.mk
@@ -24,3 +24,6 @@
# Include this library in the build server's output directory
$(call dist-for-goals, droid, $(LOCAL_BUILT_MODULE):android-common.jar)
+
+# Build the test package
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
new file mode 100644
index 0000000..71b22ce
--- /dev/null
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.SharedPreferences;
+import android.text.format.Time;
+
+import java.util.Map;
+import java.util.TreeSet;
+
+/**
+ * Tracks the success/failure history of a particular network operation in
+ * persistent storage and computes retry strategy accordingly. Handles
+ * exponential backoff, periodic rescheduling, event-driven triggering,
+ * retry-after moratorium intervals, etc. based on caller-specified parameters.
+ *
+ * <p>This class does not directly perform or invoke any operations,
+ * it only keeps track of the schedule. Somebody else needs to call
+ * {@link #getNextTimeMillis()} as appropriate and do the actual work.
+ */
+public class OperationScheduler {
+ /** Tunable parameter options for {@link #getNextTimeMillis}. */
+ public static class Options {
+ /** Wait this long after every error before retrying. */
+ public long backoffFixedMillis = 0;
+
+ /** Wait this long times the number of consecutive errors so far before retrying. */
+ public long backoffIncrementalMillis = 5000;
+
+ /** Maximum duration of moratorium to honor. Mostly an issue for clock rollbacks. */
+ public long maxMoratoriumMillis = 24 * 3600 * 1000;
+
+ /** Minimum duration after success to wait before allowing another trigger. */
+ public long minTriggerMillis = 0;
+
+ /** Automatically trigger this long after the last success. */
+ public long periodicIntervalMillis = 0;
+
+ @Override
+ public String toString() {
+ return String.format(
+ "OperationScheduler.Options[backoff=%.1f+%.1f max=%.1f min=%.1f period=%.1f]",
+ backoffFixedMillis / 1000.0, backoffIncrementalMillis / 1000.0,
+ maxMoratoriumMillis / 1000.0, minTriggerMillis / 1000.0,
+ periodicIntervalMillis / 1000.0);
+ }
+ }
+
+ private static final String PREFIX = "OperationScheduler_";
+ private final SharedPreferences mStorage;
+
+ /**
+ * Initialize the scheduler state.
+ * @param storage to use for recording the state of operations across restarts/reboots
+ */
+ public OperationScheduler(SharedPreferences storage) {
+ mStorage = storage;
+ }
+
+ /**
+ * Parse scheduler options supplied in this string form:
+ *
+ * <pre>
+ * backoff=(fixed)+(incremental) max=(maxmoratorium) min=(mintrigger) [period=](interval)
+ * </pre>
+ *
+ * All values are times in (possibly fractional) <em>seconds</em> (not milliseconds).
+ * Omitted settings are left at whatever existing default value was passed in.
+ *
+ * <p>
+ * The default options: <code>backoff=0+5 max=86400 min=0 period=0</code><br>
+ * Fractions are OK: <code>backoff=+2.5 period=10.0</code><br>
+ * The "period=" can be omitted: <code>3600</code><br>
+ *
+ * @param spec describing some or all scheduler options.
+ * @param options to update with parsed values.
+ * @return the options passed in (for convenience)
+ * @throws IllegalArgumentException if the syntax is invalid
+ */
+ public static Options parseOptions(String spec, Options options)
+ throws IllegalArgumentException {
+ for (String param : spec.split(" +")) {
+ if (param.length() == 0) continue;
+ if (param.startsWith("backoff=")) {
+ int plus = param.indexOf('+', 8);
+ if (plus < 0) {
+ options.backoffFixedMillis = parseSeconds(param.substring(8));
+ } else {
+ if (plus > 8) {
+ options.backoffFixedMillis = parseSeconds(param.substring(8, plus));
+ }
+ options.backoffIncrementalMillis = parseSeconds(param.substring(plus + 1));
+ }
+ } else if (param.startsWith("max=")) {
+ options.maxMoratoriumMillis = parseSeconds(param.substring(4));
+ } else if (param.startsWith("min=")) {
+ options.minTriggerMillis = parseSeconds(param.substring(4));
+ } else if (param.startsWith("period=")) {
+ options.periodicIntervalMillis = parseSeconds(param.substring(7));
+ } else {
+ options.periodicIntervalMillis = parseSeconds(param);
+ }
+ }
+ return options;
+ }
+
+ private static long parseSeconds(String param) throws NumberFormatException {
+ return (long) (Float.parseFloat(param) * 1000);
+ }
+
+ /**
+ * Compute the time of the next operation. Does not modify any state.
+ *
+ * @param options to use for this computation.
+ * @return the wall clock time ({@link System#currentTimeMillis()}) when the
+ * next operation should be attempted -- immediately, if the return value is
+ * before the current time.
+ */
+ public long getNextTimeMillis(Options options) {
+ boolean enabledState = mStorage.getBoolean(PREFIX + "enabledState", true);
+ if (!enabledState) return Long.MAX_VALUE;
+
+ boolean permanentError = mStorage.getBoolean(PREFIX + "permanentError", false);
+ if (permanentError) return Long.MAX_VALUE;
+
+ // We do quite a bit of limiting to prevent a clock rollback from totally
+ // hosing the scheduler. Times which are supposed to be in the past are
+ // clipped to the current time so we don't languish forever.
+
+ int errorCount = mStorage.getInt(PREFIX + "errorCount", 0);
+ long now = System.currentTimeMillis();
+ long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now);
+ long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now);
+ long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE);
+ long moratoriumSetMillis = mStorage.getLong(PREFIX + "moratoriumSetTimeMillis", 0);
+ long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis",
+ moratoriumSetMillis + options.maxMoratoriumMillis);
+
+ long time = triggerTimeMillis;
+ if (options.periodicIntervalMillis > 0) {
+ time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis);
+ }
+ if (time >= moratoriumTimeMillis - options.maxMoratoriumMillis) {
+ time = Math.max(time, moratoriumTimeMillis);
+ }
+ time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
+ time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
+ options.backoffIncrementalMillis * errorCount);
+ return time;
+ }
+
+ /**
+ * Fetch a {@link SharedPreferences} property, but force it to be before
+ * a certain time, updating the value if necessary. This is to recover
+ * gracefully from clock rollbacks which could otherwise strand our timers.
+ *
+ * @param name of SharedPreferences key
+ * @param max time to allow in result
+ * @return current value attached to key (default 0), limited by max
+ */
+ private long getTimeBefore(String name, long max) {
+ long time = mStorage.getLong(name, 0);
+ if (time > max) mStorage.edit().putLong(name, (time = max)).commit();
+ return time;
+ }
+
+ /**
+ * Request an operation to be performed at a certain time. The actual
+ * scheduled time may be affected by error backoff logic and defined
+ * minimum intervals.
+ *
+ * @param millis wall clock time ({@link System#currentTimeMillis()}) to
+ * trigger another operation; 0 to trigger immediately
+ */
+ public void setTriggerTimeMillis(long millis) {
+ mStorage.edit().putLong(PREFIX + "triggerTimeMillis", millis).commit();
+ }
+
+ /**
+ * Forbid any operations until after a certain (absolute) time.
+ * Commonly used when a server returns a "Retry-After:" type directive.
+ * Limited by {@link #Options.maxMoratoriumMillis}.
+ *
+ * @param millis wall clock time ({@link System#currentTimeMillis()}) to
+ * wait before attempting any more operations; 0 to remove moratorium
+ */
+ public void setMoratoriumTimeMillis(long millis) {
+ mStorage.edit()
+ .putLong(PREFIX + "moratoriumTimeMillis", millis)
+ .putLong(PREFIX + "moratoriumSetTimeMillis", System.currentTimeMillis())
+ .commit();
+ }
+
+ /**
+ * Enable or disable all operations. When disabled, all calls to
+ * {@link #getNextTimeMillis()} return {@link Long#MAX_VALUE}.
+ * Commonly used when data network availability goes up and down.
+ *
+ * @param enabled if operations can be performed
+ */
+ public void setEnabledState(boolean enabled) {
+ mStorage.edit().putBoolean(PREFIX + "enabledState", enabled).commit();
+ }
+
+ /**
+ * Report successful completion of an operation. Resets all error
+ * counters, clears any trigger directives, and records the success.
+ */
+ public void onSuccess() {
+ resetTransientError();
+ resetPermanentError();
+ long now = System.currentTimeMillis();
+ mStorage.edit()
+ .remove(PREFIX + "errorCount")
+ .remove(PREFIX + "lastErrorTimeMillis")
+ .remove(PREFIX + "permanentError")
+ .remove(PREFIX + "triggerTimeMillis")
+ .putLong(PREFIX + "lastSuccessTimeMillis", now).commit();
+ }
+
+ /**
+ * Report a transient error (usually a network failure). Increments
+ * the error count and records the time of the latest error for backoff
+ * purposes.
+ */
+ public void onTransientError() {
+ long now = System.currentTimeMillis();
+ mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", now).commit();
+ mStorage.edit().putInt(PREFIX + "errorCount",
+ mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit();
+ }
+
+ /**
+ * Reset all transient error counts, allowing the next operation to proceed
+ * immediately without backoff. Commonly used on network state changes, when
+ * partial progress occurs (some data received), and in other circumstances
+ * where there is reason to hope things might start working better.
+ */
+ public void resetTransientError() {
+ mStorage.edit()
+ .remove(PREFIX + "lastErrorTimeMillis")
+ .remove(PREFIX + "errorCount").commit();
+ }
+
+ /**
+ * Report a permanent error that will not go away until further notice.
+ * No operation will be scheduled until {@link #resetPermanentError()}
+ * is called. Commonly used for authentication failures (which are reset
+ * when the accounts database is updated).
+ */
+ public void onPermanentError() {
+ mStorage.edit().putBoolean(PREFIX + "permanentError", true).commit();
+ }
+
+ /**
+ * Reset any permanent error status set by {@link #onPermanentError},
+ * allowing operations to be scheduled as normal.
+ */
+ public void resetPermanentError() {
+ mStorage.edit().remove(PREFIX + "permanentError").commit();
+ }
+
+ /**
+ * Return a string description of the scheduler state for debugging.
+ */
+ public String toString() {
+ StringBuilder out = new StringBuilder("[OperationScheduler:");
+ for (String key : new TreeSet<String>(mStorage.getAll().keySet())) { // Sort keys
+ if (key.startsWith(PREFIX)) {
+ if (key.endsWith("TimeMillis")) {
+ Time time = new Time();
+ time.set(mStorage.getLong(key, 0));
+ out.append(" ").append(key.substring(PREFIX.length(), key.length() - 10));
+ out.append("=").append(time.format("%Y-%m-%d/%H:%M:%S"));
+ } else {
+ out.append(" ").append(key.substring(PREFIX.length()));
+ out.append("=").append(mStorage.getAll().get(key).toString());
+ }
+ }
+ }
+ return out.append("]").toString();
+ }
+}
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
new file mode 100644
index 0000000..13f710d
--- /dev/null
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.SharedPreferences;
+import android.test.AndroidTestCase;
+
+public class OperationSchedulerTest extends AndroidTestCase {
+ public void testScheduler() throws Exception {
+ String name = "OperationSchedulerTest.testScheduler";
+ SharedPreferences storage = getContext().getSharedPreferences(name, 0);
+ storage.edit().clear().commit();
+
+ OperationScheduler scheduler = new OperationScheduler(storage);
+ OperationScheduler.Options options = new OperationScheduler.Options();
+ assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+
+ long beforeTrigger = System.currentTimeMillis();
+ scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
+ assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+
+ // It will schedule for the later of the trigger and the moratorium...
+ scheduler.setMoratoriumTimeMillis(beforeTrigger + 500000);
+ assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+ scheduler.setMoratoriumTimeMillis(beforeTrigger + 1500000);
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+ // Test enable/disable toggle
+ scheduler.setEnabledState(false);
+ assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+ scheduler.setEnabledState(true);
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+ // Backoff interval after an error
+ long beforeError = System.currentTimeMillis();
+ scheduler.onTransientError();
+ long afterError = System.currentTimeMillis();
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+ options.backoffFixedMillis = 1000000;
+ options.backoffIncrementalMillis = 500000;
+ assertTrue(beforeError + 1500000 <= scheduler.getNextTimeMillis(options));
+ assertTrue(afterError + 1500000 >= scheduler.getNextTimeMillis(options));
+
+ // Two errors: backoff interval increases
+ beforeError = System.currentTimeMillis();
+ scheduler.onTransientError();
+ afterError = System.currentTimeMillis();
+ assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options));
+ assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options));
+
+ // Permanent error holds true even if transient errors are reset
+ // However, we remember that the transient error was reset...
+ scheduler.onPermanentError();
+ assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+ scheduler.resetTransientError();
+ assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+ scheduler.resetPermanentError();
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+
+ // Success resets the trigger
+ long beforeSuccess = System.currentTimeMillis();
+ scheduler.onSuccess();
+ long afterSuccess = System.currentTimeMillis();
+ assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+
+ // The moratorium is not reset by success!
+ scheduler.setTriggerTimeMillis(beforeSuccess + 500000);
+ assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+ scheduler.setMoratoriumTimeMillis(0);
+ assertEquals(beforeSuccess + 500000, scheduler.getNextTimeMillis(options));
+
+ // Periodic interval after success
+ options.periodicIntervalMillis = 250000;
+ assertTrue(beforeSuccess + 250000 <= scheduler.getNextTimeMillis(options));
+ assertTrue(afterSuccess + 250000 >= scheduler.getNextTimeMillis(options));
+
+ // Trigger minimum is also since the last success
+ options.minTriggerMillis = 1000000;
+ assertTrue(beforeSuccess + 1000000 <= scheduler.getNextTimeMillis(options));
+ assertTrue(afterSuccess + 1000000 >= scheduler.getNextTimeMillis(options));
+ }
+
+ public void testParseOptions() throws Exception {
+ OperationScheduler.Options options = new OperationScheduler.Options();
+ assertEquals(
+ "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]",
+ OperationScheduler.parseOptions("3600", options).toString());
+
+ assertEquals(
+ "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]",
+ OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString());
+
+ assertEquals(
+ "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
+ OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800",
+ options).toString());
+
+ assertEquals(
+ "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
+ OperationScheduler.parseOptions("", options).toString());
+ }
+}
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/common/tests/src/com/android/common/PatternsTest.java
index a89ad62..7fabe5e 100644
--- a/common/tests/src/com/android/common/PatternsTest.java
+++ b/common/tests/src/com/android/common/PatternsTest.java
@@ -28,10 +28,10 @@
public void testTldPattern() throws Exception {
boolean t;
- t = Patterns.TOP_LEVEL_DOMAIN_PATTERN.matcher("com").matches();
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches();
assertTrue("Missed valid TLD", t);
- t = Patterns.TOP_LEVEL_DOMAIN_PATTERN.matcher("xer").matches();
+ t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches();
assertFalse("Matched invalid TLD!", t);
}
@@ -39,19 +39,19 @@
public void testUrlPattern() throws Exception {
boolean t;
- t = Patterns.WEB_URL_PATTERN.matcher("http://www.google.com").matches();
+ t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
assertTrue("Valid URL", t);
- t = Patterns.WEB_URL_PATTERN.matcher("ftp://www.example.com").matches();
+ t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
assertFalse("Matched invalid protocol", t);
- t = Patterns.WEB_URL_PATTERN.matcher("http://www.example.com:8080").matches();
+ t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches();
assertTrue("Didn't match valid URL with port", t);
- t = Patterns.WEB_URL_PATTERN.matcher("http://www.example.com:8080/?foo=bar").matches();
+ t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches();
assertTrue("Didn't match valid URL with port and query args", t);
- t = Patterns.WEB_URL_PATTERN.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
+ t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
assertTrue("Didn't match valid URL with ~", t);
}
@@ -59,10 +59,10 @@
public void testIpPattern() throws Exception {
boolean t;
- t = Patterns.IP_ADDRESS_PATTERN.matcher("172.29.86.3").matches();
+ t = Patterns.IP_ADDRESS.matcher("172.29.86.3").matches();
assertTrue("Valid IP", t);
- t = Patterns.IP_ADDRESS_PATTERN.matcher("1234.4321.9.9").matches();
+ t = Patterns.IP_ADDRESS.matcher("1234.4321.9.9").matches();
assertFalse("Invalid IP", t);
}
@@ -70,10 +70,10 @@
public void testDomainPattern() throws Exception {
boolean t;
- t = Patterns.DOMAIN_NAME_PATTERN.matcher("mail.example.com").matches();
+ t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
assertTrue("Valid domain", t);
- t = Patterns.DOMAIN_NAME_PATTERN.matcher("__+&42.xer").matches();
+ t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
assertFalse("Invalid domain", t);
}
@@ -81,10 +81,10 @@
public void testPhonePattern() throws Exception {
boolean t;
- t = Patterns.PHONE_PATTERN.matcher("(919) 555-1212").matches();
+ t = Patterns.PHONE.matcher("(919) 555-1212").matches();
assertTrue("Valid phone", t);
- t = Patterns.PHONE_PATTERN.matcher("2334 9323/54321").matches();
+ t = Patterns.PHONE.matcher("2334 9323/54321").matches();
assertFalse("Invalid phone", t);
String[] tests = {
@@ -115,7 +115,7 @@
};
for (String test : tests) {
- Matcher m = Patterns.PHONE_PATTERN.matcher(test);
+ Matcher m = Patterns.PHONE.matcher(test);
assertTrue("Valid phone " + test, m.find());
}
diff --git a/core/java/android/os/LocalPowerManager.java b/core/java/android/os/LocalPowerManager.java
index 03331aa..d348f07 100644
--- a/core/java/android/os/LocalPowerManager.java
+++ b/core/java/android/os/LocalPowerManager.java
@@ -49,4 +49,5 @@
boolean isScreenOn();
void setScreenBrightnessOverride(int brightness);
+ void setButtonBrightnessOverride(int brightness);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6696533..fe329f2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -649,7 +649,28 @@
* be cleared automatically after the window is displayed.
*/
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
-
+
+ /**
+ * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the brightness value is not overridden for this window
+ * and normal brightness policy should be used.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
+
+ /**
+ * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the screen or button backlight brightness should be set
+ * to the lowest value when this window is in front.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
+
+ /**
+ * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the screen or button backlight brightness should be set
+ * to the hightest value when this window is in front.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
+
/**
* Desired operating mode for any soft input area. May any combination
* of:
@@ -717,9 +738,17 @@
* preferred screen brightness. 0 to 1 adjusts the brightness from
* dark to full bright.
*/
- public float screenBrightness = -1.0f;
+ public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
/**
+ * This can be used to override the standard behavior of the button and
+ * keyboard backlights. A value of less than 0, the default, means to
+ * use the standard backlight behavior. 0 to 1 adjusts the brightness
+ * from dark to full bright.
+ */
+ public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
+
+ /**
* Identifier for this window. This will usually be filled in for
* you.
*/
@@ -816,6 +845,7 @@
out.writeFloat(alpha);
out.writeFloat(dimAmount);
out.writeFloat(screenBrightness);
+ out.writeFloat(buttonBrightness);
out.writeStrongBinder(token);
out.writeString(packageName);
TextUtils.writeToParcel(mTitle, out, parcelableFlags);
@@ -851,6 +881,7 @@
alpha = in.readFloat();
dimAmount = in.readFloat();
screenBrightness = in.readFloat();
+ buttonBrightness = in.readFloat();
token = in.readStrongBinder();
packageName = in.readString();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -870,6 +901,8 @@
public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
+ /** {@hide} */
+ public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<12;
// internal buffer to backup/restore parameters under compatibility mode.
private int[] mCompatibilityParamsBackup = null;
@@ -971,6 +1004,10 @@
screenBrightness = o.screenBrightness;
changes |= SCREEN_BRIGHTNESS_CHANGED;
}
+ if (buttonBrightness != o.buttonBrightness) {
+ buttonBrightness = o.buttonBrightness;
+ changes |= BUTTON_BRIGHTNESS_CHANGED;
+ }
if (screenOrientation != o.screenOrientation) {
screenOrientation = o.screenOrientation;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1899a6e..8dc2ce6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3291,6 +3291,35 @@
}
}
+ /**
+ * Dump the display tree to "/sdcard/displayTree.txt"
+ *
+ * @hide debug only
+ */
+ public void dumpDisplayTree() {
+ nativeDumpDisplayTree(getUrl());
+ }
+
+ /**
+ * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to
+ * "/sdcard/domTree.txt"
+ *
+ * @hide debug only
+ */
+ public void dumpDomTree(boolean toFile) {
+ mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0);
+ }
+
+ /**
+ * Dump the render tree to adb shell if "toFile" is False, otherwise dump it
+ * to "/sdcard/renderTree.txt"
+ *
+ * @hide debug only
+ */
+ public void dumpRenderTree(boolean toFile) {
+ mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0);
+ }
+
// This is used to determine long press with the center key. Does not
// affect long press with the trackball/touch.
private boolean mGotCenterDown = false;
@@ -3380,24 +3409,15 @@
if (getSettings().getNavDump()) {
switch (keyCode) {
case KeyEvent.KEYCODE_4:
- // "/data/data/com.android.browser/displayTree.txt"
- nativeDumpDisplayTree(getUrl());
+ dumpDisplayTree();
break;
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
- // 5: dump the dom tree to the file
- // "/data/data/com.android.browser/domTree.txt"
- // 6: dump the dom tree to the adb log
- mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE,
- (keyCode == KeyEvent.KEYCODE_5) ? 1 : 0, 0);
+ dumpDomTree(keyCode == KeyEvent.KEYCODE_5);
break;
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
- // 7: dump the render tree to the file
- // "/data/data/com.android.browser/renderTree.txt"
- // 8: dump the render tree to the adb log
- mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE,
- (keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
+ dumpRenderTree(keyCode == KeyEvent.KEYCODE_7);
break;
case KeyEvent.KEYCODE_9:
nativeInstrumentReport();
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index f723cfd..6575da6 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -133,9 +133,9 @@
return INVALID_OPERATION;
};
-protected:
virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
+protected:
void* mCookie;
notify_callback_f mNotify;
};
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 960eda3..71344e6 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -30,12 +30,20 @@
class AudioPlayer : public TimeSource {
public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
virtual ~AudioPlayer();
// Caller retains ownership of "source".
void setSource(const sp<MediaSource> &source);
+ void setListenerCallback(
+ void (*notify)(void *cookie, int what), void *cookie);
+
// Return time in us.
virtual int64_t getRealTimeUs();
@@ -76,6 +84,9 @@
bool mStarted;
+ void (*mListenerCallback)(void *cookie, int what);
+ void *mListenerCookie;
+
sp<MediaPlayerBase::AudioSink> mAudioSink;
static void AudioCallback(int event, void *user, void *info);
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
deleted file mode 100644
index 53a2088..0000000
--- a/include/media/stagefright/MediaPlayerImpl.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_PLAYER_IMPL_H_
-
-#define MEDIA_PLAYER_IMPL_H_
-
-#include <pthread.h>
-
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/OMXClient.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class AudioPlayer;
-class IOMXRenderer;
-class ISurface;
-class MediaExtractor;
-class MediaBuffer;
-class MediaSource;
-class MemoryHeapPmem;
-class MetaData;
-class Surface;
-class TimeSource;
-
-class MediaPlayerImpl {
-public:
- MediaPlayerImpl(const char *uri);
-
- status_t initCheck() const;
-
- // Assumes ownership of "fd".
- MediaPlayerImpl(int fd, int64_t offset, int64_t length);
-
- ~MediaPlayerImpl();
-
- void play();
- void pause();
- bool isPlaying() const;
-
- void setSurface(const sp<Surface> &surface);
- void setISurface(const sp<ISurface> &isurface);
-
- void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
-
- int32_t getWidth() const { return mVideoWidth; }
- int32_t getHeight() const { return mVideoHeight; }
-
- int64_t getDuration();
- int64_t getPosition();
- status_t seekTo(int64_t time);
-
-private:
- status_t mInitCheck;
-
- OMXClient mClient;
-
- sp<MediaExtractor> mExtractor;
-
- TimeSource *mTimeSource;
-
- sp<MediaSource> mAudioSource;
- sp<MediaSource> mAudioDecoder;
- AudioPlayer *mAudioPlayer;
-
- sp<MediaSource> mVideoSource;
- sp<MediaSource> mVideoDecoder;
- int32_t mVideoWidth, mVideoHeight;
- int64_t mVideoPosition;
-
- int64_t mDuration;
-
- bool mPlaying;
- bool mPaused;
-
- int64_t mTimeSourceDeltaUs;
-
- sp<Surface> mSurface;
- sp<ISurface> mISurface;
- sp<IOMXRenderer> mVideoRenderer;
-
- sp<MediaPlayerBase::AudioSink> mAudioSink;
-
- Mutex mLock;
- pthread_t mVideoThread;
-
- bool mSeeking;
- int64_t mSeekTimeUs;
-
- void init();
-
- static void *VideoWrapper(void *me);
- void videoEntry();
-
- void setAudioSource(const sp<MediaSource> &source);
- void setVideoSource(const sp<MediaSource> &source);
-
- MediaSource *makeShoutcastSource(const char *path);
-
- void displayOrDiscardFrame(MediaBuffer *buffer, int64_t pts_us);
- void populateISurface();
- void depopulateISurface();
- void sendFrameToISurface(MediaBuffer *buffer);
-
- void stop();
-
- MediaPlayerImpl(const MediaPlayerImpl &);
- MediaPlayerImpl &operator=(const MediaPlayerImpl &);
-};
-
-} // namespace android
-
-#endif // MEDIA_PLAYER_IMPL_H_
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
deleted file mode 100644
index 1b39d53..0000000
--- a/include/media/stagefright/MmapSource.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MMAP_SOURCE_H_
-
-#define MMAP_SOURCE_H_
-
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-class MmapSource : public DataSource {
-public:
- MmapSource(const char *filename);
-
- // Assumes ownership of "fd".
- MmapSource(int fd, int64_t offset, int64_t length);
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off_t offset, void *data, size_t size);
- virtual status_t getSize(off_t *size);
-
-protected:
- virtual ~MmapSource();
-
-private:
- int mFd;
- void *mBase;
- size_t mSize;
-
- MmapSource(const MmapSource &);
- MmapSource &operator=(const MmapSource &);
-};
-
-} // namespace android
-
-#endif // MMAP_SOURCE_H_
-
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 7a3aee86..42c1877 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -24,11 +24,11 @@
#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h>
namespace android {
@@ -58,7 +58,7 @@
LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
mExtractor = MediaExtractor::Create(
- new MmapSource(fd, offset, length));
+ new FileSource(fd, offset, length));
return OK;
}
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index dbee451..5915105 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -3,19 +3,24 @@
#include <utils/Log.h>
#include "StagefrightPlayer.h"
-#include <media/stagefright/MediaPlayerImpl.h>
+
+#include "AwesomePlayer.h"
namespace android {
StagefrightPlayer::StagefrightPlayer()
- : mPlayer(NULL) {
+ : mPlayer(new AwesomePlayer) {
LOGV("StagefrightPlayer");
+
+ mPlayer->setListener(this);
}
StagefrightPlayer::~StagefrightPlayer() {
LOGV("~StagefrightPlayer");
reset();
- LOGV("~StagefrightPlayer done.");
+
+ delete mPlayer;
+ mPlayer = NULL;
}
status_t StagefrightPlayer::initCheck() {
@@ -25,62 +30,32 @@
status_t StagefrightPlayer::setDataSource(const char *url) {
LOGV("setDataSource('%s')", url);
-
- reset();
- mPlayer = new MediaPlayerImpl(url);
-
- status_t err = mPlayer->initCheck();
- if (err != OK) {
- delete mPlayer;
- mPlayer = NULL;
- } else {
- mPlayer->setAudioSink(mAudioSink);
- }
-
- return err;
+ return mPlayer->setDataSource(url);
}
// Warning: The filedescriptor passed into this method will only be valid until
// the method returns, if you want to keep it, dup it!
status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
-
- reset();
- mPlayer = new MediaPlayerImpl(dup(fd), offset, length);
-
- status_t err = mPlayer->initCheck();
- if (err != OK) {
- delete mPlayer;
- mPlayer = NULL;
- } else {
- mPlayer->setAudioSink(mAudioSink);
- }
-
- return err;
+ return mPlayer->setDataSource(dup(fd), offset, length);
}
status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
LOGV("setVideoSurface");
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
mPlayer->setISurface(surface);
-
return OK;
}
status_t StagefrightPlayer::prepare() {
LOGV("prepare");
- if (mPlayer == NULL) {
- return NO_INIT;
+ int32_t width, height;
+ if (mPlayer->getVideoDimensions(&width, &height) != OK) {
+ width = height = 0;
}
- sendEvent(
- MEDIA_SET_VIDEO_SIZE,
- mPlayer->getWidth(), mPlayer->getHeight());
+ sendEvent(MEDIA_SET_VIDEO_SIZE, width, height);
return OK;
}
@@ -102,92 +77,76 @@
status_t StagefrightPlayer::start() {
LOGV("start");
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- mPlayer->play();
-
- return OK;
+ return mPlayer->play();
}
status_t StagefrightPlayer::stop() {
LOGV("stop");
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- reset();
-
- return OK;
+ return pause(); // what's the difference?
}
status_t StagefrightPlayer::pause() {
LOGV("pause");
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- mPlayer->pause();
-
- return OK;
+ return mPlayer->pause();
}
bool StagefrightPlayer::isPlaying() {
LOGV("isPlaying");
- return mPlayer != NULL && mPlayer->isPlaying();
+ return mPlayer->isPlaying();
}
status_t StagefrightPlayer::seekTo(int msec) {
LOGV("seekTo");
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
status_t err = mPlayer->seekTo((int64_t)msec * 1000);
- sendEvent(MEDIA_SEEK_COMPLETE);
-
return err;
}
status_t StagefrightPlayer::getCurrentPosition(int *msec) {
LOGV("getCurrentPosition");
- if (mPlayer == NULL) {
- return NO_INIT;
+ int64_t positionUs;
+ status_t err = mPlayer->getPosition(&positionUs);
+
+ if (err != OK) {
+ return err;
}
- *msec = mPlayer->getPosition() / 1000;
+ *msec = (positionUs + 500) / 1000;
+
return OK;
}
status_t StagefrightPlayer::getDuration(int *msec) {
LOGV("getDuration");
- if (mPlayer == NULL) {
- return NO_INIT;
+ int64_t durationUs;
+ status_t err = mPlayer->getDuration(&durationUs);
+
+ if (err != OK) {
+ return err;
}
- *msec = mPlayer->getDuration() / 1000;
+ *msec = (durationUs + 500) / 1000;
+
return OK;
}
status_t StagefrightPlayer::reset() {
LOGV("reset");
- delete mPlayer;
- mPlayer = NULL;
+ mPlayer->reset();
return OK;
}
status_t StagefrightPlayer::setLooping(int loop) {
LOGV("setLooping");
- return UNKNOWN_ERROR;
+
+ return mPlayer->setLooping(loop);
}
player_type StagefrightPlayer::playerType() {
@@ -202,9 +161,7 @@
void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
MediaPlayerInterface::setAudioSink(audioSink);
- if (mPlayer != NULL) {
- mPlayer->setAudioSink(audioSink);
- }
+ mPlayer->setAudioSink(audioSink);
}
} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index f214872c..9d005cb 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -22,7 +22,7 @@
namespace android {
-class MediaPlayerImpl;
+struct AwesomePlayer;
class StagefrightPlayer : public MediaPlayerInterface {
public:
@@ -49,7 +49,7 @@
virtual void setAudioSink(const sp<AudioSink> &audioSink);
private:
- MediaPlayerImpl *mPlayer;
+ AwesomePlayer *mPlayer;
StagefrightPlayer(const StagefrightPlayer &);
StagefrightPlayer &operator=(const StagefrightPlayer &);
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 1e3c5a4..bdd7550 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -33,7 +33,10 @@
class AMRSource : public MediaSource {
public:
- AMRSource(const sp<DataSource> &source, bool isWide);
+ AMRSource(const sp<DataSource> &source,
+ const sp<MetaData> &meta,
+ size_t frameSize,
+ bool isWide);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -48,6 +51,8 @@
private:
sp<DataSource> mDataSource;
+ sp<MetaData> mMeta;
+ size_t mFrameSize;
bool mIsWide;
off_t mOffset;
@@ -61,15 +66,63 @@
////////////////////////////////////////////////////////////////////////////////
+static size_t getFrameSize(bool isWide, unsigned FT) {
+ static const size_t kFrameSizeNB[8] = {
+ 95, 103, 118, 134, 148, 159, 204, 244
+ };
+ static const size_t kFrameSizeWB[9] = {
+ 132, 177, 253, 285, 317, 365, 397, 461, 477
+ };
+
+ size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
+
+ // Round up bits to bytes and add 1 for the header byte.
+ frameSize = (frameSize + 7) / 8 + 1;
+
+ return frameSize;
+}
+
AMRExtractor::AMRExtractor(const sp<DataSource> &source)
: mDataSource(source),
mInitCheck(NO_INIT) {
String8 mimeType;
float confidence;
- if (SniffAMR(mDataSource, &mimeType, &confidence)) {
- mInitCheck = OK;
- mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
+ if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
+ return;
}
+
+ mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
+
+ mMeta = new MetaData;
+ mMeta->setCString(
+ kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
+ : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+
+ mMeta->setInt32(kKeyChannelCount, 1);
+ mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
+
+ size_t offset = mIsWide ? 9 : 6;
+ uint8_t header;
+ if (mDataSource->readAt(offset, &header, 1) != 1) {
+ return;
+ }
+
+ unsigned FT = (header >> 3) & 0x0f;
+
+ if (FT > 8 || (!mIsWide && FT > 7)) {
+ return;
+ }
+
+ mFrameSize = getFrameSize(mIsWide, FT);
+
+ off_t streamSize;
+ if (mDataSource->getSize(&streamSize) == OK) {
+ off_t numFrames = streamSize / mFrameSize;
+
+ mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
+ }
+
+ mInitCheck = OK;
}
AMRExtractor::~AMRExtractor() {
@@ -84,7 +137,7 @@
return NULL;
}
- return new AMRSource(mDataSource, mIsWide);
+ return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
}
sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -92,26 +145,17 @@
return NULL;
}
- return makeAMRFormat(mIsWide);
-}
-
-// static
-sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) {
- sp<MetaData> meta = new MetaData;
- meta->setCString(
- kKeyMIMEType, isWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
- : MEDIA_MIMETYPE_AUDIO_AMR_NB);
-
- meta->setInt32(kKeyChannelCount, 1);
- meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000);
-
- return meta;
+ return mMeta;
}
////////////////////////////////////////////////////////////////////////////////
-AMRSource::AMRSource(const sp<DataSource> &source, bool isWide)
+AMRSource::AMRSource(
+ const sp<DataSource> &source, const sp<MetaData> &meta,
+ size_t frameSize, bool isWide)
: mDataSource(source),
+ mMeta(meta),
+ mFrameSize(frameSize),
mIsWide(isWide),
mOffset(mIsWide ? 9 : 6),
mCurrentTimeUs(0),
@@ -148,13 +192,20 @@
}
sp<MetaData> AMRSource::getFormat() {
- return AMRExtractor::makeAMRFormat(mIsWide);
+ return mMeta;
}
status_t AMRSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame.
+ mCurrentTimeUs = seekFrame * 20000ll;
+ mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);
+ }
+
uint8_t header;
ssize_t n = mDataSource->readAt(mOffset, &header, 1);
@@ -180,17 +231,8 @@
return ERROR_MALFORMED;
}
- static const size_t kFrameSizeNB[8] = {
- 95, 103, 118, 134, 148, 159, 204, 244
- };
- static const size_t kFrameSizeWB[9] = {
- 132, 177, 253, 285, 317, 365, 397, 461, 477
- };
-
- size_t frameSize = mIsWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
-
- // Round up bits to bytes and add 1 for the header byte.
- frameSize = (frameSize + 7) / 8 + 1;
+ size_t frameSize = getFrameSize(mIsWide, FT);
+ CHECK_EQ(frameSize, mFrameSize);
n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index c36e769..460c496 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@
LOCAL_SRC_FILES += \
AMRExtractor.cpp \
AudioPlayer.cpp \
+ AwesomePlayer.cpp \
CachingDataSource.cpp \
CameraSource.cpp \
DataSource.cpp \
@@ -28,8 +29,6 @@
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaExtractor.cpp \
- MediaPlayerImpl.cpp \
- MmapSource.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
TimeSource.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index d7e3f66..4280683 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -47,6 +47,12 @@
}
}
+void AudioPlayer::setListenerCallback(
+ void (*notify)(void *cookie, int what), void *cookie) {
+ mListenerCallback = notify;
+ mListenerCookie = cookie;
+}
+
void AudioPlayer::setSource(const sp<MediaSource> &source) {
CHECK_EQ(mSource, NULL);
mSource = source;
@@ -195,7 +201,6 @@
mInputBuffer->release();
mInputBuffer = NULL;
}
- mSeeking = false;
}
}
@@ -205,7 +210,19 @@
CHECK((err == OK && mInputBuffer != NULL)
|| (err != OK && mInputBuffer == NULL));
+ if (mSeeking) {
+ mSeeking = false;
+
+ if (mListenerCallback) {
+ (*mListenerCallback)(mListenerCookie, SEEK_COMPLETE);
+ }
+ }
+
if (err != OK) {
+ if (mListenerCallback) {
+ (*mListenerCallback)(mListenerCookie, REACHED_EOS);
+ }
+
memset((char *)data + size_done, 0, size_remaining);
break;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
new file mode 100644
index 0000000..ed46cea
--- /dev/null
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AwesomePlayer"
+#include <utils/Log.h>
+
+#include "include/AwesomePlayer.h"
+
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+
+namespace android {
+
+struct AwesomeEvent : public TimedEventQueue::Event {
+ AwesomeEvent(AwesomePlayer *player, int32_t code)
+ : mPlayer(player),
+ mCode(code) {
+ }
+
+protected:
+ virtual ~AwesomeEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ mPlayer->onEvent(mCode);
+ }
+
+private:
+ AwesomePlayer *mPlayer;
+ int32_t mCode;
+
+ AwesomeEvent(const AwesomeEvent &);
+ AwesomeEvent &operator=(const AwesomeEvent &);
+};
+
+AwesomePlayer::AwesomePlayer()
+ : mTimeSource(NULL),
+ mAudioPlayer(NULL),
+ mLastVideoBuffer(NULL),
+ mVideoBuffer(NULL) {
+ CHECK_EQ(mClient.connect(), OK);
+
+ DataSource::RegisterDefaultSniffers();
+
+ mVideoEvent = new AwesomeEvent(this, 0);
+ mVideoEventPending = false;
+ mStreamDoneEvent = new AwesomeEvent(this, 1);
+ mStreamDoneEventPending = false;
+
+ mQueue.start();
+
+ reset();
+}
+
+AwesomePlayer::~AwesomePlayer() {
+ mQueue.stop();
+
+ reset();
+
+ mClient.disconnect();
+}
+
+void AwesomePlayer::cancelPlayerEvents() {
+ mQueue.cancelEvent(mVideoEvent->eventID());
+ mVideoEventPending = false;
+ mQueue.cancelEvent(mStreamDoneEvent->eventID());
+ mStreamDoneEventPending = false;
+}
+
+void AwesomePlayer::setListener(const sp<MediaPlayerBase> &listener) {
+ Mutex::Autolock autoLock(mLock);
+ mListener = listener;
+}
+
+status_t AwesomePlayer::setDataSource(const char *uri) {
+ Mutex::Autolock autoLock(mLock);
+
+ reset_l();
+
+ sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ return setDataSource_l(extractor);
+}
+
+status_t AwesomePlayer::setDataSource(
+ int fd, int64_t offset, int64_t length) {
+ Mutex::Autolock autoLock(mLock);
+
+ reset_l();
+
+ sp<DataSource> source = new FileSource(fd, offset, length);
+
+ status_t err = source->initCheck();
+
+ if (err != OK) {
+ return err;
+ }
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(source);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ return setDataSource_l(extractor);
+}
+
+status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+ reset_l();
+
+ bool haveAudio = false;
+ bool haveVideo = false;
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
+ if (setVideoSource(extractor->getTrack(i)) == OK) {
+ haveVideo = true;
+ }
+ } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
+ if (setAudioSource(extractor->getTrack(i)) == OK) {
+ haveAudio = true;
+ }
+ }
+
+ if (haveAudio && haveVideo) {
+ break;
+ }
+ }
+
+ return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
+}
+
+void AwesomePlayer::reset() {
+ Mutex::Autolock autoLock(mLock);
+ reset_l();
+}
+
+void AwesomePlayer::reset_l() {
+ cancelPlayerEvents();
+
+ if (mLastVideoBuffer) {
+ mLastVideoBuffer->release();
+ mLastVideoBuffer = NULL;
+ }
+
+ if (mVideoBuffer) {
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+
+ if (mVideoSource != NULL) {
+ mVideoSource->stop();
+ mVideoSource.clear();
+ }
+
+ mAudioSource.clear();
+
+ if (mTimeSource != mAudioPlayer) {
+ delete mTimeSource;
+ }
+ mTimeSource = NULL;
+
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+
+ mVideoRenderer.clear();
+
+ mDurationUs = -1;
+ mFlags = 0;
+ mVideoWidth = mVideoHeight = -1;
+ mTimeSourceDeltaUs = 0;
+ mVideoTimeUs = 0;
+
+ mSeeking = false;
+ mSeekTimeUs = 0;
+}
+
+// static
+void AwesomePlayer::AudioNotify(void *_me, int what) {
+ AwesomePlayer *me = (AwesomePlayer *)_me;
+
+ Mutex::Autolock autoLock(me->mLock);
+
+ switch (what) {
+ case AudioPlayer::REACHED_EOS:
+ me->postStreamDoneEvent_l();
+ break;
+
+ case AudioPlayer::SEEK_COMPLETE:
+ {
+ if (me->mListener != NULL) {
+ me->mListener->sendEvent(MEDIA_SEEK_COMPLETE);
+ }
+
+ break;
+ }
+
+ default:
+ CHECK(!"should not be here.");
+ break;
+ }
+}
+
+void AwesomePlayer::onStreamDone() {
+ // Posted whenever any stream finishes playing.
+
+ Mutex::Autolock autoLock(mLock);
+ mStreamDoneEventPending = false;
+
+ if (mFlags & LOOPING) {
+ seekTo_l(0);
+
+ if (mVideoRenderer != NULL) {
+ postVideoEvent_l();
+ }
+ } else {
+ if (mListener != NULL) {
+ mListener->sendEvent(MEDIA_PLAYBACK_COMPLETE);
+ }
+
+ pause_l();
+ }
+}
+
+status_t AwesomePlayer::play() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mFlags & PLAYING) {
+ return OK;
+ }
+
+ mFlags |= PLAYING;
+ mFlags |= FIRST_FRAME;
+
+ if (mAudioSource != NULL) {
+ if (mAudioPlayer == NULL) {
+ if (mAudioSink != NULL) {
+ mAudioPlayer = new AudioPlayer(mAudioSink);
+
+ mAudioPlayer->setListenerCallback(
+ &AwesomePlayer::AudioNotify, this);
+
+ mAudioPlayer->setSource(mAudioSource);
+ mAudioPlayer->start();
+
+ delete mTimeSource;
+ mTimeSource = mAudioPlayer;
+
+ // If there was a seek request while we were paused
+ // and we're just starting up again, honor the request now.
+ seekAudioIfNecessary_l();
+ }
+ } else {
+ mAudioPlayer->resume();
+ }
+ }
+
+ if (mTimeSource == NULL && mAudioPlayer == NULL) {
+ mTimeSource = new SystemTimeSource;
+ }
+
+ if (mVideoSource != NULL) {
+ if (mVideoRenderer == NULL) {
+ initRenderer_l();
+ }
+
+ if (mVideoRenderer != NULL) {
+ // Kick off video playback
+ postVideoEvent_l();
+ }
+ }
+
+ return OK;
+}
+
+void AwesomePlayer::initRenderer_l() {
+ if (mISurface != NULL) {
+ sp<MetaData> meta = mVideoSource->getFormat();
+
+ int32_t format;
+ const char *component;
+ int32_t decodedWidth, decodedHeight;
+ CHECK(meta->findInt32(kKeyColorFormat, &format));
+ CHECK(meta->findCString(kKeyDecoderComponent, &component));
+ CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
+ CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
+
+ mVideoRenderer =
+ mClient.interface()->createRenderer(
+ mISurface, component,
+ (OMX_COLOR_FORMATTYPE)format,
+ decodedWidth, decodedHeight,
+ mVideoWidth, mVideoHeight);
+ }
+}
+
+status_t AwesomePlayer::pause() {
+ Mutex::Autolock autoLock(mLock);
+ return pause_l();
+}
+
+status_t AwesomePlayer::pause_l() {
+ if (!(mFlags & PLAYING)) {
+ return OK;
+ }
+
+ cancelPlayerEvents();
+
+ if (mAudioPlayer != NULL) {
+ mAudioPlayer->pause();
+ }
+
+ mFlags &= ~PLAYING;
+
+ return OK;
+}
+
+bool AwesomePlayer::isPlaying() const {
+ Mutex::Autolock autoLock(mLock);
+
+ return mFlags & PLAYING;
+}
+
+void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
+ Mutex::Autolock autoLock(mLock);
+
+ mISurface = isurface;
+}
+
+void AwesomePlayer::setAudioSink(
+ const sp<MediaPlayerBase::AudioSink> &audioSink) {
+ Mutex::Autolock autoLock(mLock);
+
+ mAudioSink = audioSink;
+}
+
+status_t AwesomePlayer::setLooping(bool shouldLoop) {
+ Mutex::Autolock autoLock(mLock);
+
+ mFlags = mFlags & ~LOOPING;
+
+ if (shouldLoop) {
+ mFlags |= LOOPING;
+ }
+
+ return OK;
+}
+
+status_t AwesomePlayer::getDuration(int64_t *durationUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mDurationUs < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ *durationUs = mDurationUs;
+
+ return OK;
+}
+
+status_t AwesomePlayer::getPosition(int64_t *positionUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mVideoRenderer != NULL) {
+ *positionUs = mVideoTimeUs;
+ } else if (mAudioPlayer != NULL) {
+ *positionUs = mAudioPlayer->getMediaTimeUs();
+ } else {
+ *positionUs = 0;
+ }
+
+ return OK;
+}
+
+status_t AwesomePlayer::seekTo(int64_t timeUs) {
+ Mutex::Autolock autoLock(mLock);
+ return seekTo_l(timeUs);
+}
+
+status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
+ mSeeking = true;
+ mSeekTimeUs = timeUs;
+
+ seekAudioIfNecessary_l();
+
+ return OK;
+}
+
+void AwesomePlayer::seekAudioIfNecessary_l() {
+ if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) {
+ mAudioPlayer->seekTo(mSeekTimeUs);
+
+ mSeeking = false;
+ }
+}
+
+status_t AwesomePlayer::getVideoDimensions(
+ int32_t *width, int32_t *height) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mVideoWidth < 0 || mVideoHeight < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ *width = mVideoWidth;
+ *height = mVideoHeight;
+
+ return OK;
+}
+
+status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
+ if (source == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ mAudioSource = OMXCodec::Create(
+ mClient.interface(), source->getFormat(),
+ false, // createEncoder
+ source);
+
+ if (mAudioSource != NULL) {
+ int64_t durationUs;
+ if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+ if (mDurationUs < 0 || durationUs > mDurationUs) {
+ mDurationUs = durationUs;
+ }
+ }
+ }
+
+ return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
+}
+
+status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
+ if (source == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ mVideoSource = OMXCodec::Create(
+ mClient.interface(), source->getFormat(),
+ false, // createEncoder
+ source);
+
+ if (mVideoSource != NULL) {
+ int64_t durationUs;
+ if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+ if (mDurationUs < 0 || durationUs > mDurationUs) {
+ mDurationUs = durationUs;
+ }
+ }
+
+ CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
+ CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
+
+ mVideoSource->start();
+ }
+
+ return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
+}
+
+void AwesomePlayer::onEvent(int32_t code) {
+ if (code == 1) {
+ onStreamDone();
+ return;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ mVideoEventPending = false;
+
+ if (mSeeking) {
+ if (mLastVideoBuffer) {
+ mLastVideoBuffer->release();
+ mLastVideoBuffer = NULL;
+ }
+
+ if (mVideoBuffer) {
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+ }
+
+ if (!mVideoBuffer) {
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
+
+ options.setSeekTo(mSeekTimeUs);
+ }
+ for (;;) {
+ status_t err = mVideoSource->read(&mVideoBuffer, &options);
+
+ if (err != OK) {
+ CHECK_EQ(mVideoBuffer, NULL);
+
+ if (err == INFO_FORMAT_CHANGED) {
+ LOGV("VideoSource signalled format change.");
+
+ initRenderer_l();
+ continue;
+ }
+
+ postStreamDoneEvent_l();
+ return;
+ }
+
+ break;
+ }
+ }
+
+ int64_t timeUs;
+ CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+ mVideoTimeUs = timeUs;
+
+ if (mSeeking) {
+ if (mAudioPlayer != NULL) {
+ LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
+
+ mAudioPlayer->seekTo(timeUs);
+ } else {
+ // If we're playing video only, report seek complete now,
+ // otherwise audio player will notify us later.
+ if (mListener != NULL) {
+ mListener->sendEvent(MEDIA_SEEK_COMPLETE);
+ }
+ }
+
+ mFlags |= FIRST_FRAME;
+ mSeeking = false;
+ }
+
+ if (mFlags & FIRST_FRAME) {
+ mFlags &= ~FIRST_FRAME;
+
+ mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
+ }
+
+ int64_t realTimeUs, mediaTimeUs;
+ if (mAudioPlayer != NULL
+ && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
+ mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
+ }
+
+ int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
+
+ int64_t latenessUs = nowUs - timeUs;
+
+ if (latenessUs > 20000) {
+ // We're more than 20ms late.
+ LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
+
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+
+ postVideoEvent_l();
+ return;
+ }
+
+ if (latenessUs < -10000) {
+ // We're more than 10ms early.
+
+ postVideoEvent_l(10000);
+ return;
+ }
+
+ void *id;
+ if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) {
+ mVideoRenderer->render((IOMX::buffer_id)id);
+ }
+
+ if (mLastVideoBuffer) {
+ mLastVideoBuffer->release();
+ mLastVideoBuffer = NULL;
+ }
+ mLastVideoBuffer = mVideoBuffer;
+ mVideoBuffer = NULL;
+
+ postVideoEvent_l();
+}
+
+void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
+ if (mVideoEventPending) {
+ return;
+ }
+
+ mVideoEventPending = true;
+ mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void AwesomePlayer::postStreamDoneEvent_l() {
+ if (mStreamDoneEventPending) {
+ return;
+ }
+ mStreamDoneEventPending = true;
+ mQueue.postEvent(mStreamDoneEvent);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 19a1f85..9d3deb7 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -25,10 +25,10 @@
#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MmapSource.h>
#include <utils/String8.h>
namespace android {
@@ -70,13 +70,13 @@
const char *uri, const char *mime) {
sp<DataSource> source;
if (!strncasecmp("file://", uri, 7)) {
- source = new MmapSource(uri + 7);
+ source = new FileSource(uri + 7);
} else if (!strncasecmp("http://", uri, 7)) {
source = new HTTPDataSource(uri);
source = new CachingDataSource(source, 64 * 1024, 10);
} else {
// Assume it's a filename.
- source = new MmapSource(uri);
+ source = new FileSource(uri);
}
if (source == NULL || source->initCheck() != OK) {
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
deleted file mode 100644
index c1044a3..0000000
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayerImpl"
-#include "utils/Log.h"
-
-#include "include/stagefright_string.h"
-#include "include/HTTPStream.h"
-
-#include <OMX_Component.h>
-
-#include <unistd.h>
-
-#include <media/stagefright/AudioPlayer.h>
-// #include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaPlayerImpl.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/TimeSource.h>
-#include <ui/PixelFormat.h>
-#include <ui/Surface.h>
-
-namespace android {
-
-MediaPlayerImpl::MediaPlayerImpl(const char *uri)
- : mInitCheck(NO_INIT),
- mTimeSource(NULL),
- mAudioPlayer(NULL),
- mVideoWidth(0),
- mVideoHeight(0),
- mVideoPosition(0),
- mDuration(0),
- mPlaying(false),
- mPaused(false),
- mSeeking(false) {
- LOGV("MediaPlayerImpl(%s)", uri);
- DataSource::RegisterDefaultSniffers();
-
- status_t err = mClient.connect();
- if (err != OK) {
- LOGE("Failed to connect to OMXClient.");
- return;
- }
-
- if (!strncasecmp("shoutcast://", uri, 12)) {
- setAudioSource(makeShoutcastSource(uri));
-#if 0
- } else if (!strncasecmp("camera:", uri, 7)) {
- mVideoWidth = 480;
- mVideoHeight = 320;
- mVideoDecoder = CameraSource::Create();
-#endif
- } else {
- mExtractor = MediaExtractor::CreateFromURI(uri);
-
- if (mExtractor == NULL) {
- return;
- }
- }
-
- init();
-
- mInitCheck = OK;
-}
-
-MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
- : mInitCheck(NO_INIT),
- mTimeSource(NULL),
- mAudioPlayer(NULL),
- mVideoWidth(0),
- mVideoHeight(0),
- mVideoPosition(0),
- mDuration(0),
- mPlaying(false),
- mPaused(false),
- mSeeking(false) {
- LOGV("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
- DataSource::RegisterDefaultSniffers();
-
- status_t err = mClient.connect();
- if (err != OK) {
- LOGE("Failed to connect to OMXClient.");
- return;
- }
-
- mExtractor = MediaExtractor::Create(
- new MmapSource(fd, offset, length));
-
- if (mExtractor == NULL) {
- return;
- }
-
- init();
-
- mInitCheck = OK;
-}
-
-status_t MediaPlayerImpl::initCheck() const {
- return mInitCheck;
-}
-
-MediaPlayerImpl::~MediaPlayerImpl() {
- stop();
- setSurface(NULL);
-
- if (mInitCheck == OK) {
- mClient.disconnect();
- }
-
- LOGV("~MediaPlayerImpl done.");
-}
-
-void MediaPlayerImpl::play() {
- LOGV("play");
-
- if (mPlaying) {
- if (mPaused) {
- if (mAudioSource != NULL) {
- mAudioPlayer->resume();
- }
- mPaused = false;
- }
- return;
- }
-
- mPlaying = true;
-
- if (mAudioSource != NULL) {
- mAudioPlayer = new AudioPlayer(mAudioSink);
- mAudioPlayer->setSource(mAudioDecoder);
-
- if (mVideoDecoder == NULL) {
- // If there is no video, start playing right away,
- // otherwise we'll start the audio player after we decode
- // the first video frame, this way we won't be behind right
- // away.
- mAudioPlayer->start();
- }
-
- mTimeSource = mAudioPlayer;
- } else {
- mTimeSource = new SystemTimeSource;
- }
-
- if (mVideoDecoder != NULL) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- pthread_create(&mVideoThread, &attr, VideoWrapper, this);
-
- pthread_attr_destroy(&attr);
- }
-}
-
-void MediaPlayerImpl::pause() {
- if (!mPlaying || mPaused) {
- return;
- }
-
- if (mAudioSource != NULL) {
- mAudioPlayer->pause();
- }
-
- mPaused = true;
-}
-
-void MediaPlayerImpl::stop() {
- if (!mPlaying) {
- return;
- }
-
- mPlaying = false;
-
- if (mVideoDecoder != NULL) {
- void *dummy;
- pthread_join(mVideoThread, &dummy);
- }
-
- if (mAudioSource != NULL) {
- mAudioPlayer->stop();
-
- delete mAudioPlayer;
- mAudioPlayer = NULL;
- } else {
- delete mTimeSource;
- }
-
- mTimeSource = NULL;
-}
-
-// static
-void *MediaPlayerImpl::VideoWrapper(void *me) {
- ((MediaPlayerImpl *)me)->videoEntry();
-
- return NULL;
-}
-
-void MediaPlayerImpl::videoEntry() {
- bool firstFrame = true;
- bool eof = false;
-
- status_t err = mVideoDecoder->start();
- CHECK_EQ(err, OK);
-
- while (mPlaying) {
- MediaBuffer *buffer;
-
- MediaSource::ReadOptions options;
- bool seeking = false;
-
- {
- Mutex::Autolock autoLock(mLock);
- if (mSeeking) {
- LOGV("seek-options to %lld", mSeekTimeUs);
- options.setSeekTo(mSeekTimeUs);
-
- mSeeking = false;
- seeking = true;
- eof = false;
- }
- }
-
- if (eof || mPaused) {
- usleep(100000);
- continue;
- }
-
- status_t err = mVideoDecoder->read(&buffer, &options);
- CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
-
- if (err == INFO_FORMAT_CHANGED) {
- LOGV("format changed.");
- depopulateISurface();
- populateISurface();
- continue;
- }
-
- if (err == ERROR_END_OF_STREAM || err != OK) {
- eof = true;
- continue;
- }
-
- if (buffer->range_length() == 0) {
- // The final buffer is empty.
- buffer->release();
- continue;
- }
-
- int64_t pts_us;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &pts_us));
-
- {
- Mutex::Autolock autoLock(mLock);
- mVideoPosition = pts_us;
-
- LOGV("now_video = %.2f secs (%lld ms)",
- pts_us / 1E6, (pts_us + 500) / 1000);
- }
-
- if (seeking && mAudioPlayer != NULL) {
- // Now that we know where exactly video seeked (taking sync-samples
- // into account), we will seek the audio track to the same time.
- mAudioPlayer->seekTo(pts_us);
- }
-
- if (firstFrame || seeking) {
- if (firstFrame && mAudioPlayer != NULL) {
- // We've deferred starting the audio player until now.
- mAudioPlayer->start();
- }
- mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - pts_us;
- firstFrame = false;
- }
-
- displayOrDiscardFrame(buffer, pts_us);
- }
-
- mVideoDecoder->stop();
-}
-
-void MediaPlayerImpl::displayOrDiscardFrame(
- MediaBuffer *buffer, int64_t pts_us) {
- for (;;) {
- if (!mPlaying || mPaused) {
- buffer->release();
- buffer = NULL;
-
- return;
- }
-
- int64_t realtime_us, mediatime_us;
- if (mAudioPlayer != NULL
- && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
- mTimeSourceDeltaUs = realtime_us - mediatime_us;
- LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
- }
-
- int64_t now_us = mTimeSource->getRealTimeUs();
- now_us -= mTimeSourceDeltaUs;
-
- int64_t delay_us = pts_us - now_us;
-
- if (delay_us < -15000) {
- // We're late.
-
- LOGV("we're late by %lld ms, dropping a frame\n",
- -delay_us / 1000);
-
- buffer->release();
- buffer = NULL;
- return;
- } else if (delay_us > 100000) {
- LOGV("we're much too early (by %lld ms)\n",
- delay_us / 1000);
- usleep(100000);
- continue;
- } else if (delay_us > 0) {
- usleep(delay_us);
- }
-
- break;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- if (mVideoRenderer.get() != NULL) {
- sendFrameToISurface(buffer);
- }
- }
-
- buffer->release();
- buffer = NULL;
-}
-
-void MediaPlayerImpl::init() {
- if (mExtractor != NULL) {
- size_t num_tracks = mExtractor->countTracks();
-
- mDuration = 0;
-
- for (size_t i = 0; i < num_tracks; ++i) {
- const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
- CHECK(meta != NULL);
-
- const char *mime;
- if (!meta->findCString(kKeyMIMEType, &mime)) {
- continue;
- }
-
- bool is_audio = false;
- bool is_acceptable = false;
- if (!strncasecmp(mime, "audio/", 6)) {
- is_audio = true;
- is_acceptable = (mAudioSource == NULL);
- } else if (!strncasecmp(mime, "video/", 6)) {
- is_acceptable = (mVideoSource == NULL);
- }
-
- if (!is_acceptable) {
- continue;
- }
-
- sp<MediaSource> source = mExtractor->getTrack(i);
-
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDuration) {
- mDuration = durationUs;
- }
- }
-
- if (is_audio) {
- setAudioSource(source);
- } else {
- setVideoSource(source);
- }
- }
- }
-}
-
-void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
- LOGV("setAudioSource");
- mAudioSource = source;
-
- sp<MetaData> meta = source->getFormat();
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
- mAudioDecoder = source;
- } else {
- mAudioDecoder = OMXCodec::Create(
- mClient.interface(), meta, false /* createEncoder */, source);
- }
-}
-
-void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
- LOGV("setVideoSource");
- mVideoSource = source;
-
- sp<MetaData> meta = source->getFormat();
-
- bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
- CHECK(success);
-
- success = meta->findInt32(kKeyHeight, &mVideoHeight);
- CHECK(success);
-
- mVideoDecoder = OMXCodec::Create(
- mClient.interface(), meta, false /* createEncoder */, source);
-
- if (mISurface.get() != NULL || mSurface.get() != NULL) {
- depopulateISurface();
- populateISurface();
- }
-}
-
-void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
- LOGV("setSurface %p", surface.get());
- Mutex::Autolock autoLock(mLock);
-
- depopulateISurface();
-
- mSurface = surface;
- mISurface = NULL;
-
- if (mSurface.get() != NULL) {
- populateISurface();
- }
-}
-
-void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
- LOGV("setISurface %p", isurface.get());
- Mutex::Autolock autoLock(mLock);
-
- depopulateISurface();
-
- mSurface = NULL;
- mISurface = isurface;
-
- if (mISurface.get() != NULL) {
- populateISurface();
- }
-}
-
-MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
- if (strncasecmp(uri, "shoutcast://", 12)) {
- return NULL;
- }
-
- string host;
- string path;
- int port;
-
- char *slash = strchr(uri + 12, '/');
- if (slash == NULL) {
- host = uri + 12;
- path = "/";
- } else {
- host = string(uri + 12, slash - (uri + 12));
- path = slash;
- }
-
- char *colon = strchr(host.c_str(), ':');
- if (colon == NULL) {
- port = 80;
- } else {
- char *end;
- long tmp = strtol(colon + 1, &end, 10);
- CHECK(end > colon + 1);
- CHECK(tmp > 0 && tmp < 65536);
- port = tmp;
-
- host = string(host, 0, colon - host.c_str());
- }
-
- LOGV("Connecting to host '%s', port %d, path '%s'",
- host.c_str(), port, path.c_str());
-
- HTTPStream *http = new HTTPStream;
- int http_status;
-
- for (;;) {
- status_t err = http->connect(host.c_str(), port);
- CHECK_EQ(err, OK);
-
- err = http->send("GET ");
- err = http->send(path.c_str());
- err = http->send(" HTTP/1.1\r\n");
- err = http->send("Host: ");
- err = http->send(host.c_str());
- err = http->send("\r\n");
- err = http->send("Icy-MetaData: 1\r\n\r\n");
-
- CHECK_EQ(OK, http->receive_header(&http_status));
-
- if (http_status == 301 || http_status == 302) {
- string location;
- CHECK(http->find_header_value("Location", &location));
-
- CHECK(string(location, 0, 7) == "http://");
- location.erase(0, 7);
- string::size_type slashPos = location.find('/');
- if (slashPos == string::npos) {
- slashPos = location.size();
- location += '/';
- }
-
- http->disconnect();
-
- LOGV("Redirecting to %s\n", location.c_str());
-
- host = string(location, 0, slashPos);
-
- string::size_type colonPos = host.find(':');
- if (colonPos != string::npos) {
- const char *start = host.c_str() + colonPos + 1;
- char *end;
- long tmp = strtol(start, &end, 10);
- CHECK(end > start && (*end == '\0'));
-
- port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
- } else {
- port = 80;
- }
-
- path = string(location, slashPos);
-
- continue;
- }
-
- break;
- }
-
- if (http_status != 200) {
- LOGE("Connection failed: http_status = %d", http_status);
- return NULL;
- }
-
- MediaSource *source = new ShoutcastSource(http);
-
- return source;
-}
-
-bool MediaPlayerImpl::isPlaying() const {
- return mPlaying && !mPaused;
-}
-
-int64_t MediaPlayerImpl::getDuration() {
- return mDuration;
-}
-
-int64_t MediaPlayerImpl::getPosition() {
- int64_t position = 0;
- if (mVideoSource != NULL) {
- Mutex::Autolock autoLock(mLock);
- position = mVideoPosition;
- } else if (mAudioPlayer != NULL) {
- position = mAudioPlayer->getMediaTimeUs();
- }
-
- return position;
-}
-
-status_t MediaPlayerImpl::seekTo(int64_t time) {
- LOGV("seekTo %lld", time);
-
- if (mPaused) {
- return UNKNOWN_ERROR;
- }
-
- if (mVideoSource == NULL && mAudioPlayer != NULL) {
- mAudioPlayer->seekTo(time);
- } else {
- Mutex::Autolock autoLock(mLock);
- mSeekTimeUs = time;
- mSeeking = true;
- }
-
- return OK;
-}
-
-void MediaPlayerImpl::populateISurface() {
- if (mVideoSource == NULL) {
- return;
- }
-
- sp<MetaData> meta = mVideoDecoder->getFormat();
-
- int32_t format;
- const char *component;
- int32_t decodedWidth, decodedHeight;
- bool success = meta->findInt32(kKeyColorFormat, &format);
- success = success && meta->findCString(kKeyDecoderComponent, &component);
- success = success && meta->findInt32(kKeyWidth, &decodedWidth);
- success = success && meta->findInt32(kKeyHeight, &decodedHeight);
- CHECK(success);
-
- LOGV("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
- mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
-
- if (mSurface.get() != NULL) {
- mVideoRenderer =
- mClient.interface()->createRenderer(
- mSurface, component,
- (OMX_COLOR_FORMATTYPE)format,
- decodedWidth, decodedHeight,
- mVideoWidth, mVideoHeight);
- } else {
- mVideoRenderer =
- mClient.interface()->createRenderer(
- mISurface, component,
- (OMX_COLOR_FORMATTYPE)format,
- decodedWidth, decodedHeight,
- mVideoWidth, mVideoHeight);
- }
-}
-
-void MediaPlayerImpl::depopulateISurface() {
- mVideoRenderer.clear();
-}
-
-void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
- void *id;
- if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
- mVideoRenderer->render((IOMX::buffer_id)id);
- }
-}
-
-void MediaPlayerImpl::setAudioSink(
- const sp<MediaPlayerBase::AudioSink> &audioSink) {
- LOGV("setAudioSink %p", audioSink.get());
- mAudioSink = audioSink;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
deleted file mode 100644
index 42749cf..0000000
--- a/media/libstagefright/MmapSource.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MmapSource"
-#include <utils/Log.h>
-
-#include <sys/mman.h>
-
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MmapSource.h>
-
-namespace android {
-
-MmapSource::MmapSource(const char *filename)
- : mFd(open(filename, O_RDONLY)),
- mBase(NULL),
- mSize(0) {
- LOGV("MmapSource '%s'", filename);
-
- if (mFd < 0) {
- return;
- }
-
- off_t size = lseek(mFd, 0, SEEK_END);
- mSize = (size_t)size;
-
- mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, 0);
-
- if (mBase == (void *)-1) {
- mBase = NULL;
-
- close(mFd);
- mFd = -1;
- }
-}
-
-MmapSource::MmapSource(int fd, int64_t offset, int64_t length)
- : mFd(fd),
- mBase(NULL),
- mSize(length) {
- LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length);
- CHECK(fd >= 0);
-
- mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset);
-
- if (mBase == (void *)-1) {
- mBase = NULL;
-
- close(mFd);
- mFd = -1;
- }
-
-}
-
-MmapSource::~MmapSource() {
- if (mFd != -1) {
- munmap(mBase, mSize);
- mBase = NULL;
- mSize = 0;
-
- close(mFd);
- mFd = -1;
- }
-}
-
-status_t MmapSource::initCheck() const {
- return mFd == -1 ? NO_INIT : OK;
-}
-
-ssize_t MmapSource::readAt(off_t offset, void *data, size_t size) {
- LOGV("readAt offset:%ld data:%p size:%d", offset, data, size);
- CHECK(offset >= 0);
-
- size_t avail = 0;
- if (offset >= 0 && offset < (off_t)mSize) {
- avail = mSize - offset;
- }
-
- if (size > avail) {
- size = avail;
- }
-
- memcpy(data, (const uint8_t *)mBase + offset, size);
-
- return (ssize_t)size;
-}
-
-status_t MmapSource::getSize(off_t *size) {
- *size = mSize;
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d36653e..9297aff0 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -30,7 +30,6 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/Utils.h>
#include <utils/Vector.h>
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index fa68771..d079e70 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -135,7 +135,9 @@
}
bool TimedEventQueue::cancelEvent(event_id id) {
- CHECK(id != 0);
+ if (id == 0) {
+ return false;
+ }
cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */);
@@ -162,6 +164,7 @@
mQueueHeadChangedCondition.signal();
}
+ (*it).event->setEventID(0);
it = mQueue.erase(it);
if (stopAfterFirstMatch) {
@@ -228,7 +231,12 @@
}
}
+ if (mQueue.empty()) {
+ continue;
+ }
+
event = (*it).event;
+ event->setEventID(0);
mQueue.erase(it);
}
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index debf006..1972a1c 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -32,14 +32,14 @@
virtual sp<MediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
- static sp<MetaData> makeAMRFormat(bool isWide);
-
protected:
virtual ~AMRExtractor();
private:
sp<DataSource> mDataSource;
+ sp<MetaData> mMeta;
status_t mInitCheck;
+ size_t mFrameSize;
bool mIsWide;
AMRExtractor(const AMRExtractor &);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
new file mode 100644
index 0000000..2727c3c
--- /dev/null
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AWESOME_PLAYER_H_
+
+#define AWESOME_PLAYER_H_
+
+#include "TimedEventQueue.h"
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaBuffer;
+struct MediaExtractor;
+struct MediaSource;
+struct AudioPlayer;
+struct TimeSource;
+
+struct AwesomePlayer {
+ AwesomePlayer();
+ ~AwesomePlayer();
+
+ void setListener(const sp<MediaPlayerBase> &listener);
+
+ status_t setDataSource(const char *uri);
+ status_t setDataSource(int fd, int64_t offset, int64_t length);
+
+ void reset();
+
+ status_t play();
+ status_t pause();
+
+ bool isPlaying() const;
+
+ void setISurface(const sp<ISurface> &isurface);
+ void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
+ status_t setLooping(bool shouldLoop);
+
+ status_t getDuration(int64_t *durationUs);
+ status_t getPosition(int64_t *positionUs);
+
+ status_t seekTo(int64_t timeUs);
+
+ status_t getVideoDimensions(int32_t *width, int32_t *height) const;
+
+private:
+ friend struct AwesomeEvent;
+
+ enum Flags {
+ PLAYING = 1,
+ LOOPING = 2,
+ FIRST_FRAME = 4,
+ };
+
+ mutable Mutex mLock;
+
+ OMXClient mClient;
+ TimedEventQueue mQueue;
+ sp<MediaPlayerBase> mListener;
+
+ sp<ISurface> mISurface;
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ TimeSource *mTimeSource;
+
+ sp<MediaSource> mVideoSource;
+ sp<IOMXRenderer> mVideoRenderer;
+
+ sp<MediaSource> mAudioSource;
+ AudioPlayer *mAudioPlayer;
+ int64_t mDurationUs;
+
+ uint32_t mFlags;
+
+ int32_t mVideoWidth, mVideoHeight;
+ int64_t mTimeSourceDeltaUs;
+ int64_t mVideoTimeUs;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ sp<TimedEventQueue::Event> mVideoEvent;
+ bool mVideoEventPending;
+ sp<TimedEventQueue::Event> mStreamDoneEvent;
+ bool mStreamDoneEventPending;
+
+ void postVideoEvent_l(int64_t delayUs = -1);
+ void postStreamDoneEvent_l();
+
+ MediaBuffer *mLastVideoBuffer;
+ MediaBuffer *mVideoBuffer;
+
+ status_t setDataSource_l(const sp<MediaExtractor> &extractor);
+ void reset_l();
+ status_t seekTo_l(int64_t timeUs);
+ status_t pause_l();
+ void initRenderer_l();
+ void seekAudioIfNecessary_l();
+
+ void cancelPlayerEvents();
+
+ status_t setAudioSource(const sp<MediaSource> &source);
+ status_t setVideoSource(const sp<MediaSource> &source);
+
+ void onEvent(int32_t code);
+
+ static void AudioNotify(void *me, int what);
+ void onStreamDone();
+
+ AwesomePlayer(const AwesomePlayer &);
+ AwesomePlayer &operator=(const AwesomePlayer &);
+};
+
+} // namespace android
+
+#endif // AWESOME_PLAYER_H_
+
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 58fa69e..38ccde0 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -43,6 +43,8 @@
private static final int BIT_HEADSET = (1 << 0);
private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
private int mHeadsetState;
private int mPrevHeadsetState;
@@ -100,68 +102,76 @@
private synchronized final void update(String newName, int newState) {
// Retain only relevant bits
- int headsetState = newState & (BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ int headsetState = newState & SUPPORTED_HEADSETS;
+ int newOrOld = headsetState | mHeadsetState;
+ // reject all suspect transitions: only accept state changes from:
+ // - a: 0 heaset to 1 headset
+ // - b: 1 headset to 0 headset
+ if (mHeadsetState == headsetState || ((newOrOld & (newOrOld - 1)) != 0)) {
+ return;
+ }
- if (headsetState != mHeadsetState) {
- boolean isUnplug = false;
- if (((mHeadsetState & BIT_HEADSET) != 0 && (headsetState & BIT_HEADSET) == 0) ||
- ((mHeadsetState & BIT_HEADSET_NO_MIC) != 0 && (headsetState & BIT_HEADSET_NO_MIC) == 0)) {
- isUnplug = true;
- }
- mHeadsetName = newName;
- mPrevHeadsetState = mHeadsetState;
- mHeadsetState = headsetState;
- mPendingIntent = true;
+ mHeadsetName = newName;
+ mPrevHeadsetState = mHeadsetState;
+ mHeadsetState = headsetState;
+ mPendingIntent = true;
- if (isUnplug) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
+ if (headsetState == 0) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
- // It can take hundreds of ms flush the audio pipeline after
- // apps pause audio playback, but audio route changes are
- // immediate, so delay the route change by 1000ms.
- // This could be improved once the audio sub-system provides an
- // interface to clear the audio pipeline.
- mWakeLock.acquire();
- mHandler.sendEmptyMessageDelayed(0, 1000);
- } else {
- sendIntent();
- mPendingIntent = false;
+ // It can take hundreds of ms flush the audio pipeline after
+ // apps pause audio playback, but audio route changes are
+ // immediate, so delay the route change by 1000ms.
+ // This could be improved once the audio sub-system provides an
+ // interface to clear the audio pipeline.
+ mWakeLock.acquire();
+ mHandler.sendEmptyMessageDelayed(0, 1000);
+ } else {
+ sendIntents();
+ mPendingIntent = false;
+ }
+ }
+
+ private synchronized final void sendIntents() {
+ int allHeadsets = SUPPORTED_HEADSETS;
+ for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
+ if ((curHeadset & allHeadsets) != 0) {
+ sendIntent(curHeadset);
+ allHeadsets &= ~curHeadset;
}
}
}
- private synchronized final void sendIntent() {
- // Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- int state = 0;
- int microphone = 0;
+ private final void sendIntent(int headset) {
+ if ((mHeadsetState & headset) != (mPrevHeadsetState & headset)) {
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ int state = 0;
+ int microphone = 0;
- if ((mHeadsetState & BIT_HEADSET) != (mPrevHeadsetState & BIT_HEADSET)) {
- microphone = 1;
- if ((mHeadsetState & BIT_HEADSET) != 0) {
+ if ((headset & HEADSETS_WITH_MIC) != 0) {
+ microphone = 1;
+ }
+ if ((mHeadsetState & headset) != 0) {
state = 1;
}
- } else if ((mHeadsetState & BIT_HEADSET_NO_MIC) != (mPrevHeadsetState & BIT_HEADSET_NO_MIC)) {
- if ((mHeadsetState & BIT_HEADSET_NO_MIC) != 0) {
- state = 1;
- }
+ intent.putExtra("state", state);
+ intent.putExtra("name", mHeadsetName);
+ intent.putExtra("microphone", microphone);
+
+ if (LOG) Log.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+mHeadsetName+" mic: "+microphone);
+ // TODO: Should we require a permission?
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
}
-
- intent.putExtra("state", state);
- intent.putExtra("name", mHeadsetName);
- intent.putExtra("microphone", microphone);
-
- // TODO: Should we require a permission?
- ActivityManagerNative.broadcastStickyIntent(intent, null);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (mPendingIntent) {
- sendIntent();
+ sendIntents();
mPendingIntent = false;
}
mWakeLock.release();
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index a838e89..feab7d2 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -209,7 +209,9 @@
private boolean mLightSensorEnabled;
private float mLightSensorValue = -1;
private float mLightSensorPendingValue = -1;
- private int mLightSensorBrightness = -1;
+ private int mLightSensorScreenBrightness = -1;
+ private int mLightSensorButtonBrightness = -1;
+ private int mLightSensorKeyboardBrightness = -1;
private boolean mDimScreen = true;
private long mNextTimeout;
private volatile int mPokey = 0;
@@ -220,6 +222,7 @@
private long mLastScreenOnTime;
private boolean mPreventScreenOn;
private int mScreenBrightnessOverride = -1;
+ private int mButtonBrightnessOverride = -1;
private boolean mUseSoftwareAutoBrightness;
private boolean mAutoBrightessEnabled;
private int[] mAutoBrightnessLevels;
@@ -919,7 +922,8 @@
pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
+ " mScreenOffDelay=" + mScreenOffDelay);
pw.println(" mPreventScreenOn=" + mPreventScreenOn
- + " mScreenBrightnessOverride=" + mScreenBrightnessOverride);
+ + " mScreenBrightnessOverride=" + mScreenBrightnessOverride
+ + " mButtonBrightnessOverride=" + mButtonBrightnessOverride);
pw.println(" mTotalDelaySetting=" + mTotalDelaySetting);
pw.println(" mLastScreenOnTime=" + mLastScreenOnTime);
pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
@@ -933,8 +937,11 @@
pw.println(" mProximityPendingValue=" + mProximityPendingValue);
pw.println(" mLastProximityEventTime=" + mLastProximityEventTime);
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
- pw.println(" mLightSensorValue=" + mLightSensorValue);
- pw.println(" mLightSensorPendingValue=" + mLightSensorPendingValue);
+ pw.println(" mLightSensorValue=" + mLightSensorValue
+ + " mLightSensorPendingValue=" + mLightSensorPendingValue);
+ pw.println(" mLightSensorScreenBrightness=" + mLightSensorScreenBrightness
+ + " mLightSensorButtonBrightness=" + mLightSensorButtonBrightness
+ + " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness);
pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled);
mScreenBrightness.dump(pw, " mScreenBrightness: ");
@@ -1302,7 +1309,18 @@
}
}
}
-
+
+ public void setButtonBrightnessOverride(int brightness) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ synchronized (mLocks) {
+ if (mButtonBrightnessOverride != brightness) {
+ mButtonBrightnessOverride = brightness;
+ updateLightsLocked(mPowerState, BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT);
+ }
+ }
+ }
+
/**
* Sanity-check that gets called 5 seconds after any call to
* preventScreenOn(true). This ensures that the original call
@@ -1451,8 +1469,7 @@
err = setScreenStateLocked(true);
long identity = Binder.clearCallingIdentity();
try {
- mBatteryStats.noteScreenBrightness(
- getPreferredBrightness());
+ mBatteryStats.noteScreenBrightness(getPreferredBrightness());
mBatteryStats.noteScreenOn();
} catch (RemoteException e) {
Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
@@ -1523,6 +1540,8 @@
private void updateLightsLocked(int newState, int forceState) {
final int oldState = mPowerState;
+ newState = applyButtonState(newState);
+ newState = applyKeyboardState(newState);
final int realDifference = (newState ^ oldState);
final int difference = realDifference | forceState;
if (difference == 0) {
@@ -1541,9 +1560,9 @@
if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
- preferredBrightness);
+ Power.BRIGHTNESS_ON);
} else {
- mKeyboardBrightness.setTargetLocked(preferredBrightness,
+ mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
Power.BRIGHTNESS_OFF);
}
@@ -1562,9 +1581,9 @@
if ((newState & BUTTON_BRIGHT_BIT) == 0) {
mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- preferredBrightness);
+ Power.BRIGHTNESS_ON);
} else {
- mButtonBrightness.setTargetLocked(preferredBrightness,
+ mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
Power.BRIGHTNESS_OFF);
}
@@ -1820,9 +1839,9 @@
try {
if (mScreenBrightnessOverride >= 0) {
return mScreenBrightnessOverride;
- } else if (mLightSensorBrightness >= 0 && mUseSoftwareAutoBrightness
+ } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
&& mAutoBrightessEnabled) {
- return mLightSensorBrightness;
+ return mLightSensorScreenBrightness;
}
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
SCREEN_BRIGHTNESS);
@@ -1833,6 +1852,40 @@
}
}
+ private int applyButtonState(int state) {
+ int brightness = -1;
+ if (mButtonBrightnessOverride >= 0) {
+ brightness = mButtonBrightnessOverride;
+ } else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) {
+ brightness = mLightSensorButtonBrightness;
+ }
+ if (brightness > 0) {
+ return state | BUTTON_BRIGHT_BIT;
+ } else if (brightness == 0) {
+ return state & ~BUTTON_BRIGHT_BIT;
+ } else {
+ return state;
+ }
+ }
+
+ private int applyKeyboardState(int state) {
+ int brightness = -1;
+ if (!mKeyboardVisible) {
+ brightness = 0;
+ } else if (mButtonBrightnessOverride >= 0) {
+ brightness = mButtonBrightnessOverride;
+ } else if (mLightSensorKeyboardBrightness >= 0 && mUseSoftwareAutoBrightness) {
+ brightness = mLightSensorKeyboardBrightness;
+ }
+ if (brightness > 0) {
+ return state | KEYBOARD_BRIGHT_BIT;
+ } else if (brightness == 0) {
+ return state & ~KEYBOARD_BRIGHT_BIT;
+ } else {
+ return state;
+ }
+ }
+
public boolean isScreenOn() {
synchronized (mLocks) {
return (mPowerState & SCREEN_ON_BIT) != 0;
@@ -2008,7 +2061,9 @@
} else {
keyboardValue = 0;
}
- mLightSensorBrightness = lcdValue;
+ mLightSensorScreenBrightness = lcdValue;
+ mLightSensorButtonBrightness = buttonValue;
+ mLightSensorKeyboardBrightness = keyboardValue;
if (mDebugLightSensor) {
Log.d(TAG, "lcdValue " + lcdValue);
@@ -2032,31 +2087,35 @@
lcdValue, brightnessMode);
}
}
- if (ANIMATE_BUTTON_LIGHTS) {
- if (mButtonBrightness.setTargetLocked(buttonValue,
- AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- (int)mButtonBrightness.curValue)) {
- startAnimation = true;
+ if (mButtonBrightnessOverride < 0) {
+ if (ANIMATE_BUTTON_LIGHTS) {
+ if (mButtonBrightness.setTargetLocked(buttonValue,
+ AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+ (int)mButtonBrightness.curValue)) {
+ startAnimation = true;
+ }
+ } else {
+ int brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
+ buttonValue, brightnessMode);
}
- } else {
- int brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
- buttonValue, brightnessMode);
}
- if (ANIMATE_KEYBOARD_LIGHTS) {
- if (mKeyboardBrightness.setTargetLocked(keyboardValue,
- AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- (int)mKeyboardBrightness.curValue)) {
- startAnimation = true;
+ if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
+ if (ANIMATE_KEYBOARD_LIGHTS) {
+ if (mKeyboardBrightness.setTargetLocked(keyboardValue,
+ AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+ (int)mKeyboardBrightness.curValue)) {
+ startAnimation = true;
+ }
+ } else {
+ int brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+ keyboardValue, brightnessMode);
}
- } else {
- int brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
- keyboardValue, brightnessMode);
}
if (startAnimation) {
if (mDebugLightSensor) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 4bac178..0481340 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -224,20 +224,22 @@
/**
* Condition waited on by {@link #reenableKeyguard} to know the call to
* the window policy has finished.
+ * This is set to true only if mKeyguardTokenWatcher.acquired() has
+ * actually disabled the keyguard.
*/
- private boolean mWaitingUntilKeyguardReenabled = false;
+ private boolean mKeyguardDisabled = false;
-
- final TokenWatcher mKeyguardDisabled = new TokenWatcher(
- new Handler(), "WindowManagerService.mKeyguardDisabled") {
+ final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher(
+ new Handler(), "WindowManagerService.mKeyguardTokenWatcher") {
public void acquired() {
mPolicy.enableKeyguard(false);
+ mKeyguardDisabled = true;
}
public void released() {
mPolicy.enableKeyguard(true);
- synchronized (mKeyguardDisabled) {
- mWaitingUntilKeyguardReenabled = false;
- mKeyguardDisabled.notifyAll();
+ synchronized (mKeyguardTokenWatcher) {
+ mKeyguardDisabled = false;
+ mKeyguardTokenWatcher.notifyAll();
}
}
};
@@ -2447,7 +2449,12 @@
boolean assignLayers = false;
if (imMayMove) {
- if (moveInputMethodWindowsIfNeededLocked(false)) {
+ if (moveInputMethodWindowsIfNeededLocked(false) || displayed) {
+ // Little hack here -- we -should- be able to rely on the
+ // function to return true if the IME has moved and needs
+ // its layer recomputed. However, if the IME was hidden
+ // and isn't actually moved in the list, its layer may be
+ // out of data so we make sure to recompute it.
assignLayers = true;
}
}
@@ -4040,8 +4047,8 @@
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardDisabled) {
- mKeyguardDisabled.acquire(token, tag);
+ synchronized (mKeyguardTokenWatcher) {
+ mKeyguardTokenWatcher.acquire(token, tag);
}
}
@@ -4050,16 +4057,20 @@
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardDisabled) {
- mKeyguardDisabled.release(token);
+ synchronized (mKeyguardTokenWatcher) {
+ mKeyguardTokenWatcher.release(token);
- if (!mKeyguardDisabled.isAcquired()) {
- // if we are the last one to reenable the keyguard wait until
- // we have actaully finished reenabling until returning
- mWaitingUntilKeyguardReenabled = true;
- while (mWaitingUntilKeyguardReenabled) {
+ if (!mKeyguardTokenWatcher.isAcquired()) {
+ // If we are the last one to reenable the keyguard wait until
+ // we have actaully finished reenabling until returning.
+ // It is possible that reenableKeyguard() can be called before
+ // the previous disableKeyguard() is handled, in which case
+ // neither mKeyguardTokenWatcher.acquired() or released() would
+ // be called. In that case mKeyguardDisabled will be false here
+ // and we have nothing to wait for.
+ while (mKeyguardDisabled) {
try {
- mKeyguardDisabled.wait();
+ mKeyguardTokenWatcher.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
@@ -9302,6 +9313,7 @@
boolean orientationChangeComplete = true;
Session holdScreen = null;
float screenBrightness = -1;
+ float buttonBrightness = -1;
boolean focusDisplayed = false;
boolean animating = false;
@@ -10061,6 +10073,10 @@
&& screenBrightness < 0) {
screenBrightness = w.mAttrs.screenBrightness;
}
+ if (!syswin && w.mAttrs.buttonBrightness >= 0
+ && buttonBrightness < 0) {
+ buttonBrightness = w.mAttrs.buttonBrightness;
+ }
if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
|| attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
@@ -10307,6 +10323,12 @@
mPowerManager.setScreenBrightnessOverride((int)
(screenBrightness * Power.BRIGHTNESS_ON));
}
+ if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+ mPowerManager.setButtonBrightnessOverride(-1);
+ } else {
+ mPowerManager.setButtonBrightnessOverride((int)
+ (buttonBrightness * Power.BRIGHTNESS_ON));
+ }
if (holdScreen != mHoldingScreenOn) {
mHoldingScreenOn = holdScreen;
Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
@@ -10854,7 +10876,7 @@
public void monitor() {
synchronized (mWindowMap) { }
- synchronized (mKeyguardDisabled) { }
+ synchronized (mKeyguardTokenWatcher) { }
synchronized (mKeyWaiter) { }
}