Merge changes I49b383d3,I70809401
* changes:
MTP: Don't dump data packets twice in debug output.
Add support for range and enum forms in MTP ObjectPropDescs
diff --git a/api/current.xml b/api/current.xml
index 99c62a8..63215a0 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -245987,7 +245987,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f55b746..f0758fd 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -59,6 +59,7 @@
static bool gPreferSoftwareCodec;
static bool gPlaybackAudio;
static bool gWriteMP4;
+static bool gDisplayHistogram;
static String8 gWriteMP4Filename;
static int64_t getNowUs() {
@@ -68,6 +69,44 @@
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
}
+static int CompareIncreasing(const int64_t *a, const int64_t *b) {
+ return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0;
+}
+
+static void displayDecodeHistogram(Vector<int64_t> *decodeTimesUs) {
+ printf("decode times:\n");
+
+ decodeTimesUs->sort(CompareIncreasing);
+
+ size_t n = decodeTimesUs->size();
+ int64_t minUs = decodeTimesUs->itemAt(0);
+ int64_t maxUs = decodeTimesUs->itemAt(n - 1);
+
+ printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6);
+ printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6);
+
+ size_t counts[100];
+ for (size_t i = 0; i < 100; ++i) {
+ counts[i] = 0;
+ }
+
+ for (size_t i = 0; i < n; ++i) {
+ int64_t x = decodeTimesUs->itemAt(i);
+
+ size_t slot = ((x - minUs) * 100) / (maxUs - minUs);
+ if (slot == 100) { slot = 99; }
+
+ ++counts[slot];
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ int64_t slotUs = minUs + (i * (maxUs - minUs) / 100);
+
+ double fps = 1E6 / slotUs;
+ printf("[%.2f fps]: %d\n", fps, counts[i]);
+ }
+}
+
static void playSource(OMXClient *client, sp<MediaSource> &source) {
sp<MetaData> meta = source->getFormat();
@@ -201,6 +240,8 @@
int64_t sumDecodeUs = 0;
int64_t totalBytes = 0;
+ Vector<int64_t> decodeTimesUs;
+
while (numIterationsLeft-- > 0) {
long numFrames = 0;
@@ -224,9 +265,17 @@
break;
}
- if (buffer->range_length() > 0 && (n++ % 16) == 0) {
- printf(".");
- fflush(stdout);
+ if (buffer->range_length() > 0) {
+ if (gDisplayHistogram && n > 0) {
+ // Ignore the first time since it includes some setup
+ // cost.
+ decodeTimesUs.push(delayDecodeUs);
+ }
+
+ if ((n++ % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
}
sumDecodeUs += delayDecodeUs;
@@ -266,6 +315,10 @@
(double)sumDecodeUs / n);
printf("decoded a total of %d frame(s).\n", n);
+
+ if (gDisplayHistogram) {
+ displayDecodeHistogram(&decodeTimesUs);
+ }
} else if (!strncasecmp("audio/", mime, 6)) {
// Frame count makes less sense for audio, as the output buffer
// sizes may be different across decoders.
@@ -466,6 +519,8 @@
fprintf(stderr, " -o playback audio\n");
fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n");
fprintf(stderr, " -k seek test\n");
+ fprintf(stderr, " -x display a histogram of decoding times/fps "
+ "(video only)\n");
}
int main(int argc, char **argv) {
@@ -482,12 +537,13 @@
gPreferSoftwareCodec = false;
gPlaybackAudio = false;
gWriteMP4 = false;
+ gDisplayHistogram = false;
sp<ALooper> looper;
sp<ARTSPController> rtspController;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) {
+ while ((res = getopt(argc, argv, "han:lm:b:ptsow:kx")) >= 0) {
switch (res) {
case 'a':
{
@@ -560,6 +616,12 @@
break;
}
+ case 'x':
+ {
+ gDisplayHistogram = true;
+ break;
+ }
+
case '?':
case 'h':
default:
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 7f24d27..03a98d1 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -35,6 +35,7 @@
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.util.AndroidRuntimeException;
import android.util.Slog;
@@ -285,10 +286,16 @@
if (ActivityThread.localLOGV)
Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir);
+ // Temporarily disable logging of disk reads on the Looper thread
+ // as this is early and necessary.
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+
mClassLoader =
ApplicationLoaders.getDefault().getClassLoader(
zip, mLibDir, mBaseClassLoader);
initializeJavaContextClassLoader();
+
+ StrictMode.setThreadPolicy(oldPolicy);
} else {
if (mBaseClassLoader == null) {
mClassLoader = ClassLoader.getSystemClassLoader();
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 79425d6..41bb364 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1023,12 +1023,14 @@
private void setJournalMode(final String dbPath, final String mode) {
// journal mode can be set only for non-memory databases
- if (!dbPath.equalsIgnoreCase(MEMORY_DB_PATH)) {
- String s = DatabaseUtils.stringForQuery(this, "PRAGMA journal_mode=" + mode, null);
- if (!s.equalsIgnoreCase(mode)) {
- Log.e(TAG, "setting journal_mode to " + mode + " failed for db: " + dbPath +
- " (on pragma set journal_mode, sqlite returned:" + s);
- }
+ // AND can't be set for readonly databases
+ if (dbPath.equalsIgnoreCase(MEMORY_DB_PATH) || isReadOnly()) {
+ return;
+ }
+ String s = DatabaseUtils.stringForQuery(this, "PRAGMA journal_mode=" + mode, null);
+ if (!s.equalsIgnoreCase(mode)) {
+ Log.e(TAG, "setting journal_mode to " + mode + " failed for db: " + dbPath +
+ " (on pragma set journal_mode, sqlite returned:" + s);
}
}
@@ -2317,6 +2319,10 @@
* @return true if write-ahead-logging is set. false otherwise
*/
public boolean enableWriteAheadLogging() {
+ // make sure the database is not READONLY. WAL doesn't make sense for readonly-databases.
+ if (isReadOnly()) {
+ return false;
+ }
// acquire lock - no that no other thread is enabling WAL at the same time
lock();
try {
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 98bf632..32ff3b3 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -111,6 +111,27 @@
* This can be achieved by applying a <i>high-pass</i> filter. Conversely, a
* <i>low-pass</i> filter can be used to isolate the force of gravity.
* </p>
+ *
+ * <pre class="prettyprint">
+ *
+ * public void onSensorChanged(SensorEvent event)
+ * {
+ * // alpha is calculated as t / (t + dT)
+ * // with t, the low-pass filter's time-constant
+ * // and dT, the event delivery rate
+ *
+ * final float alpha = 0.8;
+ *
+ * gravity[0] = alpha * gravity[0] + (1 - alpha) * event.data[0];
+ * gravity[1] = alpha * gravity[1] + (1 - alpha) * event.data[1];
+ * gravity[2] = alpha * gravity[2] + (1 - alpha) * event.data[2];
+ *
+ * linear_acceleration[0] = event.data[0] - gravity[0];
+ * linear_acceleration[1] = event.data[1] - gravity[1];
+ * linear_acceleration[2] = event.data[2] - gravity[2];
+ * }
+ * </pre>
+ *
* <p>
* <u>Examples</u>:
* <ul>
@@ -143,8 +164,41 @@
* standard mathematical definition of positive rotation and does not agree with the
* definition of roll given earlier.
*
+ * <ul>
+ * <p>
+ * values[0]: Angular speed around the x-axis
+ * </p>
+ * <p>
+ * values[1]: Angular speed around the y-axis
+ * </p>
+ * <p>
+ * values[2]: Angular speed around the z-axis
+ * </p>
+ * </ul>
+ * <p>
+ * Typically the output of the gyroscope is integrated over time to calculate
+ * an angle, for example:
+ * </p>
+ * <pre class="prettyprint">
+ * private static final float NS2S = 1.0f / 1000000000.0f;
+ * private float timestamp;
+ * public void onSensorChanged(SensorEvent event)
+ * {
+ * if (timestamp != 0) {
+ * final float dT = (event.timestamp - timestamp) * NS2S;
+ * angle[0] += event.data[0] * dT;
+ * angle[1] += event.data[1] * dT;
+ * angle[2] += event.data[2] * dT;
+ * }
+ * timestamp = event.timestamp;
+ * }
+ * </pre>
+ *
+ * <p>In practice, the gyroscope noise and offset will introduce some errors which need
+ * to be compensated for. This is usually done using the information from other
+ * sensors, but is beyond the scope of this document.</p>
+ *
* <h4>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h4>
- *
* <ul>
* <p>
* values[0]: Ambient light level in SI lux units
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index b8a1113..f8f8a29 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -99,6 +99,7 @@
private final boolean mSecure;
/** @deprecated Use {@link #getDefault(int)} instead. */
+ @Deprecated
public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
this(handshakeTimeoutMillis, null, true);
}
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 363a311..92be373 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -102,14 +102,15 @@
}
}
- return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain);
+ return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
}
/**
* Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use
* by Chromium HTTPS stack to validate the cert chain.
- * @param certChain The bytes for certificates in ASN.1 DER encoded certficates format.
+ * @param certChain The bytes for certificates in ASN.1 DER encoded certificates format.
* @param domain The full website hostname and domain
+ * @param authType The authentication type for the cert chain
* @return An SSL error object if there is an error and null otherwise
*/
public static SslError verifyServerCertificates(
@@ -126,18 +127,19 @@
serverCertificates[i] = new X509CertImpl(certChain[i]);
}
- return verifyServerDomainAndCertificates(serverCertificates, domain);
+ return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
}
/**
* Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
- * Calls DomainNamevalidator to valide the domain, and TrustManager to valide the certs.
+ * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
* @param chain the cert chain in X509 cert format.
* @param domain The full website hostname and domain
+ * @param authType The authentication type for the cert chain
* @return An SSL error object if there is an error and null otherwise
*/
private static SslError verifyServerDomainAndCertificates(
- X509Certificate[] chain, String domain)
+ X509Certificate[] chain, String domain, String authType)
throws IOException {
// check if the first certificate in the chain is for this site
X509Certificate currCertificate = chain[0];
@@ -153,7 +155,7 @@
}
try {
- SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(chain, "RSA");
+ SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(chain, authType);
return null; // No errors.
} catch (CertificateException e) {
if (HttpLog.LOGV) {
diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java
index c29926c..30f25a2 100644
--- a/core/java/android/net/http/SslCertificate.java
+++ b/core/java/android/net/http/SslCertificate.java
@@ -112,6 +112,7 @@
* @param validNotAfter The not-after date from the certificate validity period in ISO 8601 format
* @deprecated Use {@link #SslCertificate(String, String, Date, Date)}
*/
+ @Deprecated
public SslCertificate(
String issuedTo, String issuedBy, String validNotBefore, String validNotAfter) {
this(issuedTo, issuedBy, parseDate(validNotBefore), parseDate(validNotAfter));
@@ -157,6 +158,7 @@
*
* @deprecated Use {@link #getValidNotBeforeDate()}
*/
+ @Deprecated
public String getValidNotBefore() {
return formatDate(mValidNotBefore);
}
@@ -175,6 +177,7 @@
*
* @deprecated Use {@link #getValidNotAfterDate()}
*/
+ @Deprecated
public String getValidNotAfter() {
return formatDate(mValidNotAfter);
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 88ce0f0..c007605 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -861,6 +861,8 @@
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, EventsColumns.DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC1);
+ DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
+ Events.SYNC_ADAPTER_DATA);
Entity entity = new Entity(cv);
Cursor subCursor;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1fe2c5a..ddfcb06 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2396,14 +2396,6 @@
"selected_input_method_subtype";
/**
- * Setting to record the history of input method subtype, holding the pair of ID of IME
- * and its last used subtype.
- * @hide
- */
- public static final String INPUT_METHODS_SUBTYPE_HISTORY =
- "input_methods_subtype_history";
-
- /**
* Whether the device has been provisioned (0 = false, 1 = true)
*/
public static final String DEVICE_PROVISIONED = "device_provisioned";
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index 5cf5332..8c18417 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -29,6 +29,7 @@
* @deprecated This class is no longer functional.
* Use {@link android.util.EventLog} instead.
*/
+@Deprecated
public class EventLogTags {
public static class Description {
public final int mTag;
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 8691714..0e9d9b7 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -951,8 +951,12 @@
}
equalIndex = cookieString.indexOf(EQUAL, index);
if (equalIndex > 0) {
- String name = cookieString.substring(index, equalIndex)
- .toLowerCase();
+ String name = cookieString.substring(index, equalIndex).toLowerCase();
+ int valueIndex = equalIndex + 1;
+ while (valueIndex < length && cookieString.charAt(valueIndex) == WHITE_SPACE) {
+ valueIndex++;
+ }
+
if (name.equals(EXPIRES)) {
int comaIndex = cookieString.indexOf(COMMA, equalIndex);
@@ -960,7 +964,7 @@
// (Weekday, DD-Mon-YY HH:MM:SS GMT) if it applies.
// "Wednesday" is the longest Weekday which has length 9
if ((comaIndex != -1) &&
- (comaIndex - equalIndex <= 10)) {
+ (comaIndex - valueIndex <= 10)) {
index = comaIndex + 1;
}
}
@@ -975,8 +979,7 @@
} else {
index = Math.min(semicolonIndex, commaIndex);
}
- String value =
- cookieString.substring(equalIndex + 1, index);
+ String value = cookieString.substring(valueIndex, index);
// Strip quotes if they exist
if (value.length() > 2 && value.charAt(0) == QUOTATION) {
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 3f6b10a..c788a53 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -564,7 +564,7 @@
&& exceedsMinScaleIncrement(mTextWrapScale, newTextWrapScale)) {
mTextWrapScale = newTextWrapScale;
refreshZoomScale(true);
- } else if (!mInZoomOverview) {
+ } else if (!mInZoomOverview && willScaleTriggerZoom(getZoomOverviewScale())) {
zoomToOverview();
} else {
zoomToReadingLevel();
@@ -589,8 +589,6 @@
}
private void zoomToOverview() {
- if (!willScaleTriggerZoom(getZoomOverviewScale())) return;
-
// Force the titlebar fully reveal in overview mode
int scrollY = mWebView.getScrollY();
if (scrollY < mWebView.getTitleHeight()) {
@@ -800,9 +798,9 @@
*/
public void onNewPicture(WebViewCore.DrawData drawData) {
final int viewWidth = mWebView.getViewWidth();
-
- if (mWebView.getSettings().getUseWideViewPort()) {
- if (!mWebView.getSettings().getUseFixedViewport()) {
+ WebSettings settings = mWebView.getSettings();
+ if (settings.getUseWideViewPort()) {
+ if (!settings.getUseFixedViewport()) {
// limit mZoomOverviewWidth upper bound to
// sMaxViewportWidth so that if the page doesn't behave
// well, the WebView won't go insane. limit the lower
@@ -812,7 +810,13 @@
Math.max(drawData.mMinPrefWidth, drawData.mViewSize.x))));
} else {
final int contentWidth = Math.max(drawData.mContentSize.x, drawData.mMinPrefWidth);
- setZoomOverviewWidth(Math.min(WebView.sMaxViewportWidth, contentWidth));
+ final int newZoomOverviewWidth = Math.min(WebView.sMaxViewportWidth, contentWidth);
+ if (newZoomOverviewWidth != mZoomOverviewWidth) {
+ setZoomOverviewWidth(newZoomOverviewWidth);
+ if (settings.isNarrowColumnLayout() && (mInitialZoomOverview || mInZoomOverview)) {
+ mTextWrapScale = getReadingLevelScale();
+ }
+ }
}
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index ec31dd4..50c88db 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -27,7 +27,6 @@
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
-import android.os.PowerManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -35,7 +34,7 @@
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.widget.MediaController.*;
+import android.widget.MediaController.MediaPlayerControl;
import java.io.IOException;
import java.util.Map;
@@ -458,6 +457,10 @@
}
start();
if (mMediaController != null) {
+ if (mMediaController.isShowing()) {
+ // ensure the controller will get repositioned later
+ mMediaController.hide();
+ }
mMediaController.show();
}
}
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index e961116..d2e53b3 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -16,6 +16,8 @@
package com.android.internal.service.wallpaper;
+import java.io.IOException;
+
import com.android.internal.view.WindowManagerPolicyThread;
import android.app.WallpaperManager;
@@ -169,10 +171,26 @@
void updateWallpaper() {
synchronized (mLock) {
+ Throwable exception = null;
try {
mBackground = mWallpaperManager.getFastDrawable();
} catch (RuntimeException e) {
- Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
+ exception = e;
+ } catch (OutOfMemoryError e) {
+ exception = e;
+ }
+ if (exception != null) {
+ mBackground = null;
+ // Note that if we do fail at this, and the default wallpaper can't
+ // be loaded, we will go into a cycle. Don't do a build where the
+ // default wallpaper can't be loaded.
+ Log.w("ImageWallpaper", "Unable to load wallpaper!", exception);
+ try {
+ mWallpaperManager.clear();
+ } catch (IOException ex) {
+ // now we're really screwed.
+ Log.w("ImageWallpaper", "Unable reset to default wallpaper!", ex);
+ }
}
}
}
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 3c971da..9bec8a3 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,8 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Do nothing. -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:detachWallpaper="true" android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="1.0"
+ android:fromYScale="0.9" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:fillEnabled="true" android:fillBefore="true"
+ android:interpolator="@anim/decelerate_quint_interpolator"
+ android:startOffset="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="0" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true"
+ android:interpolator="@anim/decelerate_cubic_interpolator"
+ android:startOffset="@android:integer/config_mediumAnimTime"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 2001e20..ca60214 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -22,9 +22,15 @@
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.9"
android:pivotX="50%p" android:pivotY="50%p"
+ android:fillEnabled="true" android:fillAfter="true"
android:interpolator="@anim/decelerate_quint_interpolator"
android:duration="@android:integer/config_mediumAnimTime" />
<alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:interpolator="@anim/decelerate_cubic_interpolator"
+ android:fillEnabled="true" android:fillAfter="true"
+ android:interpolator="@anim/decelerate_quint_interpolator"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <!-- This is just to keep the animation running for the entire duration. -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:startOffset="@android:integer/config_mediumAnimTime"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 6c62e61..4f72ba2 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -22,9 +22,13 @@
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="0.9" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
+ android:fillEnabled="true" android:fillBefore="true"
android:interpolator="@anim/decelerate_quint_interpolator"
+ android:startOffset="@android:integer/config_mediumAnimTime"
android:duration="@android:integer/config_mediumAnimTime" />
<alpha android:fromAlpha="0" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true"
android:interpolator="@anim/decelerate_cubic_interpolator"
+ android:startOffset="@android:integer/config_mediumAnimTime"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 3c971da..6174151 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,8 +18,19 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Do nothing. -->
+ android:detachWallpaper="true" android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="1.0"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:fillEnabled="true" android:fillAfter="true"
+ android:interpolator="@anim/decelerate_quint_interpolator"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:fillEnabled="true" android:fillAfter="true"
+ android:interpolator="@anim/decelerate_quint_interpolator"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <!-- This is just to keep the animation running for the entire duration. -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:startOffset="@android:integer/config_mediumAnimTime"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/layout/preference.xml b/core/res/res/layout/preference.xml
index ba0e225..46c3e9c 100644
--- a/core/res/res/layout/preference.xml
+++ b/core/res/res/layout/preference.xml
@@ -24,9 +24,13 @@
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
- <View
- android:layout_width="@dimen/preference_widget_width"
- android:layout_height="match_parent" />
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/preference_widget_width"
+ android:gravity="center"
+ android:orientation="vertical" />
<RelativeLayout
android:layout_width="wrap_content"
@@ -54,12 +58,5 @@
android:maxLines="4" />
</RelativeLayout>
-
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@+android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical" />
</LinearLayout>
diff --git a/core/res/res/layout/preference_child.xml b/core/res/res/layout/preference_child.xml
index d6f1182..713aa17 100644
--- a/core/res/res/layout/preference_child.xml
+++ b/core/res/res/layout/preference_child.xml
@@ -22,9 +22,13 @@
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
- <View
- android:layout_width="@dimen/preference_widget_width"
- android:layout_height="match_parent" />
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/preference_widget_width"
+ android:gravity="center"
+ android:orientation="vertical" />
<RelativeLayout
android:layout_width="wrap_content"
@@ -54,11 +58,4 @@
</RelativeLayout>
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@+android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical" />
-
</LinearLayout>
diff --git a/core/res/res/layout/preference_dialog.xml b/core/res/res/layout/preference_dialog.xml
index 035b411..9e988ad 100644
--- a/core/res/res/layout/preference_dialog.xml
+++ b/core/res/res/layout/preference_dialog.xml
@@ -15,52 +15,9 @@
-->
<!-- Layout used by DialogPreference in a PreferenceActivity. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingRight="?android:attr/scrollbarSize">
-
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@+android:id/widget_frame"
- android:layout_width="@dimen/preference_widget_width"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" >
- <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@drawable/btn_circle"
- android:src="@drawable/ic_btn_round_more" />
- </LinearLayout>
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
-
- <TextView android:id="@+android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <TextView android:id="@+android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignLeft="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="4" />
-
- </RelativeLayout>
-</LinearLayout>
-
+ android:layout_gravity="center"
+ android:background="@drawable/btn_circle"
+ android:src="@drawable/ic_btn_round_more" />
diff --git a/core/res/res/layout/preference_widget_checkbox.xml b/core/res/res/layout/preference_widget_checkbox.xml
index 1ca4393..33a43f4 100644
--- a/core/res/res/layout/preference_widget_checkbox.xml
+++ b/core/res/res/layout/preference_widget_checkbox.xml
@@ -16,54 +16,10 @@
<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
inside android.R.layout.preference. -->
-<!-- Layout used by DialogPreference in a PreferenceActivity. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/checkbox"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingRight="?android:attr/scrollbarSize">
-
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@+android:id/widget_frame"
- android:layout_width="@dimen/preference_widget_width"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" >
- <CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+android:id/checkbox"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:focusable="false"
- android:clickable="false" />
- </LinearLayout>
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
-
- <TextView android:id="@+android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <TextView android:id="@+android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignLeft="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="4" />
-
- </RelativeLayout>
-</LinearLayout>
-
+ android:layout_gravity="center"
+ android:focusable="false"
+ android:clickable="false" />
diff --git a/core/res/res/values-xlarge/dimens.xml b/core/res/res/values-xlarge/dimens.xml
index 115cb30..f52c627 100644
--- a/core/res/res/values-xlarge/dimens.xml
+++ b/core/res/res/values-xlarge/dimens.xml
@@ -31,7 +31,7 @@
<dimen name="password_keyboard_key_height_numeric">0.47in</dimen>
<!-- The width that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_width">256dp</dimen>
+ <dimen name="thumbnail_width">160dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_height">255dp</dimen>
+ <dimen name="thumbnail_height">100dp</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1fd5146..3050345 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2305,11 +2305,9 @@
<!-- See USB_STORAGE. USB_STORAGE_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to mount. This is the title. -->
<string name="usb_storage_title">USB connected</string>
<!-- See USB_STORAGE. This is the message. [CHAR LIMIT=NONE] -->
- <string name="usb_storage_message" product="tablet">You have connected your tablet to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s USB storage.</string>
+ <string name="usb_storage_message" product="nosdcard">You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s USB storage.</string>
<!-- See USB_STORAGE. This is the message. [CHAR LIMIT=NONE] -->
- <string name="usb_storage_message" product="nosdcard">You have connected your phone to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s USB storage.</string>
- <!-- See USB_STORAGE. This is the message. -->
- <string name="usb_storage_message" product="default">You have connected your phone to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
+ <string name="usb_storage_message" product="default">You have connected to your computer via USB. Touch the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
<!-- See USB_STORAGE. This is the button text to mount the phone on the computer. -->
<string name="usb_storage_button_mount">Turn on USB storage</string>
<!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1fd2565..f63805b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -818,18 +818,18 @@
<item name="android:shouldDisableView">false</item>
<item name="android:selectable">false</item>
</style>
-
+
<style name="Preference.CheckBoxPreference">
- <item name="android:layout">@android:layout/preference_widget_checkbox</item>
+ <item name="android:widgetLayout">@android:layout/preference_widget_checkbox</item>
</style>
-
+
<style name="Preference.PreferenceScreen">
</style>
<style name="Preference.DialogPreference">
<item name="android:positiveButtonText">@android:string/ok</item>
<item name="android:negativeButtonText">@android:string/cancel</item>
- <item name="android:layout">@android:layout/preference_dialog</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<style name="Preference.DialogPreference.YesNoPreference">
@@ -845,7 +845,7 @@
<item name="android:ringtoneType">ringtone</item>
<item name="android:showSilent">true</item>
<item name="android:showDefault">true</item>
- <item name="android:layout">@android:layout/preference_dialog</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<!-- Other Misc Styles -->
diff --git a/core/tests/coretests/src/android/net/http/CookiesTest.java b/core/tests/coretests/src/android/net/http/CookiesTest.java
index c9eca03..e736bc9 100644
--- a/core/tests/coretests/src/android/net/http/CookiesTest.java
+++ b/core/tests/coretests/src/android/net/http/CookiesTest.java
@@ -19,15 +19,20 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.List;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import junit.framework.TestCase;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import tests.http.MockResponse;
import tests.http.MockWebServer;
+import tests.http.RecordedRequest;
public final class CookiesTest extends TestCase {
@@ -66,4 +71,38 @@
logger.removeHandler(handler);
}
}
+
+ /**
+ * Test that cookies aren't case-sensitive with respect to hostname.
+ * http://b/3167208
+ */
+ public void testCookiesWithNonMatchingCase() throws Exception {
+ // use a proxy so we can manipulate the origin server's host name
+ server = new MockWebServer();
+ server.enqueue(new MockResponse()
+ .addHeader("Set-Cookie: a=first; Domain=my.t-mobile.com")
+ .addHeader("Set-Cookie: b=second; Domain=.T-mobile.com")
+ .addHeader("Set-Cookie: c=third; Domain=.t-mobile.com")
+ .setBody("This response sets some cookies."));
+ server.enqueue(new MockResponse()
+ .setBody("This response gets those cookies back."));
+ server.play();
+
+ HttpClient client = new DefaultHttpClient();
+ client.getParams().setParameter(
+ ConnRoutePNames.DEFAULT_PROXY, new HttpHost("localhost", server.getPort()));
+
+ HttpResponse getCookies = client.execute(new HttpGet("http://my.t-mobile.com/"));
+ getCookies.getEntity().consumeContent();
+ server.takeRequest();
+
+ HttpResponse sendCookies = client.execute(new HttpGet("http://my.t-mobile.com/"));
+ sendCookies.getEntity().consumeContent();
+ RecordedRequest sendCookiesRequest = server.takeRequest();
+ assertContains(sendCookiesRequest.getHeaders(), "Cookie: a=first; b=second; c=third");
+ }
+
+ private void assertContains(List<String> headers, String header) {
+ assertTrue(headers.toString(), headers.contains(header));
+ }
}
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index e46dbb4..acb6f9f 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -257,9 +257,9 @@
<p>
The border is used to define the stretchable and static areas of
the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide
- black line(s) in the left and top part of the border. (You can have as
- many stretchable sections as you want.) The relative size of the stretchable
- sections stays the same, so the largest sections always remain the largest.
+ black line(s) in the left and top part of the border (the other border pixels should
+ be fully transparent or white). You can have as many stretchable sections as you want:
+ their relative size stays the same, so the largest sections always remain the largest.
</p>
<p>
You can also define an optional drawable section of the image (effectively,
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 632fa4b..350f2b0 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -103,12 +103,54 @@
<div class="toggleable opened">
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
-ADT 0.9.9</a> <em>(September 2010)</em>
+ADT 8.0</a> <em>(November 2010)</em>
<div class="toggleme">
+<dl>
+<dt>Dependencies:</dt>
+
+<p><p>ADT 8.0 is designed for use with SDK Tools r8. If you haven't
+already installed SDK Tools r8 into your SDK, use the Android SDK and AVD Manager to do
+so.</p></dd>
+
+<dt>General notes:</dt>
+<dd>
+<ul>
+ <li>New version number scheme that follows the SDK Tools revision number. The major version
+number for your ADT plugin should now always match the revision number of your SDK Tools. For
+example, ADT 8.x is for SDK Tools r8.</li>
+ <li>Support for true debug build. You no longer need to change the value of the
+ <code>debuggable</code> attribute in the Android Manifest.
+ <p>Incremental builds automatically insert <code>debuggable="true"</code>, but if you perform
+ "export signed/unsigned application package", ADT does <em>not</em> insert it.
+ If you manually set <code>debuggable="true"</code> in the manifest file, then release builds will
+ actually create a debug build (it does not remove it if you placed it there).</p></li>
+ <li>Automatic <a href="{@docRoot}guide/developing/tools/proguard.html">Proguard</a> support in
+release builds. For it to work, you need to have a <code>proguard.config</code>
+ property in the <code>default.properties</code> file that points to a proguard config file.</li>
+ <li>Completely rewritten Visual Layout Editor. (This is still a work in progress.) Now includes:
+ <ul>
+ <li>Full drag and drop from palette to layout for all Layout classes.</li>
+ <li>Move widgets inside a Layout view, from one Layout view to another and from one layout file to another.</li>
+ <li>Contextual menu with enum/flag type properties.</li>
+ <li>New zoom controls.</li>
+ </ul></li>
+ <li>New HierarchyViewer plug-in integrated in Eclipse.</li>
+ <li>Android launch configurations don't recompile the whole workspace on launch anymore.</li>
+ <li><code>android.jar</code> source and javadoc location can now be configured.</li>
</ul>
</dd>
+</dl>
+ </div>
+</div>
+
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
+ADT 0.9.9</a> <em>(September 2010)</em>
+ <div class="toggleme">
<dl>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 11e6642..0f36345 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -84,34 +84,56 @@
<dd>
<ul>
+
+ <li>A new toolchain (based on GCC 4.4.3), which generates better code, and can also now
+be used as a standalone cross-compiler, for people who want to build their stuff with
+<code>./configure && make</code>. See
+docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
+but the 4.2.1 binaries were removed.</li>
+
+ <li>Support for prebuilt static and shared libraries (docs/PREBUILTS.html), module
+exports and imports to make sharing and reuse of third-party modules much easier
+(docs/IMPORT-MODULE.html explains why).</li>
+
+ <li>A C++ STL implementation (based on STLport) is now provided as a helper module. It
+can be used either as a static or shared library (details and usage exemple under
+sources/android/stlport/README). <strong>Note:</strong> For now, C++ Exceptions and RTTI are still
+not supported.</li>
+
+ <li>Improvements to the <code>cpufeatures</code> helper library to deal with buggy
+kernel that incorrectly report they run on an ARMv7 CPU (while the device really is an ARMv6). We
+recommend developers that use it to simply rebuild their applications to benefit from it, then
+upload to Market.</li>
+
<li>Adds support for native activities, which allows you to write completely native
applications.</li>
<li>Adds an EGL library that lets you create and manage OpenGL ES textures and
services.</li>
- <li>Provides an interface that lets you write a native text-to-speech engine.</li>
-
<li>Adds native support for the following:
<ul>
- <li>the input subsystem (such as the keyboard and touch screen)</li>
+ <li>Input subsystem (such as the keyboard and touch screen)</li>
- <li>the window and surface subsystem.</li>
+ <li>Window and surface subsystem</li>
- <li>audio APIs based on the OpenSL ES standard that support playback and recording
- as well as control over platform audio effects.</li>
+ <li>Audio APIs based on the OpenSL ES standard that support playback and recording
+ as well as control over platform audio effects</li>
- <li>event loop APIs to wait for things such as input and sensor events.</li>
+ <li>Event loop APIs to wait for things such as input and sensor events</li>
- <li>accessing assets packaged in an <code>.apk</code> file.</li>
+ <li>Access to assets packaged in the <code>.apk</code></li>
- <li>accessing sensor data (accelerometer, compass, gyroscope, etc).</li>
-
- <li>provides sample applications, <code>native-plasma</code> and
- <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+ <li>Access to sensor data (accelerometer, compass, gyroscope, etc.)</li>
</ul>
</li>
+
+ <li>New sample applications, <code>native-plasma</code> and
+ <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+
+ <li>Plus many bugfixes and other small improvements; see docs/CHANGES.html for a more
+detailed list of changes.</li>
</ul>
</dd>
</dl>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index ecc69c2..7ccb7a0 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -93,7 +93,7 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 0.9.9
+ <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 8.0
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
<span style="display:none" class="fr"></span>
@@ -115,7 +115,8 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Download the Android NDK, r5</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Download the Android NDK, r5</a>
+ <span class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
</ul>
</li>
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index dfd6ac8..9dc291b 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -45,9 +45,8 @@
@Override
void updateFromNative() {
- mRS.validate();
- mName = mRS.nGetName(mID);
- int typeID = mRS.nAllocationGetType(mID);
+ super.updateFromNative();
+ int typeID = mRS.nAllocationGetType(getID());
if(typeID != 0) {
mType = new Type(typeID, mRS);
mType.updateFromNative();
@@ -60,17 +59,17 @@
public void uploadToTexture(int baseMipLevel) {
mRS.validate();
- mRS.nAllocationUploadToTexture(mID, false, baseMipLevel);
+ mRS.nAllocationUploadToTexture(getID(), false, baseMipLevel);
}
public void uploadToTexture(boolean genMips, int baseMipLevel) {
mRS.validate();
- mRS.nAllocationUploadToTexture(mID, genMips, baseMipLevel);
+ mRS.nAllocationUploadToTexture(getID(), genMips, baseMipLevel);
}
public void uploadToBufferObject() {
mRS.validate();
- mRS.nAllocationUploadToBufferObject(mID);
+ mRS.nAllocationUploadToBufferObject(getID());
}
public void data(int[] d) {
@@ -90,16 +89,15 @@
subData1D(0, mType.getElementCount(), d);
}
- public void updateFromBitmap(Bitmap b)
- throws IllegalArgumentException {
+ public void updateFromBitmap(Bitmap b) {
mRS.validate();
if(mType.getX() != b.getWidth() ||
mType.getY() != b.getHeight()) {
- throw new IllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
+ throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
}
- mRS.nAllocationUpdateFromBitmap(mID, b);
+ mRS.nAllocationUpdateFromBitmap(getID(), b);
}
public void subData(int xoff, FieldPacker fp) {
@@ -108,100 +106,100 @@
int count = data.length / eSize;
if ((eSize * count) != data.length) {
- throw new IllegalArgumentException("Field packer length " + data.length +
+ throw new RSIllegalArgumentException("Field packer length " + data.length +
" not divisible by element size " + eSize + ".");
}
data1DChecks(xoff, count, data.length, data.length);
- mRS.nAllocationSubData1D(mID, xoff, count, data, data.length);
+ mRS.nAllocationSubData1D(getID(), xoff, count, data, data.length);
}
public void subElementData(int xoff, int component_number, FieldPacker fp) {
if (component_number >= mType.mElement.mElements.length) {
- throw new IllegalArgumentException("Component_number " + component_number + " out of range.");
+ throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
}
if(xoff < 0) {
- throw new IllegalArgumentException("Offset must be >= 0.");
+ throw new RSIllegalArgumentException("Offset must be >= 0.");
}
final byte[] data = fp.getData();
int eSize = mType.mElement.mElements[component_number].getSizeBytes();
if (data.length != eSize) {
- throw new IllegalArgumentException("Field packer sizelength " + data.length +
+ throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
" does not match component size " + eSize + ".");
}
- mRS.nAllocationSubElementData1D(mID, xoff, component_number, data, data.length);
+ mRS.nAllocationSubElementData1D(getID(), xoff, component_number, data, data.length);
}
private void data1DChecks(int off, int count, int len, int dataSize) {
mRS.validate();
if(off < 0) {
- throw new IllegalArgumentException("Offset must be >= 0.");
+ throw new RSIllegalArgumentException("Offset must be >= 0.");
}
if(count < 1) {
- throw new IllegalArgumentException("Count must be >= 1.");
+ throw new RSIllegalArgumentException("Count must be >= 1.");
}
if((off + count) > mType.getElementCount()) {
- throw new IllegalArgumentException("Overflow, Available count " + mType.getElementCount() +
+ throw new RSIllegalArgumentException("Overflow, Available count " + mType.getElementCount() +
", got " + count + " at offset " + off + ".");
}
if((len) < dataSize) {
- throw new IllegalArgumentException("Array too small for allocation type.");
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
}
}
public void subData1D(int off, int count, int[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+ mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
}
public void subData1D(int off, int count, short[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 2, dataSize);
- mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+ mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
}
public void subData1D(int off, int count, byte[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length, dataSize);
- mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+ mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
}
public void subData1D(int off, int count, float[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+ mRS.nAllocationSubData1D(getID(), off, count, d, dataSize);
}
public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
mRS.validate();
- mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
+ mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4);
}
public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
mRS.validate();
- mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
+ mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4);
}
public void readData(int[] d) {
mRS.validate();
- mRS.nAllocationRead(mID, d);
+ mRS.nAllocationRead(getID(), d);
}
public void readData(float[] d) {
mRS.validate();
- mRS.nAllocationRead(mID, d);
+ mRS.nAllocationRead(getID(), d);
}
public synchronized void resize(int dimX) {
if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
- throw new IllegalStateException("Resize only support for 1D allocations at this time.");
+ throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
}
- mRS.nAllocationResize1D(mID, dimX);
+ mRS.nAllocationResize1D(getID(), dimX);
mRS.finish(); // Necessary because resize is fifoed and update is async.
- int typeID = mRS.nAllocationGetType(mID);
+ int typeID = mRS.nAllocationGetType(getID());
mType = new Type(typeID, mRS);
mType.updateFromNative();
}
@@ -209,12 +207,12 @@
/*
public void resize(int dimX, int dimY) {
if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) {
- throw new IllegalStateException("Resize only support for 2D allocations at this time.");
+ throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
}
if (mType.getY() == 0) {
- throw new IllegalStateException("Resize only support for 2D allocations at this time.");
+ throw new RSIllegalStateException("Resize only support for 2D allocations at this time.");
}
- mRS.nAllocationResize2D(mID, dimX, dimY);
+ mRS.nAllocationResize2D(getID(), dimX, dimY);
}
*/
@@ -225,27 +223,27 @@
public void setConstraint(Dimension dim, int value) {
mRS.validate();
- mRS.nAdapter1DSetConstraint(mID, dim.mID, value);
+ mRS.nAdapter1DSetConstraint(getID(), dim.mID, value);
}
public void data(int[] d) {
mRS.validate();
- mRS.nAdapter1DData(mID, d);
+ mRS.nAdapter1DData(getID(), d);
}
public void data(float[] d) {
mRS.validate();
- mRS.nAdapter1DData(mID, d);
+ mRS.nAdapter1DData(getID(), d);
}
public void subData(int off, int count, int[] d) {
mRS.validate();
- mRS.nAdapter1DSubData(mID, off, count, d);
+ mRS.nAdapter1DSubData(getID(), off, count, d);
}
public void subData(int off, int count, float[] d) {
mRS.validate();
- mRS.nAdapter1DSubData(mID, off, count, d);
+ mRS.nAdapter1DSubData(getID(), off, count, d);
}
}
@@ -253,9 +251,9 @@
mRS.validate();
int id = mRS.nAdapter1DCreate();
if(id == 0) {
- throw new IllegalStateException("allocation failed.");
+ throw new RSRuntimeException("Adapter creation failed.");
}
- mRS.nAdapter1DBindAllocation(id, mID);
+ mRS.nAdapter1DBindAllocation(id, getID());
return new Adapter1D(id, mRS);
}
@@ -267,27 +265,27 @@
public void setConstraint(Dimension dim, int value) {
mRS.validate();
- mRS.nAdapter2DSetConstraint(mID, dim.mID, value);
+ mRS.nAdapter2DSetConstraint(getID(), dim.mID, value);
}
public void data(int[] d) {
mRS.validate();
- mRS.nAdapter2DData(mID, d);
+ mRS.nAdapter2DData(getID(), d);
}
public void data(float[] d) {
mRS.validate();
- mRS.nAdapter2DData(mID, d);
+ mRS.nAdapter2DData(getID(), d);
}
public void subData(int xoff, int yoff, int w, int h, int[] d) {
mRS.validate();
- mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d);
}
public void subData(int xoff, int yoff, int w, int h, float[] d) {
mRS.validate();
- mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d);
}
}
@@ -295,9 +293,12 @@
mRS.validate();
int id = mRS.nAdapter2DCreate();
if(id == 0) {
- throw new IllegalStateException("allocation failed.");
+ throw new RSRuntimeException("allocation failed.");
}
- mRS.nAdapter2DBindAllocation(id, mID);
+ mRS.nAdapter2DBindAllocation(id, getID());
+ if(id == 0) {
+ throw new RSRuntimeException("Adapter creation failed.");
+ }
return new Adapter2D(id, mRS);
}
@@ -309,14 +310,16 @@
mBitmapOptions.inScaled = false;
}
- static public Allocation createTyped(RenderScript rs, Type type)
- throws IllegalArgumentException {
+ static public Allocation createTyped(RenderScript rs, Type type) {
rs.validate();
- if(type.mID == 0) {
- throw new IllegalStateException("Bad Type");
+ if(type.getID() == 0) {
+ throw new RSInvalidStateException("Bad Type");
}
- int id = rs.nAllocationCreateTyped(type.mID);
+ int id = rs.nAllocationCreateTyped(type.getID());
+ if(id == 0) {
+ throw new RSRuntimeException("Allocation creation failed.");
+ }
return new Allocation(id, rs, type);
}
@@ -328,9 +331,9 @@
b.add(Dimension.X, count);
Type t = b.create();
- int id = rs.nAllocationCreateTyped(t.mID);
+ int id = rs.nAllocationCreateTyped(t.getID());
if(id == 0) {
- throw new IllegalStateException("Bad element.");
+ throw new RSRuntimeException("Allocation creation failed.");
}
return new Allocation(id, rs, t);
}
@@ -349,7 +352,7 @@
if (bc == Bitmap.Config.RGB_565) {
return Element.RGB_565(rs);
}
- throw new IllegalStateException("Bad bitmap type.");
+ throw new RSInvalidStateException("Bad bitmap type.");
}
static private Type typeFromBitmap(RenderScript rs, Bitmap b) {
@@ -360,28 +363,26 @@
return tb.create();
}
- static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
- throws IllegalArgumentException {
+ static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) {
rs.validate();
Type t = typeFromBitmap(rs, b);
- int id = rs.nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ int id = rs.nAllocationCreateFromBitmap(dstFmt.getID(), genMips, b);
if(id == 0) {
- throw new IllegalStateException("Load failed.");
+ throw new RSRuntimeException("Load failed.");
}
return new Allocation(id, rs, t);
}
- static public Allocation createBitmapRef(RenderScript rs, Bitmap b)
- throws IllegalArgumentException {
+ static public Allocation createBitmapRef(RenderScript rs, Bitmap b) {
rs.validate();
Type t = typeFromBitmap(rs, b);
int id = rs.nAllocationCreateBitmapRef(t.getID(), b);
if(id == 0) {
- throw new IllegalStateException("Load failed.");
+ throw new RSRuntimeException("Load failed.");
}
Allocation a = new Allocation(id, rs, t);
@@ -389,8 +390,7 @@
return a;
}
- static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
- throws IllegalArgumentException {
+ static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) {
rs.validate();
InputStream is = null;
@@ -399,15 +399,12 @@
is = res.openRawResource(id, value);
int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
- int allocationId = rs.nAllocationCreateFromAssetStream(dstFmt.mID, genMips,
- asset);
+ int aId = rs.nAllocationCreateFromAssetStream(dstFmt.getID(), genMips, asset);
- if(allocationId == 0) {
- throw new IllegalStateException("Load failed.");
+ if (aId == 0) {
+ throw new RSRuntimeException("Load failed.");
}
- return new Allocation(allocationId, rs, null);
- } catch (Exception e) {
- // Ignore
+ return new Allocation(aId, rs, null);
} finally {
if (is != null) {
try {
@@ -417,12 +414,9 @@
}
}
}
-
- return null;
}
- static public Allocation createFromString(RenderScript rs, String str)
- throws IllegalArgumentException {
+ static public Allocation createFromString(RenderScript rs, String str) {
byte[] allocArray = null;
try {
allocArray = str.getBytes("UTF-8");
@@ -431,9 +425,8 @@
return alloc;
}
catch (Exception e) {
- Log.e("rs", "could not convert string to utf-8");
+ throw new RSRuntimeException("Could not convert string to utf-8.");
}
- return null;
}
}
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index 69907d9..026f7de 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -21,9 +21,12 @@
/**
* @hide
*
+ * BaseObj is the base class for interfacing with native renderscript objects.
+ * It primarly contains code for tracking the native object ID and forcably
+ * disconecting the object from the native allocation for early cleanup.
+ *
**/
class BaseObj {
-
BaseObj(int id, RenderScript rs) {
rs.validate();
mRS = rs;
@@ -31,6 +34,13 @@
mDestroyed = false;
}
+ void setID(int id) {
+ if (mID != 0) {
+ throw new RSRuntimeException("Internal Error, reset of object ID.");
+ }
+ mID = id;
+ }
+
public int getID() {
if (mDestroyed) {
throw new RSInvalidStateException("using a destroyed object.");
@@ -38,9 +48,9 @@
return mID;
}
- int mID;
- boolean mDestroyed;
- String mName;
+ private int mID;
+ private boolean mDestroyed;
+ private String mName;
RenderScript mRS;
public void setName(String s) {
@@ -74,7 +84,7 @@
super.finalize();
}
- public void destroy() {
+ synchronized public void destroy() {
if(mDestroyed) {
throw new RSInvalidStateException("Object already destroyed.");
}
@@ -85,6 +95,8 @@
// If an object came from an a3d file, java fields need to be
// created with objects from the native layer
void updateFromNative() {
+ mRS.validate();
+ mName = mRS.nGetName(getID());
}
}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index f844b7e..8907cd2 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -373,10 +373,11 @@
@Override
void updateFromNative() {
+ super.updateFromNative();
// we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
int[] dataBuffer = new int[5];
- mRS.nElementGetNativeData(mID, dataBuffer);
+ mRS.nElementGetNativeData(getID(), dataBuffer);
mNormalized = dataBuffer[2] == 1 ? true : false;
mVectorSize = dataBuffer[3];
@@ -399,7 +400,7 @@
mElementNames = new String[numSubElements];
int[] subElementIds = new int[numSubElements];
- mRS.nElementGetSubElements(mID, subElementIds, mElementNames);
+ mRS.nElementGetSubElements(getID(), subElementIds, mElementNames);
for(int i = 0; i < numSubElements; i ++) {
mElements[i] = new Element(subElementIds[i], mRS);
mElements[i].updateFromNative();
@@ -523,7 +524,7 @@
int[] ids = new int[ein.length];
for (int ct = 0; ct < ein.length; ct++ ) {
- ids[ct] = ein[ct].mID;
+ ids[ct] = ein[ct].getID();
}
int id = mRS.nElementCreate2(ids, sin, asin);
return new Element(id, mRS, ein, sin, asin);
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index fc74fc4..af85d8e 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -149,7 +149,7 @@
}
private void initEntries() {
- int numFileEntries = mRS.nFileA3DGetNumIndexEntries(mID);
+ int numFileEntries = mRS.nFileA3DGetNumIndexEntries(getID());
if(numFileEntries <= 0) {
return;
}
@@ -158,10 +158,10 @@
int[] ids = new int[numFileEntries];
String[] names = new String[numFileEntries];
- mRS.nFileA3DGetIndexEntries(mID, numFileEntries, ids, names);
+ mRS.nFileA3DGetIndexEntries(getID(), numFileEntries, ids, names);
for(int i = 0; i < numFileEntries; i ++) {
- mFileEntries[i] = new IndexEntry(mRS, i, mID, names[i], ClassID.toClassID(ids[i]));
+ mFileEntries[i] = new IndexEntry(mRS, i, getID(), names[i], ClassID.toClassID(ids[i]));
}
}
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
index bb382f2..4187992 100644
--- a/graphics/java/android/renderscript/Mesh.java
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -60,16 +60,16 @@
@Override
void updateFromNative() {
- mName = mRS.nGetName(mID);
- int vtxCount = mRS.nMeshGetVertexBufferCount(mID);
- int idxCount = mRS.nMeshGetIndexCount(mID);
+ super.updateFromNative();
+ int vtxCount = mRS.nMeshGetVertexBufferCount(getID());
+ int idxCount = mRS.nMeshGetIndexCount(getID());
int[] vtxIDs = new int[vtxCount];
int[] idxIDs = new int[idxCount];
int[] primitives = new int[idxCount];
- mRS.nMeshGetVertices(mID, vtxIDs, vtxCount);
- mRS.nMeshGetIndices(mID, idxIDs, primitives, idxCount);
+ mRS.nMeshGetVertices(getID(), vtxIDs, vtxCount);
+ mRS.nMeshGetIndices(getID(), idxIDs, primitives, idxCount);
mVertexBuffers = new Allocation[vtxCount];
mIndexBuffers = new Allocation[idxCount];
@@ -292,7 +292,7 @@
for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
Entry entry = b.mVertexTypes[ct];
- rs.nMeshBindVertex(id, entry.a.mID, ct);
+ rs.nMeshBindVertex(id, entry.a.getID(), ct);
newMesh.mVertexBuffers[ct] = entry.a;
}
rs.nMeshInitVertexAttribs(id);
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index 35236ca..83c3601 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -54,7 +54,7 @@
a.getType().getID() != mConstants[slot].getID()) {
throw new IllegalArgumentException("Allocation type does not match slot type.");
}
- mRS.nProgramBindConstants(mID, slot, a.mID);
+ mRS.nProgramBindConstants(getID(), slot, a.getID());
}
public void bindTexture(Allocation va, int slot)
@@ -64,7 +64,7 @@
throw new IllegalArgumentException("Slot ID out of range.");
}
- mRS.nProgramBindTexture(mID, slot, va.mID);
+ mRS.nProgramBindTexture(getID(), slot, va.getID());
}
public void bindSampler(Sampler vs, int slot)
@@ -74,7 +74,7 @@
throw new IllegalArgumentException("Slot ID out of range.");
}
- mRS.nProgramBindSampler(mID, slot, vs.mID);
+ mRS.nProgramBindSampler(getID(), slot, vs.getID());
}
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 8858b74..d30e483 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -42,15 +42,15 @@
for (int i=0; i < mInputCount; i++) {
tmp[idx++] = 0;
- tmp[idx++] = mInputs[i].mID;
+ tmp[idx++] = mInputs[i].getID();
}
for (int i=0; i < mOutputCount; i++) {
tmp[idx++] = 1;
- tmp[idx++] = mOutputs[i].mID;
+ tmp[idx++] = mOutputs[i].getID();
}
for (int i=0; i < mConstantCount; i++) {
tmp[idx++] = 2;
- tmp[idx++] = mConstants[i].mID;
+ tmp[idx++] = mConstants[i].getID();
}
tmp[idx++] = 3;
tmp[idx++] = mTextureCount;
diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java
index 791dac8..5b55015 100644
--- a/graphics/java/android/renderscript/ProgramRaster.java
+++ b/graphics/java/android/renderscript/ProgramRaster.java
@@ -58,13 +58,13 @@
void setLineWidth(float w) {
mRS.validate();
mLineWidth = w;
- mRS.nProgramRasterSetLineWidth(mID, w);
+ mRS.nProgramRasterSetLineWidth(getID(), w);
}
void setCullMode(CullMode m) {
mRS.validate();
mCullMode = m;
- mRS.nProgramRasterSetCullMode(mID, m.mID);
+ mRS.nProgramRasterSetCullMode(getID(), m.mID);
}
public static ProgramRaster CULL_BACK(RenderScript rs) {
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index 32c0d01..d191b06 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -288,15 +288,7 @@
}
static synchronized ProgramStore internalCreate(RenderScript rs, Builder b) {
- int inID = 0;
- int outID = 0;
- if (b.mIn != null) {
- inID = b.mIn.mID;
- }
- if (b.mOut != null) {
- outID = b.mOut.mID;
- }
- rs.nProgramStoreBegin(inID, outID);
+ rs.nProgramStoreBegin(0, 0);
rs.nProgramStoreDepthFunc(b.mDepthFunc.mID);
rs.nProgramStoreDepthMask(b.mDepthMask);
rs.nProgramStoreColorMask(b.mColorMaskR,
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 65a0af2..13f017a 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -51,15 +51,15 @@
for (int i=0; i < mInputCount; i++) {
tmp[idx++] = 0;
- tmp[idx++] = mInputs[i].mID;
+ tmp[idx++] = mInputs[i].getID();
}
for (int i=0; i < mOutputCount; i++) {
tmp[idx++] = 1;
- tmp[idx++] = mOutputs[i].mID;
+ tmp[idx++] = mOutputs[i].getID();
}
for (int i=0; i < mConstantCount; i++) {
tmp[idx++] = 2;
- tmp[idx++] = mConstants[i].mID;
+ tmp[idx++] = mConstants[i].getID();
}
tmp[idx++] = 3;
tmp[idx++] = mTextureCount;
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index b3774d4..64afb6f 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -738,7 +738,7 @@
protected int safeID(BaseObj o) {
if(o != null) {
- return o.mID;
+ return o.getID();
}
return 0;
}
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 430789a..7d7dd6d 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -38,19 +38,19 @@
}
public void execute() {
- mRS.nScriptInvoke(mScript.mID, mSlot);
+ mRS.nScriptInvoke(mScript.getID(), mSlot);
}
}
protected void invoke(int slot) {
- mRS.nScriptInvoke(mID, slot);
+ mRS.nScriptInvoke(getID(), slot);
}
protected void invoke(int slot, FieldPacker v) {
if (v != null) {
- mRS.nScriptInvokeV(mID, slot, v.getData());
+ mRS.nScriptInvokeV(getID(), slot, v.getData());
} else {
- mRS.nScriptInvoke(mID, slot);
+ mRS.nScriptInvoke(getID(), slot);
}
}
@@ -62,40 +62,40 @@
public void bindAllocation(Allocation va, int slot) {
mRS.validate();
if (va != null) {
- mRS.nScriptBindAllocation(mID, va.mID, slot);
+ mRS.nScriptBindAllocation(getID(), va.getID(), slot);
} else {
- mRS.nScriptBindAllocation(mID, 0, slot);
+ mRS.nScriptBindAllocation(getID(), 0, slot);
}
}
public void setVar(int index, float v) {
- mRS.nScriptSetVarF(mID, index, v);
+ mRS.nScriptSetVarF(getID(), index, v);
}
public void setVar(int index, double v) {
- mRS.nScriptSetVarD(mID, index, v);
+ mRS.nScriptSetVarD(getID(), index, v);
}
public void setVar(int index, int v) {
- mRS.nScriptSetVarI(mID, index, v);
+ mRS.nScriptSetVarI(getID(), index, v);
}
public void setVar(int index, long v) {
- mRS.nScriptSetVarJ(mID, index, v);
+ mRS.nScriptSetVarJ(getID(), index, v);
}
public void setVar(int index, boolean v) {
- mRS.nScriptSetVarI(mID, index, v ? 1 : 0);
+ mRS.nScriptSetVarI(getID(), index, v ? 1 : 0);
}
public void setVar(int index, FieldPacker v) {
- mRS.nScriptSetVarV(mID, index, v.getData());
+ mRS.nScriptSetVarV(getID(), index, v.getData());
}
public void setTimeZone(String timeZone) {
mRS.validate();
try {
- mRS.nScriptSetTimeZone(mID, timeZone.getBytes("UTF-8"));
+ mRS.nScriptSetTimeZone(getID(), timeZone.getBytes("UTF-8"));
} catch (java.io.UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 5215795..44fc5fd 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -39,7 +39,8 @@
protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
super(0, rs);
- mID = internalCreate(rs, resources, resourceID);
+ int id = internalCreate(rs, resources, resourceID);
+ setID(id);
}
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 0d65737..ad933b8 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -106,7 +106,7 @@
// We have 6 integer to obtain mDimX; mDimY; mDimZ;
// mDimLOD; mDimFaces; mElement;
int[] dataBuffer = new int[6];
- mRS.nTypeGetNativeData(mID, dataBuffer);
+ mRS.nTypeGetNativeData(getID(), dataBuffer);
mDimX = dataBuffer[0];
mDimY = dataBuffer[1];
@@ -135,7 +135,7 @@
}
public Builder(RenderScript rs, Element e) {
- if(e.mID == 0) {
+ if(e.getID() == 0) {
throw new RSIllegalArgumentException("Invalid element.");
}
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 32b6fa1..a710546 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -44,7 +44,8 @@
AUDIO_SOURCE_VOICE_CALL = 4,
AUDIO_SOURCE_CAMCORDER = 5,
AUDIO_SOURCE_VOICE_RECOGNITION = 6,
- AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_RECOGNITION,
+ AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+ AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_COMMUNICATION,
AUDIO_SOURCE_LIST_END // must be last - used to validate audio source type
};
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index bb469e5..7bf07eb 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -154,6 +154,7 @@
bool exceedsFileDurationLimit();
bool isFileStreamable() const;
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+ void writeCompositionMatrix(int32_t degrees);
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 770e596..d08df44 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -127,7 +127,9 @@
}
mPathHeap = recorder.mPathHeap;
- mPathHeap->safeRef();
+ if (mPathHeap) {
+ mPathHeap->safeRef();
+ }
}
DisplayList::~DisplayList() {
@@ -155,7 +157,12 @@
}
mMatrices.clear();
- mPathHeap->safeUnref();
+ if (mPathHeap) {
+ for (int i = 0; i < mPathHeap->count(); i++) {
+ caches.pathCache.remove(&(*mPathHeap)[i]);
+ }
+ mPathHeap->safeUnref();
+ }
}
void DisplayList::init() {
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index b58785a..04d07db 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -92,10 +92,13 @@
///////////////////////////////////////////////////////////////////////////////
void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) {
- const uint32_t size = texture->width * texture->height;
- mSize -= size;
-
if (texture) {
+ const uint32_t size = texture->width * texture->height;
+ mSize -= size;
+
+ PATH_LOGD("PathCache::callback: delete path: name, size, mSize = %d, %d, %d",
+ texture->id, size, mSize);
+
glDeleteTextures(1, &texture->id);
delete texture;
}
@@ -107,12 +110,18 @@
void PathCache::remove(SkPath* path) {
Mutex::Autolock _l(mLock);
+
// TODO: Linear search...
+ Vector<uint32_t> pathsToRemove;
for (uint32_t i = 0; i < mCache.size(); i++) {
if (mCache.getKeyAt(i).path == path) {
- mCache.removeAt(i);
+ pathsToRemove.push(i);
}
}
+
+ for (size_t i = 0; i < pathsToRemove.size(); i++) {
+ mCache.removeAt(pathsToRemove.itemAt(i));
+ }
}
PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
@@ -188,6 +197,8 @@
if (size < mMaxSize) {
mLock.lock();
mSize += size;
+ PATH_LOGD("PathCache::get: create path: name, size, mSize = %d, %d, %d",
+ texture->id, size, mSize);
mCache.put(entry, texture);
mLock.unlock();
} else {
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index db5ce08..aea71cb 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -28,6 +28,24 @@
namespace android {
namespace uirenderer {
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_PATHS 0
+
+// Debug
+#if DEBUG_PATHS
+ #define PATH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define PATH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes
+///////////////////////////////////////////////////////////////////////////////
+
/**
* Describe a path in the path cache.
*/
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 9d54277..2f7c7be 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -74,10 +74,10 @@
///////////////////////////////////////////////////////////////////////////////
void TextDropShadowCache::operator()(ShadowText& text, ShadowTexture*& texture) {
- const uint32_t size = texture->width * texture->height;
- mSize -= size;
-
if (texture) {
+ const uint32_t size = texture->width * texture->height;
+ mSize -= size;
+
glDeleteTextures(1, &texture->id);
delete texture;
}
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 0c7948f..2497925 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -94,8 +94,8 @@
// This will be called already locked
if (texture) {
mSize -= texture->bitmapSize;
- TEXTURE_LOGD("TextureCache::callback: removed size, mSize = %d, %d",
- texture->bitmapSize, mSize);
+ TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
+ texture->id, texture->bitmapSize, mSize);
glDeleteTextures(1, &texture->id);
delete texture;
}
@@ -133,8 +133,8 @@
if (size < mMaxSize) {
mLock.lock();
mSize += size;
- TEXTURE_LOGD("TextureCache::get: create texture(0x%p): size, mSize = %d, %d",
- bitmap, size, mSize);
+ TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
+ bitmap, texture->id, size, mSize);
mCache.put(bitmap, texture);
mLock.unlock();
} else {
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index d9d2387..5c314fc 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -39,6 +39,10 @@
#define TEXTURE_LOGD(...)
#endif
+///////////////////////////////////////////////////////////////////////////////
+// Classes
+///////////////////////////////////////////////////////////////////////////////
+
/**
* A simple LRU texture cache. The cache has a maximum size expressed in bytes.
* Any texture added to the cache causing the cache to grow beyond the maximum
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index eb46e950..0afff34 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -53,7 +53,7 @@
boolean holdingColor[] = new boolean[10];
public void newTouchPosition(float x, float y, float pressure, int id) {
- if (id > holdingColor.length) {
+ if (id >= holdingColor.length) {
return;
}
int rate = (int)(pressure * pressure * 500.f);
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index b74fa8e..28078fc 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -869,6 +869,8 @@
}
} else {
rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
+ delete texAlloc;
+ return NULL;
}
return texAlloc;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 90febba..2bea84f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -148,6 +148,15 @@
/** Microphone audio source tuned for voice recognition if available, behaves like
* {@link #DEFAULT} otherwise. */
public static final int VOICE_RECOGNITION = 6;
+
+ /**
+ * @hide
+ * Microphone audio source tuned for voice communications such as VoIP. It
+ * will for instance take advantage of echo cancellation or automatic gain control
+ * if available. It otherwise behaves like {@link #DEFAULT} if no voice processing
+ * is available.
+ */
+ public static final int VOICE_COMMUNICATION = 7;
}
/**
@@ -253,7 +262,7 @@
* Gets the maximum value for audio sources.
* @see android.media.MediaRecorder.AudioSource
*/
- public static final int getAudioSourceMax() { return AudioSource.VOICE_RECOGNITION; }
+ public static final int getAudioSourceMax() { return AudioSource.VOICE_COMMUNICATION; }
/**
* Sets the video source to be used for recording. If this method is not
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6a25dc5..9da5f01 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -345,6 +345,17 @@
return OK;
}
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
+ LOGV("setParamVideoRotation: %d", degrees);
+ if (degrees < 0 || degrees % 90 != 0) {
+ LOGE("Unsupported video rotation angle: %d", degrees);
+ return BAD_VALUE;
+ }
+ mRotationDegrees = degrees % 360;
+ return OK;
+}
+
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
if (timeUs <= 0) {
@@ -599,6 +610,11 @@
if (safe_strtoi32(value.string(), &video_bitrate)) {
return setParamVideoEncodingBitRate(video_bitrate);
}
+ } else if (key == "video-param-rotation-angle-degrees") {
+ int32_t degrees;
+ if (safe_strtoi32(value.string(), °rees)) {
+ return setParamVideoRotation(degrees);
+ }
} else if (key == "video-param-i-frames-interval") {
int32_t seconds;
if (safe_strtoi32(value.string(), &seconds)) {
@@ -1255,6 +1271,9 @@
if (mTrackEveryTimeDurationUs > 0) {
(*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
+ if (mRotationDegrees != 0) {
+ (*meta)->setInt32(kKeyRotation, mRotationDegrees);
+ }
}
status_t StagefrightRecorder::startMPEG4Recording() {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index d11d7e0..36a15a8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -93,6 +93,7 @@
int64_t mMaxFileSizeBytes;
int64_t mMaxFileDurationUs;
int64_t mTrackEveryTimeDurationUs;
+ int32_t mRotationDegrees; // Clockwise
bool mCaptureTimeLapse;
int64_t mTimeBetweenTimeLapseFrameCaptureUs;
@@ -146,6 +147,7 @@
status_t setParamVideoEncoderLevel(int32_t level);
status_t setParamVideoCameraId(int32_t cameraId);
status_t setParamVideoTimeScale(int32_t timeScale);
+ status_t setParamVideoRotation(int32_t degrees);
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 562eb60..1df0bed 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -44,8 +44,10 @@
TimeSource.cpp \
TimedEventQueue.cpp \
Utils.cpp \
+ VBRISeeker.cpp \
WAVExtractor.cpp \
WVMExtractor.cpp \
+ XINGSeeker.cpp \
avc_utils.cpp \
string.cpp
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 82c0426..84ced8f 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -21,6 +21,8 @@
#include "include/MP3Extractor.h"
#include "include/ID3.h"
+#include "include/VBRISeeker.h"
+#include "include/XINGSeeker.h"
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
@@ -42,10 +44,11 @@
// Yes ... there are things that must indeed match...
static const uint32_t kMask = 0xfffe0cc0;
-static bool get_mp3_frame_size(
+// static
+bool MP3Extractor::get_mp3_frame_size(
uint32_t header, size_t *frame_size,
- int *out_sampling_rate = NULL, int *out_channels = NULL,
- int *out_bitrate = NULL) {
+ int *out_sampling_rate, int *out_channels,
+ int *out_bitrate) {
*frame_size = 0;
if (out_sampling_rate) {
@@ -178,136 +181,13 @@
return true;
}
-static bool parse_xing_header(
- const sp<DataSource> &source, off_t first_frame_pos,
- int32_t *frame_number = NULL, int32_t *byte_number = NULL,
- char *table_of_contents = NULL, int32_t *quality_indicator = NULL,
- int64_t *duration = NULL) {
-
- if (frame_number) {
- *frame_number = 0;
- }
- if (byte_number) {
- *byte_number = 0;
- }
- if (table_of_contents) {
- table_of_contents[0] = 0;
- }
- if (quality_indicator) {
- *quality_indicator = 0;
- }
- if (duration) {
- *duration = 0;
- }
-
- uint8_t buffer[4];
- int offset = first_frame_pos;
- if (source->readAt(offset, &buffer, 4) < 4) { // get header
- return false;
- }
- offset += 4;
-
- uint8_t id, layer, sr_index, mode;
- layer = (buffer[1] >> 1) & 3;
- id = (buffer[1] >> 3) & 3;
- sr_index = (buffer[2] >> 2) & 3;
- mode = (buffer[3] >> 6) & 3;
- if (layer == 0) {
- return false;
- }
- if (id == 1) {
- return false;
- }
- if (sr_index == 3) {
- return false;
- }
- // determine offset of XING header
- if(id&1) { // mpeg1
- if (mode != 3) offset += 32;
- else offset += 17;
- } else { // mpeg2
- if (mode != 3) offset += 17;
- else offset += 9;
- }
-
- if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
- return false;
- }
- offset += 4;
- // Check XING ID
- if ((buffer[0] != 'X') || (buffer[1] != 'i')
- || (buffer[2] != 'n') || (buffer[3] != 'g')) {
- if ((buffer[0] != 'I') || (buffer[1] != 'n')
- || (buffer[2] != 'f') || (buffer[3] != 'o')) {
- return false;
- }
- }
-
- if (source->readAt(offset, &buffer, 4) < 4) { // flags
- return false;
- }
- offset += 4;
- uint32_t flags = U32_AT(buffer);
-
- if (flags & 0x0001) { // Frames field is present
- if (source->readAt(offset, buffer, 4) < 4) {
- return false;
- }
- if (frame_number) {
- *frame_number = U32_AT(buffer);
- }
- int32_t frame = U32_AT(buffer);
- // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer
- const int samplesPerFrames[2][3] =
- {
- { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3
- { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3
- };
- // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
- const int samplingRates[4][3] =
- {
- { 11025, 12000, 8000, }, // MPEG 2.5
- { 0, 0, 0, }, // reserved
- { 22050, 24000, 16000, }, // MPEG 2
- { 44100, 48000, 32000, } // MPEG 1
- };
- if (duration) {
- *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL
- / samplingRates[id][sr_index];
- }
- offset += 4;
- }
- if (flags & 0x0002) { // Bytes field is present
- if (byte_number) {
- if (source->readAt(offset, buffer, 4) < 4) {
- return false;
- }
- *byte_number = U32_AT(buffer);
- }
- offset += 4;
- }
- if (flags & 0x0004) { // TOC field is present
- if (table_of_contents) {
- if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
- return false;
- }
- }
- offset += 100;
- }
- if (flags & 0x0008) { // Quality indicator field is present
- if (quality_indicator) {
- if (source->readAt(offset, buffer, 4) < 4) {
- return false;
- }
- *quality_indicator = U32_AT(buffer);
- }
- }
- return true;
-}
-
static bool Resync(
const sp<DataSource> &source, uint32_t match_header,
- off_t *inout_pos, uint32_t *out_header) {
+ off_t *inout_pos, off_t *post_id3_pos, uint32_t *out_header) {
+ if (post_id3_pos != NULL) {
+ *post_id3_pos = 0;
+ }
+
if (*inout_pos == 0) {
// Skip an optional ID3 header if syncing at the very beginning
// of the datasource.
@@ -340,6 +220,10 @@
LOGV("skipped ID3 tag, new starting offset is %ld (0x%08lx)",
*inout_pos, *inout_pos);
}
+
+ if (post_id3_pos != NULL) {
+ *post_id3_pos = *inout_pos;
+ }
}
off_t pos = *inout_pos;
@@ -365,8 +249,9 @@
size_t frame_size;
int sample_rate, num_channels, bitrate;
- if (!get_mp3_frame_size(header, &frame_size,
- &sample_rate, &num_channels, &bitrate)) {
+ if (!MP3Extractor::get_mp3_frame_size(
+ header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
++pos;
continue;
}
@@ -396,7 +281,8 @@
}
size_t test_frame_size;
- if (!get_mp3_frame_size(test_header, &test_frame_size)) {
+ if (!MP3Extractor::get_mp3_frame_size(
+ test_header, &test_frame_size)) {
valid = false;
break;
}
@@ -427,7 +313,7 @@
MP3Source(
const sp<MetaData> &meta, const sp<DataSource> &source,
off_t first_frame_pos, uint32_t fixed_header,
- int32_t byte_number, const char *table_of_contents);
+ const sp<MP3Seeker> &seeker);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -448,9 +334,7 @@
off_t mCurrentPos;
int64_t mCurrentTimeUs;
bool mStarted;
- int32_t mByteNumber; // total number of bytes in this MP3
- // TOC entries in XING header. Skip the first one since it's always 0.
- char mTableOfContents[99];
+ sp<MP3Seeker> mSeeker;
MediaBufferGroup *mGroup;
MP3Source(const MP3Source &);
@@ -462,25 +346,28 @@
: mInitCheck(NO_INIT),
mDataSource(source),
mFirstFramePos(-1),
- mFixedHeader(0),
- mByteNumber(0) {
+ mFixedHeader(0) {
off_t pos = 0;
+ off_t post_id3_pos;
uint32_t header;
bool success;
int64_t meta_offset;
uint32_t meta_header;
+ int64_t meta_post_id3_offset;
if (meta != NULL
&& meta->findInt64("offset", &meta_offset)
- && meta->findInt32("header", (int32_t *)&meta_header)) {
+ && meta->findInt32("header", (int32_t *)&meta_header)
+ && meta->findInt64("post-id3-offset", &meta_post_id3_offset)) {
// The sniffer has already done all the hard work for us, simply
// accept its judgement.
pos = (off_t)meta_offset;
header = meta_header;
+ post_id3_pos = (off_t)meta_post_id3_offset;
success = true;
} else {
- success = Resync(mDataSource, 0, &pos, &header);
+ success = Resync(mDataSource, 0, &pos, &post_id3_pos, &header);
}
if (!success) {
@@ -505,21 +392,27 @@
mMeta->setInt32(kKeyBitRate, bitrate * 1000);
mMeta->setInt32(kKeyChannelCount, num_channels);
- int64_t duration;
- parse_xing_header(
- mDataSource, mFirstFramePos, NULL, &mByteNumber,
- mTableOfContents, NULL, &duration);
- if (duration > 0) {
- mMeta->setInt64(kKeyDuration, duration);
- } else {
+ mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
+
+ if (mSeeker == NULL) {
+ mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
+ }
+
+ int64_t durationUs;
+
+ if (mSeeker == NULL || !mSeeker->getDuration(&durationUs)) {
off_t fileSize;
if (mDataSource->getSize(&fileSize) == OK) {
- mMeta->setInt64(
- kKeyDuration,
- 8000LL * (fileSize - mFirstFramePos) / bitrate);
+ durationUs = 8000LL * (fileSize - mFirstFramePos) / bitrate;
+ } else {
+ durationUs = -1;
}
}
+ if (durationUs >= 0) {
+ mMeta->setInt64(kKeyDuration, durationUs);
+ }
+
mInitCheck = OK;
}
@@ -534,7 +427,7 @@
return new MP3Source(
mMeta, mDataSource, mFirstFramePos, mFixedHeader,
- mByteNumber, mTableOfContents);
+ mSeeker);
}
sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -550,7 +443,7 @@
MP3Source::MP3Source(
const sp<MetaData> &meta, const sp<DataSource> &source,
off_t first_frame_pos, uint32_t fixed_header,
- int32_t byte_number, const char *table_of_contents)
+ const sp<MP3Seeker> &seeker)
: mMeta(meta),
mDataSource(source),
mFirstFramePos(first_frame_pos),
@@ -558,9 +451,8 @@
mCurrentPos(0),
mCurrentTimeUs(0),
mStarted(false),
- mByteNumber(byte_number),
+ mSeeker(seeker),
mGroup(NULL) {
- memcpy (mTableOfContents, table_of_contents, sizeof(mTableOfContents));
}
MP3Source::~MP3Source() {
@@ -607,43 +499,21 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
- int32_t bitrate;
- if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
- // bitrate is in bits/sec.
- LOGI("no bitrate");
+ int64_t actualSeekTimeUs = seekTimeUs;
+ if (mSeeker == NULL
+ || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
+ int32_t bitrate;
+ if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
+ // bitrate is in bits/sec.
+ LOGI("no bitrate");
- return ERROR_UNSUPPORTED;
- }
-
- mCurrentTimeUs = seekTimeUs;
- // interpolate in TOC to get file seek point in bytes
- int64_t duration;
- if ((mByteNumber > 0) && (mTableOfContents[0] > 0)
- && mMeta->findInt64(kKeyDuration, &duration)) {
- float percent = (float)seekTimeUs * 100 / duration;
- float fx;
- if( percent <= 0.0f ) {
- fx = 0.0f;
- } else if( percent >= 100.0f ) {
- fx = 256.0f;
- } else {
- int a = (int)percent;
- float fa, fb;
- if ( a == 0 ) {
- fa = 0.0f;
- } else {
- fa = (float)mTableOfContents[a-1];
- }
- if ( a < 99 ) {
- fb = (float)mTableOfContents[a];
- } else {
- fb = 256.0f;
- }
- fx = fa + (fb-fa)*(percent-a);
+ return ERROR_UNSUPPORTED;
}
- mCurrentPos = mFirstFramePos + (int)((1.0f/256.0f)*fx*mByteNumber);
- } else {
+
+ mCurrentTimeUs = seekTimeUs;
mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
+ } else {
+ mCurrentTimeUs = actualSeekTimeUs;
}
}
@@ -667,7 +537,8 @@
uint32_t header = U32_AT((const uint8_t *)buffer->data());
if ((header & kMask) == (mFixedHeader & kMask)
- && get_mp3_frame_size(header, &frame_size, NULL, NULL, &bitrate)) {
+ && MP3Extractor::get_mp3_frame_size(
+ header, &frame_size, NULL, NULL, &bitrate)) {
break;
}
@@ -675,7 +546,7 @@
LOGV("lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader);
off_t pos = mCurrentPos;
- if (!Resync(mDataSource, mFixedHeader, &pos, NULL)) {
+ if (!Resync(mDataSource, mFixedHeader, &pos, NULL, NULL)) {
LOGE("Unable to resync. Signalling end of stream.");
buffer->release();
@@ -781,14 +652,16 @@
const sp<DataSource> &source, String8 *mimeType,
float *confidence, sp<AMessage> *meta) {
off_t pos = 0;
+ off_t post_id3_pos;
uint32_t header;
- if (!Resync(source, 0, &pos, &header)) {
+ if (!Resync(source, 0, &pos, &post_id3_pos, &header)) {
return false;
}
*meta = new AMessage;
(*meta)->setInt64("offset", pos);
(*meta)->setInt32("header", header);
+ (*meta)->setInt64("post-id3-offset", post_id3_pos);
*mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
*confidence = 0.2f;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b3ed845..17a40b00 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -202,6 +202,7 @@
// Simple validation on the codec specific data
status_t checkCodecSpecificData() const;
+ int32_t mRotation;
void updateTrackSizeEstimate();
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -520,6 +521,59 @@
LOGD("Writer thread stopped");
}
+/*
+ * MP4 file standard defines a composition matrix:
+ * | a b u |
+ * | c d v |
+ * | x y w |
+ *
+ * the element in the matrix is stored in the following
+ * order: {a, b, u, c, d, v, x, y, w},
+ * where a, b, c, d, x, and y is in 16.16 format, while
+ * u, v and w is in 2.30 format.
+ */
+void MPEG4Writer::writeCompositionMatrix(int degrees) {
+ LOGV("writeCompositionMatrix");
+ uint32_t a = 0x00010000;
+ uint32_t b = 0;
+ uint32_t c = 0;
+ uint32_t d = 0x00010000;
+ switch (degrees) {
+ case 0:
+ break;
+ case 90:
+ a = 0;
+ b = 0x00010000;
+ c = 0xFFFF0000;
+ d = 0;
+ break;
+ case 180:
+ a = 0xFFFF0000;
+ d = 0xFFFF0000;
+ break;
+ case 270:
+ a = 0;
+ b = 0xFFFF0000;
+ c = 0x00010000;
+ d = 0;
+ break;
+ default:
+ CHECK(!"Should never reach this unknown rotation");
+ break;
+ }
+
+ writeInt32(a); // a
+ writeInt32(b); // b
+ writeInt32(0); // u
+ writeInt32(c); // c
+ writeInt32(d); // d
+ writeInt32(0); // v
+ writeInt32(0); // x
+ writeInt32(0); // y
+ writeInt32(0x40000000); // w
+}
+
+
status_t MPEG4Writer::stop() {
if (mFile == NULL) {
return OK;
@@ -585,15 +639,7 @@
writeInt16(0); // reserved
writeInt32(0); // reserved
writeInt32(0); // reserved
- writeInt32(0x10000); // matrix
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x10000);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x40000000);
+ writeCompositionMatrix(0); // matrix
writeInt32(0); // predefined
writeInt32(0); // predefined
writeInt32(0); // predefined
@@ -886,7 +932,8 @@
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
- mReachedEOS(false) {
+ mReachedEOS(false),
+ mRotation(0) {
getCodecSpecificDataFromInputFormatIfPossible();
const char *mime;
@@ -1179,6 +1226,11 @@
startTimeUs = 0;
}
+ int32_t rotationDegrees;
+ if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
+ mRotation = rotationDegrees;
+ }
+
mIsRealTimeRecording = true;
{
int32_t isNotRealTime;
@@ -2075,15 +2127,7 @@
mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume
mOwner->writeInt16(0); // reserved
- mOwner->writeInt32(0x10000); // matrix
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x10000);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x40000000);
+ mOwner->writeCompositionMatrix(mRotation); // matrix
if (mIsAudio) {
mOwner->writeInt32(0);
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
new file mode 100644
index 0000000..6608644
--- /dev/null
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VBRISeeker"
+#include <utils/Log.h>
+
+#include "include/VBRISeeker.h"
+
+#include "include/MP3Extractor.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static uint32_t U24_AT(const uint8_t *ptr) {
+ return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+}
+
+// static
+sp<VBRISeeker> VBRISeeker::CreateFromSource(
+ const sp<DataSource> &source, off_t post_id3_pos) {
+ off_t pos = post_id3_pos;
+
+ uint8_t header[4];
+ ssize_t n = source->readAt(pos, header, sizeof(header));
+ if (n < (ssize_t)sizeof(header)) {
+ return NULL;
+ }
+
+ uint32_t tmp = U32_AT(&header[0]);
+ size_t frameSize;
+ int sampleRate;
+ if (!MP3Extractor::get_mp3_frame_size(tmp, &frameSize, &sampleRate)) {
+ return NULL;
+ }
+
+ // VBRI header follows 32 bytes after the header _ends_.
+ pos += sizeof(header) + 32;
+
+ uint8_t vbriHeader[26];
+ n = source->readAt(pos, vbriHeader, sizeof(vbriHeader));
+ if (n < (ssize_t)sizeof(vbriHeader)) {
+ return NULL;
+ }
+
+ if (memcmp(vbriHeader, "VBRI", 4)) {
+ return NULL;
+ }
+
+ size_t numFrames = U32_AT(&vbriHeader[14]);
+
+ int64_t durationUs =
+ numFrames * 1000000ll * (sampleRate >= 32000 ? 1152 : 576) / sampleRate;
+
+ LOGV("duration = %.2f secs", durationUs / 1E6);
+
+ size_t numEntries = U16_AT(&vbriHeader[18]);
+ size_t entrySize = U16_AT(&vbriHeader[22]);
+ size_t scale = U16_AT(&vbriHeader[20]);
+
+ LOGV("%d entries, scale=%d, size_per_entry=%d",
+ numEntries,
+ scale,
+ entrySize);
+
+ size_t totalEntrySize = numEntries * entrySize;
+ uint8_t *buffer = new uint8_t[totalEntrySize];
+
+ n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize);
+ if (n < (ssize_t)totalEntrySize) {
+ delete[] buffer;
+ buffer = NULL;
+
+ return NULL;
+ }
+
+ sp<VBRISeeker> seeker = new VBRISeeker;
+ seeker->mBasePos = post_id3_pos;
+ seeker->mDurationUs = durationUs;
+
+ off_t offset = post_id3_pos;
+ for (size_t i = 0; i < numEntries; ++i) {
+ uint32_t numBytes;
+ switch (entrySize) {
+ case 1: numBytes = buffer[i]; break;
+ case 2: numBytes = U16_AT(buffer + 2 * i); break;
+ case 3: numBytes = U24_AT(buffer + 3 * i); break;
+ default:
+ {
+ CHECK_EQ(entrySize, 4u);
+ numBytes = U32_AT(buffer + 4 * i); break;
+ }
+ }
+
+ numBytes *= scale;
+
+ seeker->mSegments.push(numBytes);
+
+ LOGV("entry #%d: %d offset 0x%08lx", i, numBytes, offset);
+ offset += numBytes;
+ }
+
+ delete[] buffer;
+ buffer = NULL;
+
+ LOGI("Found VBRI header.");
+
+ return seeker;
+}
+
+VBRISeeker::VBRISeeker()
+ : mDurationUs(-1) {
+}
+
+bool VBRISeeker::getDuration(int64_t *durationUs) {
+ if (mDurationUs < 0) {
+ return false;
+ }
+
+ *durationUs = mDurationUs;
+
+ return true;
+}
+
+bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off_t *pos) {
+ if (mDurationUs < 0) {
+ return false;
+ }
+
+ int64_t segmentDurationUs = mDurationUs / mSegments.size();
+
+ int64_t nowUs = 0;
+ *pos = mBasePos;
+ size_t segmentIndex = 0;
+ while (segmentIndex < mSegments.size() && nowUs < *timeUs) {
+ nowUs += segmentDurationUs;
+ *pos += mSegments.itemAt(segmentIndex++);
+ }
+
+ LOGV("getOffsetForTime %lld us => 0x%08lx", *timeUs, *pos);
+
+ *timeUs = nowUs;
+
+ return true;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
new file mode 100644
index 0000000..72f260e
--- /dev/null
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/XINGSeeker.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static bool parse_xing_header(
+ const sp<DataSource> &source, off_t first_frame_pos,
+ int32_t *frame_number = NULL, int32_t *byte_number = NULL,
+ char *table_of_contents = NULL, int32_t *quality_indicator = NULL,
+ int64_t *duration = NULL);
+
+// static
+sp<XINGSeeker> XINGSeeker::CreateFromSource(
+ const sp<DataSource> &source, off_t first_frame_pos) {
+ sp<XINGSeeker> seeker = new XINGSeeker;
+
+ seeker->mFirstFramePos = first_frame_pos;
+
+ if (!parse_xing_header(
+ source, first_frame_pos,
+ NULL, &seeker->mSizeBytes, seeker->mTableOfContents,
+ NULL, &seeker->mDurationUs)) {
+ return NULL;
+ }
+
+ LOGI("Found XING header.");
+
+ return seeker;
+}
+
+XINGSeeker::XINGSeeker()
+ : mDurationUs(-1),
+ mSizeBytes(0) {
+}
+
+bool XINGSeeker::getDuration(int64_t *durationUs) {
+ if (mDurationUs < 0) {
+ return false;
+ }
+
+ *durationUs = mDurationUs;
+
+ return true;
+}
+
+bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off_t *pos) {
+ if (mSizeBytes == 0 || mTableOfContents[0] <= 0 || mDurationUs < 0) {
+ return false;
+ }
+
+ float percent = (float)(*timeUs) * 100 / mDurationUs;
+ float fx;
+ if( percent <= 0.0f ) {
+ fx = 0.0f;
+ } else if( percent >= 100.0f ) {
+ fx = 256.0f;
+ } else {
+ int a = (int)percent;
+ float fa, fb;
+ if ( a == 0 ) {
+ fa = 0.0f;
+ } else {
+ fa = (float)mTableOfContents[a-1];
+ }
+ if ( a < 99 ) {
+ fb = (float)mTableOfContents[a];
+ } else {
+ fb = 256.0f;
+ }
+ fx = fa + (fb-fa)*(percent-a);
+ }
+
+ *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos;
+
+ return true;
+}
+
+static bool parse_xing_header(
+ const sp<DataSource> &source, off_t first_frame_pos,
+ int32_t *frame_number, int32_t *byte_number,
+ char *table_of_contents, int32_t *quality_indicator,
+ int64_t *duration) {
+ if (frame_number) {
+ *frame_number = 0;
+ }
+ if (byte_number) {
+ *byte_number = 0;
+ }
+ if (table_of_contents) {
+ table_of_contents[0] = 0;
+ }
+ if (quality_indicator) {
+ *quality_indicator = 0;
+ }
+ if (duration) {
+ *duration = 0;
+ }
+
+ uint8_t buffer[4];
+ int offset = first_frame_pos;
+ if (source->readAt(offset, &buffer, 4) < 4) { // get header
+ return false;
+ }
+ offset += 4;
+
+ uint8_t id, layer, sr_index, mode;
+ layer = (buffer[1] >> 1) & 3;
+ id = (buffer[1] >> 3) & 3;
+ sr_index = (buffer[2] >> 2) & 3;
+ mode = (buffer[3] >> 6) & 3;
+ if (layer == 0) {
+ return false;
+ }
+ if (id == 1) {
+ return false;
+ }
+ if (sr_index == 3) {
+ return false;
+ }
+ // determine offset of XING header
+ if(id&1) { // mpeg1
+ if (mode != 3) offset += 32;
+ else offset += 17;
+ } else { // mpeg2
+ if (mode != 3) offset += 17;
+ else offset += 9;
+ }
+
+ if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
+ return false;
+ }
+ offset += 4;
+ // Check XING ID
+ if ((buffer[0] != 'X') || (buffer[1] != 'i')
+ || (buffer[2] != 'n') || (buffer[3] != 'g')) {
+ if ((buffer[0] != 'I') || (buffer[1] != 'n')
+ || (buffer[2] != 'f') || (buffer[3] != 'o')) {
+ return false;
+ }
+ }
+
+ if (source->readAt(offset, &buffer, 4) < 4) { // flags
+ return false;
+ }
+ offset += 4;
+ uint32_t flags = U32_AT(buffer);
+
+ if (flags & 0x0001) { // Frames field is present
+ if (source->readAt(offset, buffer, 4) < 4) {
+ return false;
+ }
+ if (frame_number) {
+ *frame_number = U32_AT(buffer);
+ }
+ int32_t frame = U32_AT(buffer);
+ // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer
+ const int samplesPerFrames[2][3] =
+ {
+ { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3
+ { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3
+ };
+ // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
+ const int samplingRates[4][3] =
+ {
+ { 11025, 12000, 8000, }, // MPEG 2.5
+ { 0, 0, 0, }, // reserved
+ { 22050, 24000, 16000, }, // MPEG 2
+ { 44100, 48000, 32000, } // MPEG 1
+ };
+ if (duration) {
+ *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL
+ / samplingRates[id][sr_index];
+ }
+ offset += 4;
+ }
+ if (flags & 0x0002) { // Bytes field is present
+ if (byte_number) {
+ if (source->readAt(offset, buffer, 4) < 4) {
+ return false;
+ }
+ *byte_number = U32_AT(buffer);
+ }
+ offset += 4;
+ }
+ if (flags & 0x0004) { // TOC field is present
+ if (table_of_contents) {
+ if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
+ return false;
+ }
+ }
+ offset += 100;
+ }
+ if (flags & 0x0008) { // Quality indicator field is present
+ if (quality_indicator) {
+ if (source->readAt(offset, buffer, 4) < 4) {
+ return false;
+ }
+ *quality_indicator = U32_AT(buffer);
+ }
+ }
+ return true;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index d5a5313..72611cf 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -50,6 +50,7 @@
profileLevel = CORE_PROFILE_LEVEL2;
break;
}
+ break;
default:
LOGE("Unsupported profile (%d) for H263", omxProfile);
return BAD_VALUE;
@@ -74,7 +75,8 @@
LOGE("Unsupported level (%d) for MPEG4 simple profile",
omxLevel);
return BAD_VALUE;
- }
+ }
+ break;
case OMX_VIDEO_MPEG4ProfileSimpleScalable:
switch (omxLevel) {
case OMX_VIDEO_MPEG4Level0b:
@@ -91,6 +93,7 @@
"scalable profile", omxLevel);
return BAD_VALUE;
}
+ break;
case OMX_VIDEO_MPEG4ProfileCore:
switch (omxLevel) {
case OMX_VIDEO_MPEG4Level1:
@@ -104,6 +107,7 @@
"profile", omxLevel);
return BAD_VALUE;
}
+ break;
case OMX_VIDEO_MPEG4ProfileCoreScalable:
switch (omxLevel) {
case OMX_VIDEO_MPEG4Level1:
@@ -120,6 +124,7 @@
"scalable profile", omxLevel);
return BAD_VALUE;
}
+ break;
default:
LOGE("Unsupported MPEG4 profile (%d)", omxProfile);
return BAD_VALUE;
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 30136e7d..11ca243 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -24,6 +24,7 @@
struct AMessage;
class DataSource;
+struct MP3Seeker;
class String8;
class MP3Extractor : public MediaExtractor {
@@ -37,6 +38,11 @@
virtual sp<MetaData> getMetaData();
+ static bool get_mp3_frame_size(
+ uint32_t header, size_t *frame_size,
+ int *out_sampling_rate = NULL, int *out_channels = NULL,
+ int *out_bitrate = NULL);
+
private:
status_t mInitCheck;
@@ -44,8 +50,7 @@
off_t mFirstFramePos;
sp<MetaData> mMeta;
uint32_t mFixedHeader;
- int32_t mByteNumber; // total number of bytes in this MP3
- char mTableOfContents[99]; // TOC entries in XING header
+ sp<MP3Seeker> mSeeker;
MP3Extractor(const MP3Extractor &);
MP3Extractor &operator=(const MP3Extractor &);
diff --git a/media/libstagefright/include/MP3Seeker.h b/media/libstagefright/include/MP3Seeker.h
new file mode 100644
index 0000000..190eaed
--- /dev/null
+++ b/media/libstagefright/include/MP3Seeker.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MP3_SEEKER_H_
+
+#define MP3_SEEKER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MP3Seeker : public RefBase {
+ MP3Seeker() {}
+
+ virtual bool getDuration(int64_t *durationUs) = 0;
+
+ // Given a request seek time in "*timeUs", find the byte offset closest
+ // to that position and return it in "*pos". Update "*timeUs" to reflect
+ // the actual time that seekpoint represents.
+ virtual bool getOffsetForTime(int64_t *timeUs, off_t *pos) = 0;
+
+protected:
+ virtual ~MP3Seeker() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(MP3Seeker);
+};
+
+} // namespace android
+
+#endif // MP3_SEEKER_H_
+
diff --git a/media/libstagefright/include/VBRISeeker.h b/media/libstagefright/include/VBRISeeker.h
new file mode 100644
index 0000000..d6bd19d
--- /dev/null
+++ b/media/libstagefright/include/VBRISeeker.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VBRI_SEEKER_H_
+
+#define VBRI_SEEKER_H_
+
+#include "include/MP3Seeker.h"
+
+#include <utils/Vector.h>
+
+namespace android {
+
+struct DataSource;
+
+struct VBRISeeker : public MP3Seeker {
+ static sp<VBRISeeker> CreateFromSource(
+ const sp<DataSource> &source, off_t post_id3_pos);
+
+ virtual bool getDuration(int64_t *durationUs);
+ virtual bool getOffsetForTime(int64_t *timeUs, off_t *pos);
+
+private:
+ off_t mBasePos;
+ int64_t mDurationUs;
+ Vector<uint32_t> mSegments;
+
+ VBRISeeker();
+
+ DISALLOW_EVIL_CONSTRUCTORS(VBRISeeker);
+};
+
+} // namespace android
+
+#endif // VBRI_SEEKER_H_
+
+
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/libstagefright/include/XINGSeeker.h
new file mode 100644
index 0000000..d4ff4e1
--- /dev/null
+++ b/media/libstagefright/include/XINGSeeker.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef XING_SEEKER_H_
+
+#define XING_SEEKER_H_
+
+#include "include/MP3Seeker.h"
+
+namespace android {
+
+struct DataSource;
+
+struct XINGSeeker : public MP3Seeker {
+ static sp<XINGSeeker> CreateFromSource(
+ const sp<DataSource> &source, off_t first_frame_pos);
+
+ virtual bool getDuration(int64_t *durationUs);
+ virtual bool getOffsetForTime(int64_t *timeUs, off_t *pos);
+
+private:
+ int64_t mFirstFramePos;
+ int64_t mDurationUs;
+ int32_t mSizeBytes;
+
+ // TOC entries in XING header. Skip the first one since it's always 0.
+ char mTableOfContents[99];
+
+ XINGSeeker();
+
+ DISALLOW_EVIL_CONSTRUCTORS(XINGSeeker);
+};
+
+} // namespace android
+
+#endif // XING_SEEKER_H_
+
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index 25d7697..bfac71b 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -78,18 +78,7 @@
typedef void *EGLNativeWindowType;
typedef void *EGLNativePixmapType;
-#elif defined(__unix__) && !defined(ANDROID)
-
-/* X11 (tentative) */
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-typedef Display *EGLNativeDisplayType;
-typedef Pixmap EGLNativePixmapType;
-typedef Window EGLNativeWindowType;
-
-
-#elif defined(ANDROID)
+#elif defined(__ANDROID__) || defined(ANDROID)
#include <android/native_window.h>
@@ -99,6 +88,16 @@
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
+#elif defined(__unix__)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
#else
#error "Platform not recognized"
#endif
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
new file mode 100644
index 0000000..50a8ac8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml
index 2f9e0d7..ac038a7 100644
--- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml
@@ -25,25 +25,29 @@
android:background="@drawable/sysbar_panel_recents_bg"
android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/recent_tasks_app_label"
+ android:textSize="22dip"
+ android:drawableLeft="@drawable/app_icon"
+ android:layout_margin="10dip"
+ />
+
<TextView android:id="@+id/recents_no_recents"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/recent_tasks_empty"
+ android:textSize="22dip"
android:gravity="center_horizontal|center_vertical"
- android:visibility="gone">
+ android:visibility="gone"
+ android:layout_margin="10dip">
</TextView>
- <HorizontalScrollView android:id="@+id/scroll_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout android:id="@+id/recents_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="right"
- android:orientation="horizontal"
- />
-
- </HorizontalScrollView>
+ <LinearLayout android:id="@+id/recents_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
</com.android.systemui.statusbar.tablet.RecentAppsPanel>
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent_item.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent_item.xml
new file mode 100644
index 0000000..b1997b8
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent_item.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ android:layout_margin="10dip">
+
+ <ImageView android:id="@+id/app_thumbnail"
+ android:layout_width="88dip"
+ android:layout_height="56dip"
+ android:layout_margin="10dip"
+ android:background="#80808080">
+ </ImageView>
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="10dip"
+ android:layout_marginBottom="10dip"
+ android:layout_marginRight="10dip">
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="23dip"
+ android:layout_height="23dip"
+ android:gravity="bottom"
+ android:layout_margin="5dip"
+ />
+
+ <TextView android:id="@+id/app_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="22dip"
+ />
+
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6384db5..a65de37 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -80,6 +80,9 @@
<!-- Recent Tasks dialog: message when there are no recent applications [CHAR LIMIT=NONE]-->
<string name="recent_tasks_empty">No recent applications.</string>
+ <!-- Recent apps label. Shown as title on recent apps panel -->
+ <string name="recent_tasks_app_label">Apps</string>
+
<!-- Rotation lock toast text: shown when rotation lock is turned off (and the screen will
auto-rotate based on the accelerometer). [CHAR LIMIT=NONE]-->
<string name="toast_rotation_free">Screen will rotate automatically.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index 6797958..1831eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -20,45 +20,75 @@
import java.util.List;
import android.app.ActivityManager;
-import android.bluetooth.BluetoothAdapter;
+import android.app.IThumbnailReceiver;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.wifi.WifiManager;
+import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnClickListener;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.HorizontalScrollView;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.systemui.R;
public class RecentAppsPanel extends LinearLayout implements StatusBarPanel, OnClickListener {
private static final String TAG = "RecentAppsPanel";
private static final boolean DEBUG = TabletStatusBarService.DEBUG;
- private static final int MAX_RECENT_TASKS = 20;
- private static final float ITEM_WIDTH = 75;
- private static final float ITEM_HEIGHT = 75;
+ private static final int DISPLAY_TASKS = 4; // number of recent tasks to display
+ private static final int MAX_TASKS = 2 * DISPLAY_TASKS; // give some slack for non-apps
+ private static final boolean DBG = true;
private TabletStatusBarService mBar;
private TextView mNoRecents;
private LinearLayout mRecentsContainer;
- private float mDensity;
- private HorizontalScrollView mScrollView;
+ private ArrayList<ActivityDescription> mActivityDescriptions;
+
+ static class ActivityDescription {
+ int id;
+ Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
+ Drawable icon; // application package icon
+ String label; // application package label
+ CharSequence description; // generated by Activity.onCreateDescription()
+ Intent intent; // launch intent for application
+ Matrix matrix; // arbitrary rotation matrix to correct orientation
+ int position; // position in list
+
+ public ActivityDescription(Bitmap _thumbnail,
+ Drawable _icon, String _label, String _desc, Intent _intent, int _id, int _pos)
+ {
+ thumbnail = _thumbnail;
+ icon = _icon;
+ label = _label;
+ description = _desc;
+ intent = _intent;
+ id = _id;
+ position = _pos;
+ }
+ };
+
+ private final IThumbnailReceiver mThumbnailReceiver = new IThumbnailReceiver.Stub() {
+
+ public void finished() throws RemoteException {
+ }
+
+ public void newThumbnail(final int id, final Bitmap bitmap, CharSequence description)
+ throws RemoteException {
+ ActivityDescription info = findActivityDescription(id);
+ if (info != null) {
+ info.thumbnail = bitmap;
+ info.description = description;
+ }
+ }
+ };
public boolean isInContentArea(int x, int y) {
final int l = getPaddingLeft();
@@ -78,7 +108,6 @@
public RecentAppsPanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mDensity = getResources().getDisplayMetrics().density;
}
@Override
@@ -86,8 +115,6 @@
super.onFinishInflate();
mNoRecents = (TextView) findViewById(R.id.recents_no_recents);
mRecentsContainer = (LinearLayout) findViewById(R.id.recents_container);
- mScrollView = (HorizontalScrollView) findViewById(R.id.scroll_view);
- mScrollView.setHorizontalFadingEdgeEnabled(true);
}
@Override
@@ -95,63 +122,124 @@
super.onVisibilityChanged(changedView, visibility);
Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
if (visibility == View.VISIBLE && changedView == this) {
- refreshIcons();
+ refreshApplicationList();
mRecentsContainer.setScrollbarFadingEnabled(true);
mRecentsContainer.scrollTo(0, 0);
}
}
- private void refreshIcons() {
- mRecentsContainer.removeAllViews();
- final Context context = getContext();
- final PackageManager pm = context.getPackageManager();
+ private ArrayList<ActivityDescription> getRecentTasks() {
+ ArrayList<ActivityDescription> activityDescriptions = new ArrayList<ActivityDescription>();
+ final PackageManager pm = mContext.getPackageManager();
final ActivityManager am = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ mContext.getSystemService(Context.ACTIVITY_SERVICE);
- ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
+ final List<ActivityManager.RecentTaskInfo> recentTasks =
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+
+ ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+ .resolveActivityInfo(pm, 0);
int numTasks = recentTasks.size();
- final int width = (int) (mDensity * ITEM_WIDTH + 0.5f);
- final int height = (int) (mDensity * ITEM_HEIGHT + 0.5f);
- ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(width, height);
- for (int i = 0; i < numTasks; ++i) {
- final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
+ for (int i = 0, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
+ final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
- Intent intent = new Intent(info.baseIntent);
- if (info.origActivity != null) {
- intent.setComponent(info.origActivity);
+ Intent intent = new Intent(recentInfo.baseIntent);
+ if (recentInfo.origActivity != null) {
+ intent.setComponent(recentInfo.origActivity);
}
- // Exclude home activity.
+ // Skip the current home activity.
if (homeInfo != null
&& homeInfo.packageName.equals(intent.getComponent().getPackageName())
&& homeInfo.name.equals(intent.getComponent().getClassName())) {
- continue;
+ continue;
}
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- final String title = activityInfo.loadLabel(pm).toString();
- Drawable icon = activityInfo.loadIcon(pm);
-
+ final ActivityInfo info = resolveInfo.activityInfo;
+ final String title = info.loadLabel(pm).toString();
+ Drawable icon = info.loadIcon(pm);
+ int id = recentTasks.get(i).id;
if (title != null && title.length() > 0 && icon != null) {
- ImageView imageView = new ImageView(mContext);
- imageView.setScaleType(ImageView.ScaleType.FIT_XY);
- imageView.setLayoutParams(layoutParams);
- imageView.setOnClickListener(this);
- imageView.setTag(intent);
- imageView.setImageDrawable(icon);
- mRecentsContainer.addView(imageView);
+ Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
+ ActivityDescription item = new ActivityDescription(
+ null, icon, title, null, intent, id, index);
+ activityDescriptions.add(item);
+ ++index;
+ } else {
+ if (DBG) Log.v(TAG, "SKIPPING item " + id);
}
}
}
+ return activityDescriptions;
+ }
+
+ ActivityDescription findActivityDescription(int id)
+ {
+ ActivityDescription desc = null;
+ for (int i = 0; i < mActivityDescriptions.size(); i++) {
+ ActivityDescription item = mActivityDescriptions.get(i);
+ if (item != null && item.id == id) {
+ desc = item;
+ break;
+ }
+ }
+ return desc;
+ }
+
+ private void getThumbnails(ArrayList<ActivityDescription> tasks) {
+ ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ List<RunningTaskInfo> runningTasks = am.getRunningTasks(MAX_TASKS, 0, mThumbnailReceiver);
+ for (RunningTaskInfo r : runningTasks) {
+ // Find the activity description associted with the given id
+ ActivityDescription desc = findActivityDescription(r.id);
+ if (desc != null) {
+ if (r.thumbnail != null) {
+ desc.thumbnail = r.thumbnail;
+ desc.description = r.description;
+ } else {
+ if (DBG) Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
+ }
+ } else {
+ if (DBG) Log.v(TAG, "Couldn't find ActivityDesc for id=" + r.id);
+ }
+ }
+ }
+
+ private void refreshApplicationList() {
+ mActivityDescriptions = getRecentTasks();
+ getThumbnails(mActivityDescriptions);
+ updateUiElements();
+ }
+
+ private void updateUiElements() {
+ mRecentsContainer.removeAllViews();
+ final int first = 0;
+ final int last = Math.min(mActivityDescriptions.size(), DISPLAY_TASKS) - 1;
+ for (int i = last; i >= first; i--) {
+ ActivityDescription activityDescription = mActivityDescriptions.get(i);
+ View view = View.inflate(mContext, R.layout.sysbar_panel_recent_item, null);
+ ImageView appThumbnail = (ImageView) view.findViewById(R.id.app_thumbnail);
+ ImageView appIcon = (ImageView) view.findViewById(R.id.app_icon);
+ TextView appDescription = (TextView) view.findViewById(R.id.app_label);
+ if (activityDescription.thumbnail != null) {
+ Log.v(TAG, "thumbnail res = " + activityDescription.thumbnail.getWidth()
+ + "x" + activityDescription.thumbnail.getHeight());
+ } else {
+ Log.v(TAG, "thumbnail for " + activityDescription.label + " was null");
+ }
+ appThumbnail.setImageBitmap(activityDescription.thumbnail);
+ appIcon.setImageDrawable(activityDescription.icon);
+ appDescription.setText(activityDescription.label);
+ view.setOnClickListener(this);
+ view.setTag(activityDescription.intent);
+ Log.v(TAG, "Adding task: " + activityDescription.label);
+ mRecentsContainer.addView(view);
+ }
int views = mRecentsContainer.getChildCount();
mNoRecents.setVisibility(views == 0 ? View.VISIBLE : View.GONE);
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 86d4c9f..edea2c5 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1749,6 +1749,7 @@
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index da5f204..d035eb5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -116,7 +116,6 @@
static final long TIME_TO_RECONNECT = 10*1000;
private static final int NOT_A_SUBTYPE_ID = -1;
- private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
// If IME doesn't support the system locale, the default subtype will be the first defined one.
private static final int DEFAULT_SUBTYPE_ID = 0;
@@ -367,7 +366,9 @@
if (!doit) {
return true;
}
- resetSelectedInputMethodAndSubtypeLocked("");
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, "");
+ resetSelectedInputMethodSubtype();
chooseNewDefaultIMELocked();
return true;
}
@@ -424,7 +425,9 @@
changed = true;
curIm = null;
Slog.i(TAG, "Unsetting current input method");
- resetSelectedInputMethodAndSubtypeLocked("");
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, "");
+ resetSelectedInputMethodSubtype();
}
}
}
@@ -507,7 +510,9 @@
Slog.i(TAG, "No default found, using " + defIm.getId());
}
if (defIm != null) {
- setSelectSubtypeLocked(defIm, NOT_A_SUBTYPE_ID);
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId());
+ putSelectedInputMethodSubtype(defIm, NOT_A_SUBTYPE_ID);
}
}
@@ -989,7 +994,7 @@
synchronized (mMethodMap) {
if (mCurMethod != null) {
try {
- setSelectSubtypeLocked(info, subtypeId);
+ putSelectedInputMethodSubtype(info, subtypeId);
if (mInputShown) {
// If mInputShown is false, there is no IME button on the
// system bar.
@@ -1009,13 +1014,13 @@
final long ident = Binder.clearCallingIdentity();
try {
+ mCurMethodId = id;
// Set a subtype to this input method.
// subtypeId the name of a subtype which will be set.
- setSelectedInputMethodAndSubtypeLocked(info, subtypeId);
- // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
- // because mCurMethodId is stored as a history in
- // setSelectedInputMethodAndSubtypeLocked().
- mCurMethodId = id;
+ putSelectedInputMethodSubtype(info, subtypeId);
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, id);
if (ActivityManagerNative.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -1482,7 +1487,9 @@
}
}
InputMethodInfo imi = enabled.get(i);
- resetSelectedInputMethodAndSubtypeLocked(imi.getId());
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, imi.getId());
+ putSelectedInputMethodSubtype(imi, NOT_A_SUBTYPE_ID);
return true;
}
@@ -1786,8 +1793,11 @@
String selId = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
if (id.equals(selId)) {
- resetSelectedInputMethodAndSubtypeLocked(enabledInputMethodsList.size() > 0
- ? enabledInputMethodsList.get(0).first : "");
+ Settings.Secure.putString(
+ mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
+ enabledInputMethodsList.size() > 0
+ ? enabledInputMethodsList.get(0).first : "");
+ resetSelectedInputMethodSubtype();
}
// Previous state was enabled.
return true;
@@ -1799,54 +1809,22 @@
}
}
- private void saveCurrentInputMethodAndSubtypeToHistory() {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
- if (mCurrentSubtype != null) {
- subtypeId = String.valueOf(mCurrentSubtype.hashCode());
- }
- mSettings.addSubtypeToHistory(mCurMethodId, subtypeId);
+ private void resetSelectedInputMethodSubtype() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID);
}
- private void setSelectSubtypeLocked(InputMethodInfo imi, int subtypeId) {
- saveCurrentInputMethodAndSubtypeToHistory();
- if (imi == null || subtypeId < 0) {
- mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
- mCurrentSubtype = null;
+ private void putSelectedInputMethodSubtype(InputMethodInfo imi, int subtypeId) {
+ final ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
+ if (subtypeId >= 0 && subtypeId < subtypes.size()) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
+ subtypes.get(subtypeId).hashCode());
+ mCurrentSubtype = subtypes.get(subtypeId);
} else {
- final ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
- if (subtypeId < subtypes.size()) {
- mSettings.putSelectedSubtype(subtypes.get(subtypeId).hashCode());
- mCurrentSubtype = subtypes.get(subtypeId);
- } else {
- mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
- mCurrentSubtype = null;
- }
+ resetSelectedInputMethodSubtype();
+ mCurrentSubtype = null;
}
-
- }
-
- private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId) {
- setSelectSubtypeLocked(imi, subtypeId);
- mSettings.putSelectedInputMethod(imi.getId());
- }
-
- private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
- InputMethodInfo imi = mMethodMap.get(newDefaultIme);
- int lastSubtypeId = NOT_A_SUBTYPE_ID;
- // newDefaultIme is empty when there is no candidate for the selected IME.
- if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
- String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
- if (subtypeHashCode != null) {
- try {
- lastSubtypeId = getSubtypeIdFromHashCode(
- imi, Integer.valueOf(subtypeHashCode));
- } catch (NumberFormatException e) {
- Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
- }
- }
- }
- setSelectSubtypeLocked(imi, lastSubtypeId);
- mSettings.putSelectedInputMethod(newDefaultIme);
}
private int getSelectedInputMethodSubtypeId(String id) {
@@ -1854,6 +1832,7 @@
if (imi == null) {
return NOT_A_SUBTYPE_ID;
}
+ ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
int subtypeId;
try {
subtypeId = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -1861,14 +1840,9 @@
} catch (SettingNotFoundException e) {
return NOT_A_SUBTYPE_ID;
}
- return getSubtypeIdFromHashCode(imi, subtypeId);
- }
-
- private int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
- ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
for (int i = 0; i < subtypes.size(); ++i) {
InputMethodSubtype ims = subtypes.get(i);
- if (subtypeHashCode == ims.hashCode()) {
+ if (subtypeId == ims.hashCode()) {
return i;
}
}
@@ -1948,10 +1922,10 @@
// example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
private static final char INPUT_METHOD_SEPARATER = ':';
private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
- private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
+ private final TextUtils.SimpleStringSplitter mStringColonSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
- private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
+ private final TextUtils.SimpleStringSplitter mStringSemiColonSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
private final ContentResolver mResolver;
@@ -2014,16 +1988,16 @@
if (TextUtils.isEmpty(enabledInputMethodsStr)) {
return imsList;
}
- mInputMethodSplitter.setString(enabledInputMethodsStr);
- while (mInputMethodSplitter.hasNext()) {
- String nextImsStr = mInputMethodSplitter.next();
- mSubtypeSplitter.setString(nextImsStr);
- if (mSubtypeSplitter.hasNext()) {
+ mStringColonSplitter.setString(enabledInputMethodsStr);
+ while (mStringColonSplitter.hasNext()) {
+ String nextImsStr = mStringColonSplitter.next();
+ mStringSemiColonSplitter.setString(nextImsStr);
+ if (mStringSemiColonSplitter.hasNext()) {
ArrayList<String> subtypeHashes = new ArrayList<String>();
// The first element is ime id.
- String imeId = mSubtypeSplitter.next();
- while (mSubtypeSplitter.hasNext()) {
- subtypeHashes.add(mSubtypeSplitter.next());
+ String imeId = mStringSemiColonSplitter.next();
+ while (mStringSemiColonSplitter.hasNext()) {
+ subtypeHashes.add(mStringSemiColonSplitter.next());
}
imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
}
@@ -2109,161 +2083,8 @@
private String getEnabledInputMethodsStr() {
mEnabledInputMethodsStrCache = Settings.Secure.getString(
mResolver, Settings.Secure.ENABLED_INPUT_METHODS);
- if (DEBUG) {
- Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache);
- }
return mEnabledInputMethodsStrCache;
}
-
- private void saveSubtypeHistory(
- List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
- StringBuilder builder = new StringBuilder();
- boolean isImeAdded = false;
- if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
- builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
- newSubtypeId);
- isImeAdded = true;
- }
- for (Pair<String, String> ime: savedImes) {
- String imeId = ime.first;
- String subtypeId = ime.second;
- if (TextUtils.isEmpty(subtypeId)) {
- subtypeId = NOT_A_SUBTYPE_ID_STR;
- }
- if (isImeAdded) {
- builder.append(INPUT_METHOD_SEPARATER);
- } else {
- isImeAdded = true;
- }
- builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
- subtypeId);
- }
- // Remove the last INPUT_METHOD_SEPARATER
- putSubtypeHistoryStr(builder.toString());
- }
-
- public void addSubtypeToHistory(String imeId, String subtypeId) {
- List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
- for (Pair<String, String> ime: subtypeHistory) {
- if (ime.first.equals(imeId)) {
- if (DEBUG) {
- Slog.v(TAG, "Subtype found in the history: " + imeId
- + ime.second);
- }
- // We should break here
- subtypeHistory.remove(ime);
- break;
- }
- }
- saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
- }
-
- private void putSubtypeHistoryStr(String str) {
- if (DEBUG) {
- Slog.d(TAG, "putSubtypeHistoryStr: " + str);
- }
- Settings.Secure.putString(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
- }
-
- public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
- // Gets the first one from the history
- return getLastSubtypeForInputMethodLockedInternal(null);
- }
-
- public String getLastSubtypeForInputMethodLocked(String imeId) {
- Pair<String, String> ime = getLastSubtypeForInputMethodLockedInternal(imeId);
- if (ime != null) {
- return ime.second;
- } else {
- return null;
- }
- }
-
- private Pair<String, String> getLastSubtypeForInputMethodLockedInternal(String imeId) {
- List<Pair<String, ArrayList<String>>> enabledImes =
- getEnabledInputMethodsAndSubtypeListLocked();
- List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
- for (Pair<String, String> imeAndSubtype: subtypeHistory) {
- final String imeInTheHistory = imeAndSubtype.first;
- // If imeId is empty, returns the first IME and subtype in the history
- if (TextUtils.isEmpty(imeId) || imeInTheHistory.equals(imeId)) {
- final String subtypeInTheHistory = imeAndSubtype.second;
- final String subtypeHashCode = getEnabledSubtypeForInputMethodAndSubtypeLocked(
- enabledImes, imeInTheHistory, subtypeInTheHistory);
- if (!TextUtils.isEmpty(subtypeHashCode)) {
- if (DEBUG) {
- Slog.d(TAG, "Enabled subtype found in the history:" + subtypeHashCode);
- }
- return new Pair<String, String>(imeInTheHistory, subtypeHashCode);
- }
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "No enabled IME found in the history");
- }
- return null;
- }
-
- private String getEnabledSubtypeForInputMethodAndSubtypeLocked(List<Pair<String,
- ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
- for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
- if (enabledIme.first.equals(imeId)) {
- for (String s: enabledIme.second) {
- if (s.equals(subtypeHashCode)) {
- // If both imeId and subtypeId are enabled, return subtypeId.
- return s;
- }
- }
- // If imeId was enabled but subtypeId was disabled.
- return NOT_A_SUBTYPE_ID_STR;
- }
- }
- // If both imeId and subtypeId are disabled, return null
- return null;
- }
-
- private List<Pair<String, String>> loadInputMethodAndSubtypeHistoryLocked() {
- ArrayList<Pair<String, String>> imsList = new ArrayList<Pair<String, String>>();
- final String subtypeHistoryStr = getSubtypeHistoryStr();
- if (TextUtils.isEmpty(subtypeHistoryStr)) {
- return imsList;
- }
- mInputMethodSplitter.setString(subtypeHistoryStr);
- while (mInputMethodSplitter.hasNext()) {
- String nextImsStr = mInputMethodSplitter.next();
- mSubtypeSplitter.setString(nextImsStr);
- if (mSubtypeSplitter.hasNext()) {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
- // The first element is ime id.
- String imeId = mSubtypeSplitter.next();
- while (mSubtypeSplitter.hasNext()) {
- subtypeId = mSubtypeSplitter.next();
- break;
- }
- imsList.add(new Pair<String, String>(imeId, subtypeId));
- }
- }
- return imsList;
- }
-
- private String getSubtypeHistoryStr() {
- if (DEBUG) {
- Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getString(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY));
- }
- return Settings.Secure.getString(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
- }
-
- public void putSelectedInputMethod(String imeId) {
- Settings.Secure.putString(mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId);
- }
-
- public void putSelectedSubtype(int subtypeId) {
- Settings.Secure.putInt(
- mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
- }
}
// ----------------------------------------------------------------------
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 1c92da9..fb87d69 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -23,8 +23,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -100,7 +98,6 @@
import android.view.Display;
import android.view.DragEvent;
import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
@@ -128,7 +125,6 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
-import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
@@ -464,6 +460,11 @@
// If non-null, we are in the middle of animating from one wallpaper target
// to another, and this is the higher one in Z-order.
WindowState mUpperWallpaperTarget = null;
+ // Window currently running an animation that has requested it be detached
+ // from the wallpaper. This means we need to ensure the wallpaper is
+ // visible behind it in case it animates in a way that would allow it to be
+ // seen.
+ WindowState mWindowDetachedWallpaper = null;
int mWallpaperAnimLayerAdjustment;
float mLastWallpaperX = -1;
float mLastWallpaperY = -1;
@@ -1709,6 +1710,7 @@
int foundI = 0;
WindowState topCurW = null;
int topCurI = 0;
+ int windowDetachedI = -1;
int i = N;
while (i > 0) {
i--;
@@ -1721,13 +1723,12 @@
continue;
}
topCurW = null;
- if (w.mAppToken != null) {
+ if (w != mWindowDetachedWallpaper && w.mAppToken != null) {
// If this window's app token is hidden and not animating,
// it is of no interest to us.
if (w.mAppToken.hidden && w.mAppToken.animation == null) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
- "Skipping hidden or animating token: " + w);
- topCurW = null;
+ "Skipping not hidden or animating token: " + w);
continue;
}
}
@@ -1752,9 +1753,18 @@
continue;
}
break;
+ } else if (w == mWindowDetachedWallpaper) {
+ windowDetachedI = i;
}
}
+ if (foundW == null && windowDetachedI >= 0) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Found animating detached wallpaper activity: #" + i + "=" + w);
+ foundW = w;
+ foundI = windowDetachedI;
+ }
+
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
// If we are currently waiting for an app transition, and either
// the current target or the next target are involved with it,
@@ -8961,6 +8971,12 @@
int curLayer = 0;
int i;
+ if (DEBUG_LAYERS) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Log.v(TAG, "Assigning layers", here);
+ }
+
for (i=0; i<N; i++) {
WindowState w = mWindows.get(i);
if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
@@ -9297,6 +9313,7 @@
boolean tokenMayBeDrawn = false;
boolean wallpaperMayChange = false;
boolean forceHiding = false;
+ WindowState windowDetachedWallpaper = null;
mPolicy.beginAnimationLw(dw, dh);
@@ -9318,19 +9335,35 @@
}
}
- boolean wasAnimating = w.mAnimating;
- if (w.stepAnimationLocked(currentTime, dw, dh)) {
+ final boolean wasAnimating = w.mAnimating;
+ final boolean nowAnimating = w.stepAnimationLocked(currentTime, dw, dh);
+
+ // If this window is animating, make a note that we have
+ // an animating window and take care of a request to run
+ // a detached wallpaper animation.
+ if (nowAnimating) {
+ if (w.mAnimation != null && w.mAnimation.getDetachWallpaper()) {
+ windowDetachedWallpaper = w;
+ }
animating = true;
- //w.dump(" ");
}
+
+ // If this window's app token is running a detached wallpaper
+ // animation, make a note so we can ensure the wallpaper is
+ // displayed behind it.
+ if (w.mAppToken != null && w.mAppToken.animation != null
+ && w.mAppToken.animation.getDetachWallpaper()) {
+ windowDetachedWallpaper = w;
+ }
+
if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
wallpaperMayChange = true;
}
if (mPolicy.doesForceHide(w, attrs)) {
- if (!wasAnimating && animating) {
+ if (!wasAnimating && nowAnimating) {
if (DEBUG_VISIBILITY) Slog.v(TAG,
- "Animation done that could impact force hide: "
+ "Animation started that could impact force hide: "
+ w);
wallpaperForceHidingChanged = true;
mFocusMayChange = true;
@@ -9754,6 +9787,14 @@
}
}
+ if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Detached wallpaper changed from " + mWindowDetachedWallpaper
+ + windowDetachedWallpaper);
+ mWindowDetachedWallpaper = windowDetachedWallpaper;
+ wallpaperMayChange = true;
+ }
+
if (wallpaperMayChange) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper may change! Adjusting");
@@ -11085,6 +11126,9 @@
pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
}
+ if (mWindowDetachedWallpaper != null) {
+ pw.print(" mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
+ }
pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration);
pw.print(" mInTouchMode="); pw.print(mInTouchMode);
pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
index ebdf9c2..6c33a21 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java
@@ -240,13 +240,18 @@
/**
* Checks if the file is a test.
- * Currently we run .html and .xhtml tests.
+ * Currently we run .html, .xhtml and .php tests.
+ *
+ * @warning You MUST also call isTestDir() on the parent directory before
+ * assuming that a file is a test.
*
* @param testName
* @return if the file is a test
*/
public static boolean isTestFile(String testName) {
- return testName.endsWith(".html") || testName.endsWith(".xhtml");
+ return testName.endsWith(".html")
+ || testName.endsWith(".xhtml")
+ || testName.endsWith(".php");
}
/**