Merge "Turn off media time adjustment by default" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 524d296..8c164c1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -63056,146 +63056,6 @@
>
</field>
</class>
-<class name="BitmapRegionDecoder"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="decodeRegion"
- return="android.graphics.Bitmap"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="rect" type="android.graphics.Rect">
-</parameter>
-<parameter name="options" type="android.graphics.BitmapFactory.Options">
-</parameter>
-</method>
-<method name="getHeight"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getWidth"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isRecycled"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="data" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fd" type="java.io.FileDescriptor">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="is" type="java.io.InputStream">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="pathName" type="java.lang.String">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="recycle"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
<class name="BitmapShader"
extends="android.graphics.Shader"
abstract="false"
@@ -79357,7 +79217,7 @@
type="float"
transient="false"
volatile="false"
- value="0.0010f"
+ value="0.001f"
static="true"
final="true"
deprecated="not deprecated"
@@ -128720,7 +128580,7 @@
visibility="public"
>
<method name="allowThreadDiskReads"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
abstract="false"
native="false"
synchronized="false"
@@ -128731,7 +128591,7 @@
>
</method>
<method name="allowThreadDiskWrites"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
abstract="false"
native="false"
synchronized="false"
@@ -128742,7 +128602,18 @@
>
</method>
<method name="getThreadPolicy"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVmPolicy"
+ return="android.os.StrictMode.VmPolicy"
abstract="false"
native="false"
synchronized="false"
@@ -128762,86 +128633,313 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="policyMask" type="int">
+<parameter name="policy" type="android.os.StrictMode.ThreadPolicy">
</parameter>
</method>
-<field name="DISALLOW_DISK_READ"
- type="int"
+<method name="setVmPolicy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policy" type="android.os.StrictMode.VmPolicy">
+</parameter>
+</method>
+</class>
+<class name="StrictMode.ThreadPolicy"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="LAX"
+ type="android.os.StrictMode.ThreadPolicy"
transient="false"
volatile="false"
- value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="DISALLOW_DISK_WRITE"
- type="int"
+</class>
+<class name="StrictMode.ThreadPolicy.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StrictMode.ThreadPolicy.Builder"
+ type="android.os.StrictMode.ThreadPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="StrictMode.ThreadPolicy.Builder"
+ type="android.os.StrictMode.ThreadPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policy" type="android.os.StrictMode.ThreadPolicy">
+</parameter>
+</constructor>
+<method name="build"
+ return="android.os.StrictMode.ThreadPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectAll"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectDiskReads"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectDiskWrites"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectNetwork"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDeath"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDialog"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDropBox"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyLog"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitAll"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitDiskReads"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitDiskWrites"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitNetwork"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="StrictMode.VmPolicy"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="LAX"
+ type="android.os.StrictMode.VmPolicy"
transient="false"
volatile="false"
- value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="DISALLOW_NETWORK"
- type="int"
- transient="false"
- volatile="false"
- value="4"
+</class>
+<class name="StrictMode.VmPolicy.Builder"
+ extends="java.lang.Object"
+ abstract="false"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
-</field>
-<field name="PENALTY_DEATH"
- type="int"
- transient="false"
- volatile="false"
- value="64"
- static="true"
- final="true"
+<constructor name="StrictMode.VmPolicy.Builder"
+ type="android.os.StrictMode.VmPolicy.Builder"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
-</field>
-<field name="PENALTY_DIALOG"
- type="int"
- transient="false"
- volatile="false"
- value="32"
- static="true"
- final="true"
+</constructor>
+<method name="build"
+ return="android.os.StrictMode.VmPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
-</field>
-<field name="PENALTY_DROPBOX"
- type="int"
- transient="false"
- volatile="false"
- value="128"
- static="true"
- final="true"
+</method>
+<method name="detectAll"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
-</field>
-<field name="PENALTY_LOG"
- type="int"
- transient="false"
- volatile="false"
- value="16"
- static="true"
- final="true"
+</method>
+<method name="detectLeakedSqlLiteObjects"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
-</field>
+</method>
+<method name="penaltyDeath"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDropBox"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyLog"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<class name="SystemClock"
extends="java.lang.Object"
@@ -225068,7 +225166,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
@@ -232827,7 +232925,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="n" type="long">
+<parameter name="byteCount" type="long">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 39b3a20..37c8ad0 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -34,7 +34,6 @@
private String[] mArgs;
private int mNextArg;
- private String mCurArgData;
public static void main(String[] args) {
try {
@@ -274,6 +273,10 @@
}
private void printRestoreSets(RestoreSet[] sets) {
+ if (sets == null || sets.length == 0) {
+ System.out.println("No restore sets");
+ return;
+ }
for (RestoreSet s : sets) {
System.out.println(" " + Long.toHexString(s.token) + " : " + s.name);
}
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 971a177..afa64f8 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -143,15 +143,20 @@
send(the_socket, message, length, 0);
}
-/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to
- * compute their checksums. To make the files portable, the length is stored in
- * network order. Note that the first four bytes are reserved for future use and
- * are always set to zero in this implementation. */
+/* Here is the file format. There are two parts in blob.value, the secret and
+ * the description. The secret is stored in ciphertext, and its original size
+ * can be found in blob.length. The description is stored after the secret in
+ * plaintext, and its size is specified in blob.info. The total size of the two
+ * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
+ * file are reserved for future use and are always set to zero. Fields other
+ * than blob.info, blob.length, and blob.value are modified by encrypt_blob()
+ * and decrypt_blob(). Thus they should not be accessed from outside. */
static int the_entropy = -1;
static struct __attribute__((packed)) {
- uint32_t reserved;
+ uint8_t reserved[3];
+ uint8_t info;
uint8_t vector[AES_BLOCK_SIZE];
uint8_t encrypted[0];
uint8_t digest[MD5_DIGEST_LENGTH];
@@ -170,9 +175,13 @@
return SYSTEM_ERROR;
}
- length = blob.length + blob.value - blob.encrypted;
+ length = blob.length + (blob.value - blob.encrypted);
length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
+ if (blob.info != 0) {
+ memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info);
+ }
+
blob.length = htonl(blob.length);
MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest);
@@ -180,8 +189,8 @@
AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
AES_ENCRYPT);
- blob.reserved = 0;
- length += blob.encrypted - (uint8_t *)&blob;
+ memset(blob.reserved, 0, sizeof(blob.reserved));
+ length += (blob.encrypted - (uint8_t *)&blob) + blob.info;
fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
length -= write(fd, &blob, length);
@@ -200,7 +209,7 @@
length = read(fd, &blob, sizeof(blob));
close(fd);
- length -= blob.encrypted - (uint8_t *)&blob;
+ length -= (blob.encrypted - (uint8_t *)&blob) + blob.info;
if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
return VALUE_CORRUPTED;
}
@@ -215,8 +224,13 @@
length -= blob.value - blob.digested;
blob.length = ntohl(blob.length);
- return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED :
- NO_ERROR;
+ if (blob.length < 0 || blob.length > length) {
+ return VALUE_CORRUPTED;
+ }
+ if (blob.info != 0) {
+ memmove(&blob.value[blob.length], &blob.value[length], blob.info);
+ }
+ return NO_ERROR;
}
/* Here are the actions. Each of them is a function without arguments. All
@@ -266,6 +280,7 @@
char name[NAME_MAX];
int n = sprintf(name, "%u_", uid);
encode_key(&name[n], params[0].value, params[0].length);
+ blob.info = 0;
blob.length = params[1].length;
memcpy(blob.value, params[1].value, params[1].length);
return encrypt_blob(name, &encryption_key);
@@ -336,56 +351,88 @@
#define MASTER_KEY_FILE ".masterkey"
#define MASTER_KEY_SIZE 16
+#define SALT_SIZE 16
-static void generate_key(uint8_t *key, uint8_t *password, int length)
+static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt)
{
- PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
- sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+ if (salt) {
+ PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE,
+ 8192, MASTER_KEY_SIZE, key);
+ } else {
+ PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
+ sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+ }
}
+/* Here is the history. To improve the security, the parameters to generate the
+ * master key has been changed. To make a seamless transition, we update the
+ * file using the same password when the user unlock it for the first time. If
+ * any thing goes wrong during the transition, the new file will not overwrite
+ * the old one. This avoids permanent damages of the existing data. */
+
static int8_t password()
{
uint8_t key[MASTER_KEY_SIZE];
AES_KEY aes_key;
- int n;
+ int8_t response = SYSTEM_ERROR;
if (state == UNINITIALIZED) {
- blob.length = MASTER_KEY_SIZE;
if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
return SYSTEM_ERROR;
}
} else {
- generate_key(key, params[0].value, params[0].length);
+ int fd = open(MASTER_KEY_FILE, O_RDONLY);
+ uint8_t *salt = NULL;
+ if (fd != -1) {
+ int length = read(fd, &blob, sizeof(blob));
+ close(fd);
+ if (length > SALT_SIZE && blob.info == SALT_SIZE) {
+ salt = (uint8_t *)&blob + length - SALT_SIZE;
+ }
+ }
+
+ set_key(key, params[0].value, params[0].length, salt);
AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
- n = decrypt_blob(MASTER_KEY_FILE, &aes_key);
- if (n == SYSTEM_ERROR) {
+ response = decrypt_blob(MASTER_KEY_FILE, &aes_key);
+ if (response == SYSTEM_ERROR) {
return SYSTEM_ERROR;
}
- if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
+ if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
if (retry <= 0) {
reset();
return UNINITIALIZED;
}
return WRONG_PASSWORD + --retry;
}
+
+ if (!salt && params[1].length == -1) {
+ params[1] = params[0];
+ }
}
if (params[1].length == -1) {
memcpy(key, blob.value, MASTER_KEY_SIZE);
} else {
- generate_key(key, params[1].value, params[1].length);
+ uint8_t *salt = &blob.value[MASTER_KEY_SIZE];
+ if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) {
+ return SYSTEM_ERROR;
+ }
+
+ set_key(key, params[1].value, params[1].length, salt);
AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
memcpy(key, blob.value, MASTER_KEY_SIZE);
- n = encrypt_blob(MASTER_KEY_FILE, &aes_key);
+ blob.info = SALT_SIZE;
+ blob.length = MASTER_KEY_SIZE;
+ response = encrypt_blob(MASTER_KEY_FILE, &aes_key);
}
- if (n == NO_ERROR) {
+ if (response == NO_ERROR) {
AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
state = NO_ERROR;
retry = MAX_RETRY;
}
- return n;
+ return response;
}
static int8_t lock()
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 9d559d4..c476b8f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -47,6 +47,10 @@
* Instances of this class should be obtained through
* {@link android.content.Context#getSystemService(String)} by passing
* {@link android.content.Context#DOWNLOAD_SERVICE}.
+ *
+ * Apps that request downloads through this API should register a broadcast receiver for
+ * {@link #ACTION_NOTIFICATION_CLICKED} to appropriately handle when the user clicks on a running
+ * download in a notification or from the downloads UI.
*/
public class DownloadManager {
/**
@@ -239,8 +243,8 @@
public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
/**
- * Broadcast intent action sent by the download manager when a running download notification is
- * clicked.
+ * Broadcast intent action sent by the download manager when the user clicks on a running
+ * download, either from a system notification or from the downloads UI.
*/
public final static String ACTION_NOTIFICATION_CLICKED =
"android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
@@ -413,7 +417,9 @@
}
/**
- * Set the title of this download, to be displayed in notifications (if enabled)
+ * Set the title of this download, to be displayed in notifications (if enabled). If no
+ * title is given, a default one will be assigned based on the download filename, once the
+ * download starts.
* @return this object
*/
public Request setTitle(CharSequence title) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index cb6b708..7346561 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -27,8 +27,6 @@
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Environment;
-import android.os.StatFs;
import android.util.AndroidException;
import android.util.DisplayMetrics;
@@ -1388,11 +1386,18 @@
* {@link Intent#resolveActivity} finds an activity if a class has not
* been explicitly specified.
*
+ * <p><em>Note: if using an implicit Intent (without an explicit ComponentName
+ * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
+ * only flag. You need to do so to resolve the activity in the same way
+ * that {@link android.content.Context#startActivity(Intent)} and
+ * {@link android.content.Intent#resolveActivity(PackageManager)
+ * Intent.resolveActivity(PackageManager)} do.</p>
+ *
* @param intent An intent containing all of the desired specification
* (action, data, type, category, and/or component).
* @param flags Additional option flags. The most important is
- * MATCH_DEFAULT_ONLY, to limit the resolution to only
- * those activities that support the CATEGORY_DEFAULT.
+ * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+ * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
*
* @return Returns a ResolveInfo containing the final activity intent that
* was determined to be the best action. Returns null if no
@@ -1411,13 +1416,13 @@
*
* @param intent The desired intent as per resolveActivity().
* @param flags Additional option flags. The most important is
- * MATCH_DEFAULT_ONLY, to limit the resolution to only
- * those activities that support the CATEGORY_DEFAULT.
+ * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+ * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
*
- * @return A List<ResolveInfo> containing one entry for each matching
+ * @return A List<ResolveInfo> containing one entry for each matching
* Activity. These are ordered from best to worst match -- that
* is, the first item in the list is what is returned by
- * resolveActivity(). If there are no matching activities, an empty
+ * {@link #resolveActivity}. If there are no matching activities, an empty
* list is returned.
*
* @see #MATCH_DEFAULT_ONLY
@@ -1442,10 +1447,10 @@
* first specific results. Can be null.
* @param intent The desired intent as per resolveActivity().
* @param flags Additional option flags. The most important is
- * MATCH_DEFAULT_ONLY, to limit the resolution to only
- * those activities that support the CATEGORY_DEFAULT.
+ * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+ * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
*
- * @return A List<ResolveInfo> containing one entry for each matching
+ * @return A List<ResolveInfo> containing one entry for each matching
* Activity. These are ordered first by all of the intents resolved
* in <var>specifics</var> and then any additional activities that
* can handle <var>intent</var> but did not get included by one of
@@ -1463,11 +1468,9 @@
* Retrieve all receivers that can handle a broadcast of the given intent.
*
* @param intent The desired intent as per resolveActivity().
- * @param flags Additional option flags. The most important is
- * MATCH_DEFAULT_ONLY, to limit the resolution to only
- * those activities that support the CATEGORY_DEFAULT.
+ * @param flags Additional option flags.
*
- * @return A List<ResolveInfo> containing one entry for each matching
+ * @return A List<ResolveInfo> containing one entry for each matching
* Receiver. These are ordered from first to last in priority. If
* there are no matching receivers, an empty list is returned.
*
@@ -1500,7 +1503,7 @@
* @param intent The desired intent as per resolveService().
* @param flags Additional option flags.
*
- * @return A List<ResolveInfo> containing one entry for each matching
+ * @return A List<ResolveInfo> containing one entry for each matching
* ServiceInfo. These are ordered from best to worst match -- that
* is, the first item in the list is what is returned by
* resolveService(). If there are no matching services, an empty
@@ -1537,7 +1540,7 @@
* uid owning the requested content providers.
* @param flags Additional option flags. Currently should always be 0.
*
- * @return A List<ContentProviderInfo> containing one entry for each
+ * @return A List<ContentProviderInfo> containing one entry for each
* content provider either patching <var>processName</var> or, if
* <var>processName</var> is null, all known content providers.
* <em>If there are no matching providers, null is returned.</em>
@@ -1573,7 +1576,7 @@
* returned.
* @param flags Additional option flags. Currently should always be 0.
*
- * @return A List<InstrumentationInfo> containing one entry for each
+ * @return A List<InstrumentationInfo> containing one entry for each
* matching available Instrumentation. Returns an empty list if
* there is no instrumentation available for the given package.
*/
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 25aa9b3..003d0f2 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -16,6 +16,7 @@
package android.database.sqlite;
+import android.os.StrictMode;
import android.util.Log;
/**
@@ -145,10 +146,14 @@
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
Log.v(TAG, "** warning ** Finalized DbObj (id#" + nStatement + ")");
}
- int len = mSqlStmt.length();
- Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
+ if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+ int len = mSqlStmt.length();
+ StrictMode.onSqliteObjectLeaked(
+ "Releasing statement in a finalizer. Please ensure " +
"that you explicitly call close() on your cursor: " +
- mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
+ mSqlStmt.substring(0, (len > 100) ? 100 : len),
+ mStackTrace);
+ }
releaseSqlStatement();
} finally {
super.finalize();
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index c7e58fa..d8dcaf7 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -24,6 +24,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.Process;
+import android.os.StrictMode;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
@@ -582,11 +583,14 @@
try {
// if the cursor hasn't been closed yet, close it first
if (mWindow != null) {
- int len = mQuery.mSql.length();
- Log.e(TAG, "Finalizing a Cursor that has not been deactivated or closed. " +
+ if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+ int len = mQuery.mSql.length();
+ StrictMode.onSqliteObjectLeaked(
+ "Finalizing a Cursor that has not been deactivated or closed. " +
"database = " + mDatabase.getPath() + ", table = " + mEditTable +
", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len),
mStackTrace);
+ }
close();
SQLiteDebug.notifyActiveCursorFinalized();
} else {
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3ddaad9..9494a06 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,8 +30,9 @@
import java.util.HashMap;
/**
- * <p>StrictMode is a developer tool which lets you impose stricter
- * rules under which your application runs.
+ * <p>StrictMode is a developer tool which detects things you might be
+ * doing by accident and brings them to your attention so you can fix
+ * them.
*
* <p>StrictMode is most commonly used to catch accidental disk or
* network access on the application's main thread, where UI
@@ -55,24 +56,33 @@
* <pre>
* public void onCreate() {
* if (DEVELOPER_MODE) {
- * StrictMode.setThreadPolicy(StrictMode.DISALLOW_DISK_WRITE |
- * StrictMode.DISALLOW_DISK_READ |
- * StrictMode.DISALLOW_NETWORK |
- * StrictMode.PENALTY_LOG);
+ * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
+ * .detectDiskReads()
+ * .detectDiskWrites()
+ * .detectNetwork() // or .detectAll() for all detectable problems
+ * .penaltyLog()
+ * .build());
+ * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
+ * .detectLeakedSqlLiteCursors()
+ * .penaltyLog()
+ * .penaltyDeath()
+ * .build());
* }
* super.onCreate();
* }
* </pre>
*
- * <p>Then you can watch the output of <code>adb logcat</code> while you
- * use your application.
+ * <p>You can decide what should happen when a violation is detected.
+ * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
+ * watch the output of <code>adb logcat</code> while you use your
+ * application to see the violations as they happen.
*
* <p>If you find violations that you feel are problematic, there are
* a variety of tools to help solve them: threads, {@link android.os.Handler},
* {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc.
* But don't feel compelled to fix everything that StrictMode finds. In particular,
- * a lot of disk accesses are often necessary during the normal activity lifecycle. Use
- * StrictMode to find things you did on accident. Network requests on the UI thread
+ * many cases of disk access are often necessary during the normal activity lifecycle. Use
+ * StrictMode to find things you did by accident. Network requests on the UI thread
* are almost always a problem, though.
*
* <p class="note">StrictMode is not a security mechanism and is not
@@ -94,55 +104,50 @@
// Only show an annoying dialog at most every 30 seconds
private static final long MIN_DIALOG_INTERVAL_MS = 30000;
- private StrictMode() {}
+ // Thread-policy:
/**
- * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
- * thread to write to disk.
+ * @hide
*/
- public static final int DISALLOW_DISK_WRITE = 0x01;
+ public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
/**
- * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
- * thread to read from disk.
+ * @hide
*/
- public static final int DISALLOW_DISK_READ = 0x02;
+ public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
/**
- * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
- * thread to access the network.
+ * @hide
*/
- public static final int DISALLOW_NETWORK = 0x04;
+ public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
- /** @hide */
- public static final int DISALLOW_MASK =
- DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK;
+ // Process-policy:
/**
- * Penalty flag for {@link #setThreadPolicy} to log violations to
- * the system log, visible with <code>adb logcat</code>.
+ * Note, a "VM_" bit, not thread.
+ * @hide
+ */
+ public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for ProcessPolicy
+
+ /**
+ * @hide
*/
public static final int PENALTY_LOG = 0x10; // normal android.util.Log
+ // Used for both process and thread policy:
+
/**
- * Penalty flag for {@link #setThreadPolicy} to show an annoying
- * dialog to the developer, rate-limited to be only a little
- * annoying.
+ * @hide
*/
public static final int PENALTY_DIALOG = 0x20;
/**
- * Penalty flag for {@link #setThreadPolicy} to crash hard if
- * policy is violated.
+ * @hide
*/
public static final int PENALTY_DEATH = 0x40;
/**
- * Penalty flag for {@link #setThreadPolicy} to log a stacktrace
- * and timing data to the
- * {@link android.os.DropBoxManager DropBox} on policy violation.
- * Intended mostly for platform integrators doing beta user field
- * data collection.
+ * @hide
*/
public static final int PENALTY_DROPBOX = 0x80;
@@ -159,10 +164,321 @@
*/
public static final int PENALTY_GATHER = 0x100;
- /** @hide */
- public static final int PENALTY_MASK =
- PENALTY_LOG | PENALTY_DIALOG |
- PENALTY_DROPBOX | PENALTY_DEATH;
+ /**
+ * The current VmPolicy in effect.
+ */
+ private static volatile int sVmPolicyMask = 0;
+
+ private StrictMode() {}
+
+ /**
+ * {@link StrictMode} policy applied to a certain thread.
+ *
+ * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy
+ * can be retrieved with {@link #getThreadPolicy}.
+ *
+ * <p>Note that multiple penalties may be provided and they're run
+ * in order from least to most severe (logging before process
+ * death, for example). There's currently no mechanism to choose
+ * different penalties for different detected actions.
+ */
+ public static final class ThreadPolicy {
+ /**
+ * The default, lax policy which doesn't catch anything.
+ */
+ public static final ThreadPolicy LAX = new ThreadPolicy(0);
+
+ final int mask;
+
+ private ThreadPolicy(int mask) {
+ this.mask = mask;
+ }
+
+ @Override
+ public String toString() {
+ return "[StrictMode.ThreadPolicy; mask=" + mask + "]";
+ }
+
+ /**
+ * Creates ThreadPolicy instances. Methods whose names start
+ * with {@code detect} specify what problems we should look
+ * for. Methods whose names start with {@code penalty} specify what
+ * we should do when we detect a problem.
+ *
+ * <p>You can call as many {@code detect} and {@code penalty}
+ * methods as you like. Currently order is insignificant: all
+ * penalties apply to all detected problems.
+ *
+ * <p>For example, detect everything and log anything that's found:
+ * <pre>
+ * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
+ * .detectAll()
+ * .penaltyLog()
+ * .build();
+ * StrictMode.setVmPolicy(policy);
+ * </pre>
+ */
+ public static final class Builder {
+ private int mMask = 0;
+
+ /**
+ * Create a Builder that detects nothing and has no
+ * violations. (but note that {@link #build} will default
+ * to enabling {@link #penaltyLog} if no other penalties
+ * are specified)
+ */
+ public Builder() {
+ mMask = 0;
+ }
+
+ /**
+ * Initialize a Builder from an existing ThreadPolicy.
+ */
+ public Builder(ThreadPolicy policy) {
+ mMask = policy.mask;
+ }
+
+ /**
+ * Detect everything that's potentially suspect.
+ *
+ * <p>As of the Gingerbread release this includes network and
+ * disk operations but will likely expand in future releases.
+ */
+ public Builder detectAll() {
+ return enable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
+ }
+
+ /**
+ * Disable the detection of everything.
+ */
+ public Builder permitAll() {
+ return disable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
+ }
+
+ /**
+ * Enable detection of network operations.
+ */
+ public Builder detectNetwork() {
+ return enable(DETECT_NETWORK);
+ }
+
+ /**
+ * Disable detection of network operations.
+ */
+ public Builder permitNetwork() {
+ return disable(DETECT_NETWORK);
+ }
+
+ /**
+ * Enable detection of disk reads.
+ */
+ public Builder detectDiskReads() {
+ return enable(DETECT_DISK_READ);
+ }
+
+ /**
+ * Disable detection of disk reads.
+ */
+ public Builder permitDiskReads() {
+ return disable(DETECT_DISK_READ);
+ }
+
+ /**
+ * Enable detection of disk writes.
+ */
+ public Builder detectDiskWrites() {
+ return enable(DETECT_DISK_WRITE);
+ }
+
+ /**
+ * Disable detection of disk writes.
+ */
+ public Builder permitDiskWrites() {
+ return disable(DETECT_DISK_WRITE);
+ }
+
+ /**
+ * Show an annoying dialog to the developer on detected
+ * violations, rate-limited to be only a little annoying.
+ */
+ public Builder penaltyDialog() {
+ return enable(PENALTY_DIALOG);
+ }
+
+ /**
+ * Crash the whole process on violation. This penalty runs at
+ * the end of all enabled penalties so you'll still get
+ * see logging or other violations before the process dies.
+ */
+ public Builder penaltyDeath() {
+ return enable(PENALTY_DEATH);
+ }
+
+ /**
+ * Log detected violations to the system log.
+ */
+ public Builder penaltyLog() {
+ return enable(PENALTY_LOG);
+ }
+
+ /**
+ * Enable detected violations log a stacktrace and timing data
+ * to the {@link android.os.DropBoxManager DropBox} on policy
+ * violation. Intended mostly for platform integrators doing
+ * beta user field data collection.
+ */
+ public Builder penaltyDropBox() {
+ return enable(PENALTY_DROPBOX);
+ }
+
+ private Builder enable(int bit) {
+ mMask |= bit;
+ return this;
+ }
+
+ private Builder disable(int bit) {
+ mMask &= ~bit;
+ return this;
+ }
+
+ /**
+ * Construct the ThreadPolicy instance.
+ *
+ * <p>Note: if no penalties are enabled before calling
+ * <code>build</code>, {@link #penaltyLog} is implicitly
+ * set.
+ */
+ public ThreadPolicy build() {
+ // If there are detection bits set but no violation bits
+ // set, enable simple logging.
+ if (mMask != 0 &&
+ (mMask & (PENALTY_DEATH | PENALTY_LOG |
+ PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+ penaltyLog();
+ }
+ return new ThreadPolicy(mMask);
+ }
+ }
+ }
+
+ /**
+ * {@link StrictMode} policy applied to all threads in the virtual machine's process.
+ *
+ * <p>The policy is enabled by {@link #setVmPolicy}.
+ */
+ public static final class VmPolicy {
+ /**
+ * The default, lax policy which doesn't catch anything.
+ */
+ public static final VmPolicy LAX = new VmPolicy(0);
+
+ final int mask;
+
+ private VmPolicy(int mask) {
+ this.mask = mask;
+ }
+
+ @Override
+ public String toString() {
+ return "[StrictMode.VmPolicy; mask=" + mask + "]";
+ }
+
+ /**
+ * Creates {@link VmPolicy} instances. Methods whose names start
+ * with {@code detect} specify what problems we should look
+ * for. Methods whose names start with {@code penalty} specify what
+ * we should do when we detect a problem.
+ *
+ * <p>You can call as many {@code detect} and {@code penalty}
+ * methods as you like. Currently order is insignificant: all
+ * penalties apply to all detected problems.
+ *
+ * <p>For example, detect everything and log anything that's found:
+ * <pre>
+ * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
+ * .detectAll()
+ * .penaltyLog()
+ * .build();
+ * StrictMode.setVmPolicy(policy);
+ * </pre>
+ */
+ public static final class Builder {
+ private int mMask;
+
+ /**
+ * Detect everything that's potentially suspect.
+ *
+ * <p>As of the Gingerbread release this only includes
+ * SQLite cursor leaks but will likely expand in future
+ * releases.
+ */
+ public Builder detectAll() {
+ return enable(DETECT_VM_CURSOR_LEAKS);
+ }
+
+ /**
+ * Detect when an
+ * {@link android.database.sqlite.SQLiteCursor} or other
+ * SQLite object is finalized without having been closed.
+ *
+ * <p>You always want to explicitly close your SQLite
+ * cursors to avoid unnecessary database contention and
+ * temporary memory leaks.
+ */
+ public Builder detectLeakedSqlLiteObjects() {
+ return enable(DETECT_VM_CURSOR_LEAKS);
+ }
+
+ /**
+ * Crashes the whole process on violation. This penalty runs at
+ * the end of all enabled penalties so yo you'll still get
+ * your logging or other violations before the process dies.
+ */
+ public Builder penaltyDeath() {
+ return enable(PENALTY_DEATH);
+ }
+
+ /**
+ * Log detected violations to the system log.
+ */
+ public Builder penaltyLog() {
+ return enable(PENALTY_LOG);
+ }
+
+ /**
+ * Enable detected violations log a stacktrace and timing data
+ * to the {@link android.os.DropBoxManager DropBox} on policy
+ * violation. Intended mostly for platform integrators doing
+ * beta user field data collection.
+ */
+ public Builder penaltyDropBox() {
+ return enable(PENALTY_DROPBOX);
+ }
+
+ private Builder enable(int bit) {
+ mMask |= bit;
+ return this;
+ }
+
+ /**
+ * Construct the VmPolicy instance.
+ *
+ * <p>Note: if no penalties are enabled before calling
+ * <code>build</code>, {@link #penaltyLog} is implicitly
+ * set.
+ */
+ public VmPolicy build() {
+ // If there are detection bits set but no violation bits
+ // set, enable simple logging.
+ if (mMask != 0 &&
+ (mMask & (PENALTY_DEATH | PENALTY_LOG |
+ PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+ penaltyLog();
+ }
+ return new VmPolicy(mMask);
+ }
+ }
+ }
/**
* Log of strict mode violation stack traces that have occurred
@@ -181,19 +497,21 @@
};
/**
- * Sets the policy for what actions the current thread isn't
- * expected to do, as well as the penalty if it does.
+ * Sets the policy for what actions on the current thread should
+ * be detected, as well as the penalty if such actions occur.
*
- * <p>Internally this sets a thread-local integer which is
+ * <p>Internally this sets a thread-local variable which is
* propagated across cross-process IPC calls, meaning you can
* catch violations when a system service or another process
* accesses the disk or network on your behalf.
*
- * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values,
- * e.g. {@link #DISALLOW_DISK_READ}, {@link #DISALLOW_DISK_WRITE},
- * {@link #DISALLOW_NETWORK}, {@link #PENALTY_LOG}.
+ * @param policy the policy to put into place
*/
- public static void setThreadPolicy(final int policyMask) {
+ public static void setThreadPolicy(final ThreadPolicy policy) {
+ setThreadPolicyMask(policy.mask);
+ }
+
+ private static void setThreadPolicyMask(final int policyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
@@ -222,65 +540,76 @@
private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeNetworkViolation(int policyMask) {
- super(policyMask, DISALLOW_NETWORK);
+ super(policyMask, DETECT_NETWORK);
}
}
private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeDiskReadViolation(int policyMask) {
- super(policyMask, DISALLOW_DISK_READ);
+ super(policyMask, DETECT_DISK_READ);
}
}
private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeDiskWriteViolation(int policyMask) {
- super(policyMask, DISALLOW_DISK_WRITE);
+ super(policyMask, DETECT_DISK_WRITE);
}
}
/**
* Returns the bitmask of the current thread's policy.
*
- * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled
+ * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
+ *
+ * @hide
*/
- public static int getThreadPolicy() {
+ public static int getThreadPolicyMask() {
return BlockGuard.getThreadPolicy().getPolicyMask();
}
/**
- * A convenience wrapper around {@link #getThreadPolicy} and
- * {@link #setThreadPolicy}. Updates the current thread's policy
- * mask to allow both reading & writing to disk, returning the
- * old policy so you can restore it at the end of a block.
- *
- * @return the old policy mask, to be passed to setThreadPolicy to
- * restore the policy.
+ * Returns the current thread's policy.
*/
- public static int allowThreadDiskWrites() {
- int oldPolicy = getThreadPolicy();
- int newPolicy = oldPolicy & ~(DISALLOW_DISK_WRITE | DISALLOW_DISK_READ);
- if (newPolicy != oldPolicy) {
- setThreadPolicy(newPolicy);
- }
- return oldPolicy;
+ public static ThreadPolicy getThreadPolicy() {
+ return new ThreadPolicy(getThreadPolicyMask());
}
/**
- * A convenience wrapper around {@link #getThreadPolicy} and
- * {@link #setThreadPolicy}. Updates the current thread's policy
- * mask to allow reading from disk, returning the old
- * policy so you can restore it at the end of a block.
+ * A convenience wrapper that takes the current
+ * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
+ * to permit both disk reads & writes, and sets the new policy
+ * with {@link #setThreadPolicy}, returning the old policy so you
+ * can restore it at the end of a block.
*
- * @return the old policy mask, to be passed to setThreadPolicy to
+ * @return the old policy, to be passed to {@link #setThreadPolicy} to
+ * restore the policy at the end of a block
+ */
+ public static ThreadPolicy allowThreadDiskWrites() {
+ int oldPolicyMask = getThreadPolicyMask();
+ int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
+ if (newPolicyMask != oldPolicyMask) {
+ setThreadPolicyMask(newPolicyMask);
+ }
+ return new ThreadPolicy(oldPolicyMask);
+ }
+
+ /**
+ * A convenience wrapper that takes the current
+ * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
+ * to permit disk reads, and sets the new policy
+ * with {@link #setThreadPolicy}, returning the old policy so you
+ * can restore it at the end of a block.
+ *
+ * @return the old policy, to be passed to setThreadPolicy to
* restore the policy.
*/
- public static int allowThreadDiskReads() {
- int oldPolicy = getThreadPolicy();
- int newPolicy = oldPolicy & ~(DISALLOW_DISK_READ);
- if (newPolicy != oldPolicy) {
- setThreadPolicy(newPolicy);
+ public static ThreadPolicy allowThreadDiskReads() {
+ int oldPolicyMask = getThreadPolicyMask();
+ int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
+ if (newPolicyMask != oldPolicyMask) {
+ setThreadPolicyMask(newPolicyMask);
}
- return oldPolicy;
+ return new ThreadPolicy(oldPolicyMask);
}
/**
@@ -294,11 +623,14 @@
if ("user".equals(Build.TYPE)) {
return false;
}
- StrictMode.setThreadPolicy(
- StrictMode.DISALLOW_DISK_WRITE |
- StrictMode.DISALLOW_DISK_READ |
- StrictMode.DISALLOW_NETWORK |
+ StrictMode.setThreadPolicyMask(
+ StrictMode.DETECT_DISK_WRITE |
+ StrictMode.DETECT_DISK_READ |
+ StrictMode.DETECT_NETWORK |
StrictMode.PENALTY_DROPBOX);
+ sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS |
+ StrictMode.PENALTY_DROPBOX |
+ StrictMode.PENALTY_LOG;
return true;
}
@@ -372,7 +704,7 @@
// Part of BlockGuard.Policy interface:
public void onWriteToDisk() {
- if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) {
+ if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
@@ -382,7 +714,7 @@
// Part of BlockGuard.Policy interface:
public void onReadFromDisk() {
- if ((mPolicyMask & DISALLOW_DISK_READ) == 0) {
+ if ((mPolicyMask & DETECT_DISK_READ) == 0) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
@@ -392,7 +724,7 @@
// Part of BlockGuard.Policy interface:
public void onNetwork() {
- if ((mPolicyMask & DISALLOW_NETWORK) == 0) {
+ if ((mPolicyMask & DETECT_NETWORK) == 0) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
@@ -547,13 +879,13 @@
if (violationMaskSubset != 0) {
int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
violationMaskSubset |= violationBit;
- final int savedPolicy = getThreadPolicy();
+ final int savedPolicyMask = getThreadPolicyMask();
try {
// First, remove any policy before we call into the Activity Manager,
// otherwise we'll infinite recurse as we try to log policy violations
// to disk, thus violating policy, thus requiring logging, etc...
// We restore the current policy below, in the finally block.
- setThreadPolicy(0);
+ setThreadPolicyMask(0);
ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
RuntimeInit.getApplicationObject(),
@@ -563,7 +895,7 @@
Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
} finally {
// Restore the policy.
- setThreadPolicy(savedPolicy);
+ setThreadPolicyMask(savedPolicyMask);
}
}
@@ -592,6 +924,74 @@
}
/**
+ * Sets the policy for what actions in the VM process (on any
+ * thread) should be detected, as well as the penalty if such
+ * actions occur.
+ *
+ * @param policy the policy to put into place
+ */
+ public static void setVmPolicy(final VmPolicy policy) {
+ sVmPolicyMask = policy.mask;
+ }
+
+ /**
+ * Gets the current VM policy.
+ */
+ public static VmPolicy getVmPolicy() {
+ return new VmPolicy(sVmPolicyMask);
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean vmSqliteObjectLeaksEnabled() {
+ return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
+ }
+
+ /**
+ * @hide
+ */
+ public static void onSqliteObjectLeaked(String message, Throwable originStack) {
+ if ((sVmPolicyMask & PENALTY_LOG) != 0) {
+ Log.e(TAG, message, originStack);
+ }
+
+ if ((sVmPolicyMask & PENALTY_DROPBOX) != 0) {
+ final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+
+ // The violationMask, passed to ActivityManager, is a
+ // subset of the original StrictMode policy bitmask, with
+ // only the bit violated and penalty bits to be executed
+ // by the ActivityManagerService remaining set.
+ int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
+ final int savedPolicyMask = getThreadPolicyMask();
+ try {
+ // First, remove any policy before we call into the Activity Manager,
+ // otherwise we'll infinite recurse as we try to log policy violations
+ // to disk, thus violating policy, thus requiring logging, etc...
+ // We restore the current policy below, in the finally block.
+ setThreadPolicyMask(0);
+
+ ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
+ RuntimeInit.getApplicationObject(),
+ violationMaskSubset,
+ info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ } finally {
+ // Restore the policy.
+ setThreadPolicyMask(savedPolicyMask);
+ }
+ }
+
+ if ((sVmPolicyMask & PENALTY_DEATH) != 0) {
+ System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down.");
+ Process.killProcess(Process.myPid());
+ System.exit(10);
+ }
+ }
+
+ /**
* Called from Parcel.writeNoException()
*/
/* package */ static void writeGatheredViolationsToParcel(Parcel p) {
@@ -621,7 +1021,7 @@
new LogStackTrace().printStackTrace(new PrintWriter(sw));
String ourStack = sw.toString();
- int policyMask = getThreadPolicy();
+ int policyMask = getThreadPolicyMask();
boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
int numViolations = p.readInt();
diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java
index 3d340d9..1b2a894 100644
--- a/core/java/android/util/CalendarUtils.java
+++ b/core/java/android/util/CalendarUtils.java
@@ -146,6 +146,9 @@
* This formats a date/time range using Calendar's time zone and the
* local conventions for the region of the device.
*
+ * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in
+ * the UTC time zone instead.
+ *
* @param context the context is required only if the time is shown
* @param startMillis the start time in UTC milliseconds
* @param endMillis the end time in UTC milliseconds
@@ -156,10 +159,16 @@
public String formatDateRange(Context context, long startMillis,
long endMillis, int flags) {
String date;
+ String tz;
+ if ((flags & DateUtils.FORMAT_UTC) != 0) {
+ tz = Time.TIMEZONE_UTC;
+ } else {
+ tz = getTimeZone(context, null);
+ }
synchronized (mSB) {
mSB.setLength(0);
date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
- getTimeZone(context, null)).toString();
+ tz).toString();
}
return date;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 76701a9..954b3e7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -73,6 +73,7 @@
public final static int FLAG_ALT_GR = 0x00000020;
public final static int FLAG_MENU = 0x00000040;
public final static int FLAG_LAUNCHER = 0x00000080;
+ public final static int FLAG_VIRTUAL = 0x00000100;
public final static int FLAG_INJECTED = 0x01000000;
@@ -261,24 +262,6 @@
boolean isDisplayedLw();
/**
- * Returns true if the window is both full screen and opaque. Must be
- * called with the window manager lock held.
- *
- * @param width The width of the screen
- * @param height The height of the screen
- * @param shownFrame If true, this is based on the actual shown frame of
- * the window (taking into account animations); if
- * false, this is based on the currently requested
- * frame, which any current animation will be moving
- * towards.
- * @param onlyOpaque If true, this will only pass if the window is
- * also opaque.
- * @return Returns true if the window is both full screen and opaque
- */
- public boolean fillsScreenLw(int width, int height, boolean shownFrame,
- boolean onlyOpaque);
-
- /**
* Returns true if this window has been shown on screen at some time in
* the past. Must be called with the window manager lock held.
*
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f4d1b6e..d51c0b7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -101,7 +101,6 @@
android_graphics_PixelFormat.cpp \
android/graphics/Picture.cpp \
android/graphics/PorterDuff.cpp \
- android/graphics/BitmapRegionDecoder.cpp \
android/graphics/Rasterizer.cpp \
android/graphics/Region.cpp \
android/graphics/Shader.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e5d5d8a..5f73443 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,7 +53,6 @@
extern int register_android_os_Process(JNIEnv* env);
extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
@@ -1220,7 +1219,6 @@
REG_JNI(register_android_graphics_Bitmap),
REG_JNI(register_android_graphics_BitmapFactory),
- REG_JNI(register_android_graphics_BitmapRegionDecoder),
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_ColorFilter),
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
deleted file mode 100644
index 4503852..0000000
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * 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_TAG "BitmapRegionDecoder"
-
-#include "SkBitmap.h"
-#include "SkImageEncoder.h"
-#include "GraphicsJNI.h"
-#include "SkUtils.h"
-#include "SkTemplates.h"
-#include "SkPixelRef.h"
-#include "SkStream.h"
-#include "BitmapFactory.h"
-#include "AutoDecodeCancel.h"
-#include "SkBitmapRegionDecoder.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-#include "Utils.h"
-
-#include <android_runtime/AndroidRuntime.h>
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <binder/Parcel.h>
-#include <jni.h>
-#include <utils/Asset.h>
-#include <sys/stat.h>
-
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
-#if 0
- #define TRACE_BITMAP(code) code
-#else
- #define TRACE_BITMAP(code)
-#endif
-
-using namespace android;
-
-static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
- size_t bufferSize = 4096;
- size_t streamLen = 0;
- size_t len;
- char* data = (char*)sk_malloc_throw(bufferSize);
-
- while ((len = stream->read(data + streamLen,
- bufferSize - streamLen)) != 0) {
- streamLen += len;
- if (streamLen == bufferSize) {
- bufferSize *= 2;
- data = (char*)sk_realloc_throw(data, bufferSize);
- }
- }
- data = (char*)sk_realloc_throw(data, streamLen);
- SkMemoryStream* streamMem = new SkMemoryStream();
- streamMem->setMemoryOwned(data, streamLen);
- return streamMem;
-}
-
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
- SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
- int width, height;
- if (NULL == decoder) {
- doThrowIOE(env, "Image format not supported");
- return nullObjectReturn("SkImageDecoder::Factory returned null");
- }
-
- JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
- decoder->setAllocator(javaAllocator);
- JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
- decoder->setReporter(javaMemoryReporter);
- javaAllocator->unref();
- javaMemoryReporter->unref();
-
- if (!decoder->buildTileIndex(stream, &width, &height)) {
- char msg[100];
- snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
- decoder->getFormatName());
- doThrowIOE(env, msg);
- return nullObjectReturn("decoder->buildTileIndex returned false");
- }
-
- SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
-
- return GraphicsJNI::createBitmapRegionDecoder(env, bm);
-}
-
-static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
- int offset, int length, jboolean isShareable) {
- /* If isShareable we could decide to just wrap the java array and
- share it, but that means adding a globalref to the java array object
- For now we just always copy the array's data if isShareable.
- */
- AutoJavaByteArray ar(env, byteArray);
- SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
- return doBuildTileIndex(env, stream);
-}
-
-static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jboolean isShareable) {
- NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
-
- jint descriptor = env->GetIntField(fileDescriptor,
- gFileDescriptor_descriptor);
- SkStream *stream = NULL;
- struct stat fdStat;
- int newFD;
- if (fstat(descriptor, &fdStat) == -1) {
- doThrowIOE(env, "broken file descriptor");
- return nullObjectReturn("fstat return -1");
- }
-
- if (isShareable &&
- S_ISREG(fdStat.st_mode) &&
- (newFD = ::dup(descriptor)) != -1) {
- SkFDStream* fdStream = new SkFDStream(newFD, true);
- if (!fdStream->isValid()) {
- fdStream->unref();
- return NULL;
- }
- stream = fdStream;
- } else {
- SkFDStream* fdStream = new SkFDStream(descriptor, false);
- if (!fdStream->isValid()) {
- fdStream->unref();
- return NULL;
- }
- stream = buildSkMemoryStream(fdStream);
- fdStream->unref();
- }
-
- /* Restore our offset when we leave, so we can be called more than once
- with the same descriptor. This is only required if we didn't dup the
- file descriptor, but it is OK to do it all the time.
- */
- AutoFDSeek as(descriptor);
-
- return doBuildTileIndex(env, stream);
-}
-
-static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
- jobject is, // InputStream
- jbyteArray storage, // byte[]
- jboolean isShareable) {
- jobject largeBitmap = NULL;
- SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
-
- if (stream) {
- // for now we don't allow shareable with java inputstreams
- SkMemoryStream *mStream = buildSkMemoryStream(stream);
- largeBitmap = doBuildTileIndex(env, mStream);
- stream->unref();
- }
- return largeBitmap;
-}
-
-static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
- jint native_asset, // Asset
- jboolean isShareable) {
- SkStream* stream, *assStream;
- Asset* asset = reinterpret_cast<Asset*>(native_asset);
- assStream = new AssetStreamAdaptor(asset);
- stream = buildSkMemoryStream(assStream);
- assStream->unref();
- return doBuildTileIndex(env, stream);
-}
-
-/*
- * nine patch not supported
- *
- * purgeable not supported
- * reportSizeToVM not supported
- */
-static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
- int start_x, int start_y, int width, int height, jobject options) {
- SkImageDecoder *decoder = brd->getDecoder();
- int sampleSize = 1;
- SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
- bool doDither = true;
-
- if (NULL != options) {
- sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
- // initialize these, in case we fail later on
- env->SetIntField(options, gOptions_widthFieldID, -1);
- env->SetIntField(options, gOptions_heightFieldID, -1);
- env->SetObjectField(options, gOptions_mimeFieldID, 0);
-
- jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
- prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
- doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
- }
-
- decoder->setDitherImage(doDither);
- SkBitmap* bitmap = new SkBitmap;
- SkAutoTDelete<SkBitmap> adb(bitmap);
- AutoDecoderCancel adc(options, decoder);
-
- // To fix the race condition in case "requestCancelDecode"
- // happens earlier than AutoDecoderCancel object is added
- // to the gAutoDecoderCancelMutex linked list.
- if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
- return nullObjectReturn("gOptions_mCancelID");;
- }
-
- SkIRect region;
- region.fLeft = start_x;
- region.fTop = start_y;
- region.fRight = start_x + width;
- region.fBottom = start_y + height;
-
- if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
- return nullObjectReturn("decoder->decodeRegion returned false");
- }
-
- // update options (if any)
- if (NULL != options) {
- env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
- env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
- // TODO: set the mimeType field with the data from the codec.
- // but how to reuse a set of strings, rather than allocating new one
- // each time?
- env->SetObjectField(options, gOptions_mimeFieldID,
- getMimeTypeString(env, decoder->getFormat()));
- }
-
- // detach bitmap from its autotdeleter, since we want to own it now
- adb.detach();
-
- SkPixelRef* pr;
- pr = bitmap->pixelRef();
- // promise we will never change our pixels (great for sharing and pictures)
- pr->setImmutable();
- // now create the java bitmap
- return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
-}
-
-static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
- return brd->getHeight();
-}
-
-static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
- return brd->getWidth();
-}
-
-static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
- delete brd;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapRegionDecoderMethods[] = {
- { "nativeDecodeRegion",
- "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
- (void*)nativeDecodeRegion},
-
- { "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
-
- { "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
-
- { "nativeClean", "(I)V", (void*)nativeClean},
-
- { "nativeNewInstance",
- "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
- (void*)nativeNewInstanceFromByteArray
- },
-
- { "nativeNewInstance",
- "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
- (void*)nativeNewInstanceFromStream
- },
-
- { "nativeNewInstance",
- "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
- (void*)nativeNewInstanceFromFileDescriptor
- },
-
- { "nativeNewInstance",
- "(IZ)Landroid/graphics/BitmapRegionDecoder;",
- (void*)nativeNewInstanceFromAsset
- },
-};
-
-#define kClassPathName "android/graphics/BitmapRegionDecoder"
-
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
- gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
-}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1ebe14b..195f4d2 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -168,9 +168,6 @@
static jclass gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
-static jclass gBitmapRegionDecoder_class;
-static jmethodID gBitmapRegionDecoder_constructorMethodID;
-
static jclass gCanvas_class;
static jfieldID gCanvas_nativeInstanceID;
@@ -377,24 +374,6 @@
return obj;
}
-jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
-{
- SkASSERT(bitmap != NULL);
-
- jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
- if (hasException(env)) {
- obj = NULL;
- return obj;
- }
- if (obj) {
- env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
- if (hasException(env)) {
- obj = NULL;
- }
- }
- return obj;
-}
-
jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
{
SkASSERT(region != NULL);
@@ -613,9 +592,6 @@
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
"(IZ[BI)V");
- gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
- gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
-
gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
"nativeInt", "I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index d0f9125..1f94418 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -4,7 +4,6 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkBitmap.h"
-#include "../images/SkBitmapRegionDecoder.h"
#include "../images/SkImageDecoder.h"
#include <jni.h>
@@ -56,8 +55,6 @@
static jobject createRegion(JNIEnv* env, SkRegion* region);
- static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
-
/** Set a pixelref for the bitmap (needs setConfig to already be called)
Returns true on success. If it returns false, then it failed, and the
appropriate exception will have been raised.
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4cdf4f6f..02524bf 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -244,6 +244,7 @@
<item name="android:clickable">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
<item name="android:textColor">@android:color/primary_text_light</item>
+ <item name="android:textStyle">bold</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 92d4e15..3b4ccb0e 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:12.0,17.5,0.1,41.7,28.7&chl=
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:9.7,16.4,0.1,40.4,33.4&chl=
Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
6fad0c" />
@@ -62,13 +62,13 @@
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>12.0%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>17.5%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>41.7%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>28.7%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>9.7%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>16.4%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>40.4%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>33.4%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on September 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on October 1, 2010</em></p>
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
</div><!-- end dashboard-panel -->
@@ -96,19 +96,19 @@
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0%3A%7C2010/03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/
-01%7C08/15%7C2010/09/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
-%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.4,99.5,99.6,99.6,99.6,99.7,
-100.6,101.1,99.9,100.0,100.0,99.8,99.9|61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,
-88.0|24.3,25.4,29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.2,70.4|0.0,0.0,4.0,28.3,32.0,34.9,45.
-9,51.0,54.9,58.8,64.0,68.1,70.3|0.0,0.0,0.0,0.0,0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,27.8&chm=tAndroid%
-201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|
-tAndroid%202.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid%202.1,2f4708,3,3,15,,t::-5|b,89cf19,3,
-4,0|tAndroid%202.2,131d02,4,11,15,,t::-5|B,6fad0c,4,5,0&chg=7,25&chdl=Android%201.5|Android%201.6|
-Android%202.0.1|Android%202.1|Android%202.2&chco=add274,9ad145,84c323,6ba213,507d08" />
+src="http://chart.apis.google.com/chart?cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
+chxl=0:|2010/04/01|04/15|05/01|05/15|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|2010/10/01|1:|0
+%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
+chxtc=0,5&chd=t:99.6,99.6,99.6,99.7,100.6,101.1,99.9,100.0,100.0,99.8,99.9,100.0,100.0|61.5,61.7,62.
+3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,88.0,89.3,90.3|29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.
+2,70.4,72.2,73.9|4.0,28.3,32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8|0.0,0.0,0.0,0.0,0.8
+,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4&chm=tAndroid+1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid+1
+.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid+2.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid+2
+.1,2f4708,3,1,15,,t:-30:-40|b,89cf19,3,4,0|tAndroid+2.2,131d02,4,9,15,,t::-5|B,6fad0c,4,5,0&chg=7,25
+&chdl=Android+1.5|Android+1.6|Android+2.0.1|Android+2.1|Android+2.2&chco=add274,9ad145,84c323,6ba213
+,507d08" />
-<p><em>Last historical dataset collected during two weeks ending on September 1, 2010</em></p>
+<p><em>Last historical dataset collected during two weeks ending on October 1, 2010</em></p>
</div><!-- end dashboard-panel -->
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
deleted file mode 100644
index 454eb4a..0000000
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/* Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.content.res.AssetManager;
-
-import java.io.BufferedInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * BitmapRegionDecoder can be used to decode a rectangle region from an image.
- * BitmapRegionDecoder is particularly useful when an original image is large and
- * you only need parts of the image.
- *
- * <p>To create a BitmapRegionDecoder, call newInstance(...).
- * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
- * to get a decoded Bitmap of the specified region.
- *
- */
-public final class BitmapRegionDecoder {
- private int mNativeBitmapRegionDecoder;
- private boolean mRecycled;
-
- /**
- * Create a BitmapRegionDecoder from the specified byte array.
- * Currently only the Jpeg format is supported.
- *
- * @param data byte array of compressed image data.
- * @param offset offset into data for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
- * shallow reference to the input. If this is false,
- * then the BitmapRegionDecoder will explicitly make a copy of the
- * input data, and keep that. Even if sharing is allowed,
- * the implementation may still decide to make a deep
- * copy of the input data. If an image is progressively encoded,
- * allowing sharing may degrade the decoding speed.
- * @return BitmapRegionDecoder, or null if the image data could not be decoded.
- * @throws IOException if the image format is not supported or can not be decoded.
- */
- public static BitmapRegionDecoder newInstance(byte[] data,
- int offset, int length, boolean isShareable) throws IOException {
- if ((offset | length) < 0 || data.length < offset + length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- return nativeNewInstance(data, offset, length, isShareable);
- }
-
- /**
- * Create a BitmapRegionDecoder from the file descriptor.
- * The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
- * Currently only the Jpeg format is supported.
- *
- * @param fd The file descriptor containing the data to decode
- * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
- * shallow reference to the input. If this is false,
- * then the BitmapRegionDecoder will explicitly make a copy of the
- * input data, and keep that. Even if sharing is allowed,
- * the implementation may still decide to make a deep
- * copy of the input data. If an image is progressively encoded,
- * allowing sharing may degrade the decoding speed.
- * @return BitmapRegionDecoder, or null if the image data could not be decoded.
- * @throws IOException if the image format is not supported or can not be decoded.
- */
- public static BitmapRegionDecoder newInstance(
- FileDescriptor fd, boolean isShareable) throws IOException {
- return nativeNewInstance(fd, isShareable);
- }
-
- /**
- * Create a BitmapRegionDecoder from an input stream.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- * Currently only the Jpeg format is supported.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * BitmapRegionDecoder.
- * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
- * shallow reference to the input. If this is false,
- * then the BitmapRegionDecoder will explicitly make a copy of the
- * input data, and keep that. Even if sharing is allowed,
- * the implementation may still decide to make a deep
- * copy of the input data. If an image is progressively encoded,
- * allowing sharing may degrade the decoding speed.
- * @return BitmapRegionDecoder, or null if the image data could not be decoded.
- * @throws IOException if the image format is not supported or can not be decoded.
- */
- public static BitmapRegionDecoder newInstance(InputStream is,
- boolean isShareable) throws IOException {
- // we need mark/reset to work properly in JNI
-
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 16 * 1024);
- }
-
- if (is instanceof AssetManager.AssetInputStream) {
- return nativeNewInstance(
- ((AssetManager.AssetInputStream) is).getAssetInt(),
- isShareable);
- } else {
- // pass some temp storage down to the native code. 1024 is made up,
- // but should be large enough to avoid too many small calls back
- // into is.read(...).
- byte [] tempStorage = new byte[16 * 1024];
- return nativeNewInstance(is, tempStorage, isShareable);
- }
- }
-
- /**
- * Create a BitmapRegionDecoder from a file path.
- * Currently only the Jpeg format is supported.
- *
- * @param pathName complete path name for the file to be decoded.
- * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
- * shallow reference to the input. If this is false,
- * then the BitmapRegionDecoder will explicitly make a copy of the
- * input data, and keep that. Even if sharing is allowed,
- * the implementation may still decide to make a deep
- * copy of the input data. If an image is progressively encoded,
- * allowing sharing may degrade the decoding speed.
- * @return BitmapRegionDecoder, or null if the image data could not be decoded.
- * @throws IOException if the image format is not supported or can not be decoded.
- */
- public static BitmapRegionDecoder newInstance(String pathName,
- boolean isShareable) throws IOException {
- BitmapRegionDecoder decoder = null;
- InputStream stream = null;
-
- try {
- stream = new FileInputStream(pathName);
- decoder = newInstance(stream, isShareable);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- // do nothing here
- }
- }
- }
- return decoder;
- }
-
- /* Private constructor that must receive an already allocated native
- region decoder int (pointer).
-
- This can be called from JNI code.
- */
- private BitmapRegionDecoder(int decoder) {
- mNativeBitmapRegionDecoder = decoder;
- mRecycled = false;
- }
-
- /**
- * Decodes a rectangle region in the image specified by rect.
- *
- * @param rect The rectangle that specified the region to be decode.
- * @param options null-ok; Options that control downsampling.
- * inPurgeable is not supported.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded.
- */
- public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
- checkRecycled("decodeRegion called on recycled region decoder");
- if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
- || rect.bottom > getHeight())
- throw new IllegalArgumentException("rectangle is not inside the image");
- return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top, options);
- }
-
- /** Returns the original image's width */
- public int getWidth() {
- checkRecycled("getWidth called on recycled region decoder");
- return nativeGetWidth(mNativeBitmapRegionDecoder);
- }
-
- /** Returns the original image's height */
- public int getHeight() {
- checkRecycled("getHeight called on recycled region decoder");
- return nativeGetHeight(mNativeBitmapRegionDecoder);
- }
-
- /**
- * Frees up the memory associated with this region decoder, and mark the
- * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
- * getWidth() or getHeight() is called.
- *
- * <p>This operation cannot be reversed, so it should only be called if you are
- * sure there are no further uses for the region decoder. This is an advanced call,
- * and normally need not be called, since the normal GC process will free up this
- * memory when there are no more references to this region decoder.
- */
- public void recycle() {
- if (!mRecycled) {
- nativeClean(mNativeBitmapRegionDecoder);
- mRecycled = true;
- }
- }
-
- /**
- * Returns true if this region decoder has been recycled.
- * If so, then it is an error to try use its method.
- *
- * @return true if the region decoder has been recycled
- */
- public final boolean isRecycled() {
- return mRecycled;
- }
-
- /**
- * Called by methods that want to throw an exception if the region decoder
- * has already been recycled.
- */
- private void checkRecycled(String errorMessage) {
- if (mRecycled) {
- throw new IllegalStateException(errorMessage);
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- recycle();
- } finally {
- super.finalize();
- }
- }
-
- private static native Bitmap nativeDecodeRegion(int lbm,
- int start_x, int start_y, int width, int height,
- BitmapFactory.Options options);
- private static native int nativeGetWidth(int lbm);
- private static native int nativeGetHeight(int lbm);
- private static native void nativeClean(int lbm);
-
- private static native BitmapRegionDecoder nativeNewInstance(
- byte[] data, int offset, int length, boolean isShareable);
- private static native BitmapRegionDecoder nativeNewInstance(
- FileDescriptor fd, boolean isShareable);
- private static native BitmapRegionDecoder nativeNewInstance(
- InputStream is, byte[] storage, boolean isShareable);
- private static native BitmapRegionDecoder nativeNewInstance(
- int asset, boolean isShareable);
-}
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 21baf32..ee40b85 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,8 @@
* policy decisions such as waking from device sleep.
*/
enum {
- /* These flags originate in RawEvents and are generally set in the key map. */
+ /* These flags originate in RawEvents and are generally set in the key map.
+ * See also labels for policy flags in KeycodeLabels.h. */
POLICY_FLAG_WAKE = 0x00000001,
POLICY_FLAG_WAKE_DROPPED = 0x00000002,
@@ -83,6 +84,7 @@
POLICY_FLAG_ALT_GR = 0x00000020,
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
+ POLICY_FLAG_VIRTUAL = 0x00000100,
POLICY_FLAG_RAW_MASK = 0x0000ffff,
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index d3fbaf7..2209cb8 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -103,10 +103,6 @@
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation) = 0;
- /* Provides feedback for a virtual key down.
- */
- virtual void virtualKeyDownFeedback() = 0;
-
/* Intercepts a key event.
* The policy can use this method as an opportunity to perform power management functions
* and early event preprocessing such as updating policy flags.
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index c8d6ffc..f71d9cd 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -142,6 +142,7 @@
{ NULL, 0 }
};
+// See also policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
@@ -151,6 +152,7 @@
{ "ALT_GR", 0x00000020 },
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
+ { "VIRTUAL", 0x00000100 },
{ NULL, 0 }
};
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 1d35e10..825febc 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -993,7 +993,10 @@
int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
+ keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
+ if (policyFlags & POLICY_FLAG_VIRTUAL) {
+ keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
@@ -2162,10 +2165,7 @@
int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
int32_t metaState = mContext->getGlobalMetaState();
- if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
- getPolicy()->virtualKeyDownFeedback();
- }
-
+ policyFlags |= POLICY_FLAG_VIRTUAL;
int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 12022bd..c955ac3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -273,20 +273,6 @@
status_t AwesomePlayer::setDataSource(
int fd, int64_t offset, int64_t length) {
-#if 0
- // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
- return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
- // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
- // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
- // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
- // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
- // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
- // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
- // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
- // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
- // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
-#endif
-
Mutex::Autolock autoLock(mLock);
reset_l();
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 511ae12..a8f1104 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -21,7 +21,7 @@
namespace android {
-static unsigned parseUE(ABitReader *br) {
+unsigned parseUE(ABitReader *br) {
unsigned numZeroes = 0;
while (br->getBits(1) == 0) {
++numZeroes;
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index 3c0b736..868c514 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -31,6 +31,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/hexdump.h>
namespace android {
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 001afc4..9103927 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -93,7 +93,7 @@
}
if (mLastFetchTimeUs < 0) {
- mPlaylistIndex = mPlaylist->size() / 2;
+ mPlaylistIndex = 0;
} else {
if (nextSequenceNumber < mFirstItemSequenceNumber
|| nextSequenceNumber
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index cc405b5..6602852 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -22,9 +22,13 @@
namespace android {
+struct ABitReader;
+
void FindAVCDimensions(
const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
+unsigned parseUE(ABitReader *br);
+
} // namespace android
#endif // AVC_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 47cca80..bcaab9f 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -21,6 +21,7 @@
#include "ATSParser.h"
#include "AnotherPacketSource.h"
+#include "ESQueue.h"
#include "include/avc_utils.h"
#include <media/stagefright/foundation/ABitReader.h>
@@ -79,6 +80,8 @@
sp<AnotherPacketSource> mSource;
bool mPayloadStarted;
+ ElementaryStreamQueue mQueue;
+
void flush();
void parsePES(ABitReader *br);
@@ -232,7 +235,9 @@
: mElementaryPID(elementaryPID),
mStreamType(streamType),
mBuffer(new ABuffer(128 * 1024)),
- mPayloadStarted(false) {
+ mPayloadStarted(false),
+ mQueue(streamType == 0x1b
+ ? ElementaryStreamQueue::H264 : ElementaryStreamQueue::AAC) {
mBuffer->setRange(0, 0);
}
@@ -433,373 +438,31 @@
mBuffer->setRange(0, 0);
}
-static sp<ABuffer> FindNAL(
- const uint8_t *data, size_t size, unsigned nalType,
- size_t *stopOffset) {
- bool foundStart = false;
- size_t startOffset = 0;
-
- size_t offset = 0;
- for (;;) {
- while (offset + 3 < size
- && memcmp("\x00\x00\x00\x01", &data[offset], 4)) {
- ++offset;
- }
-
- if (foundStart) {
- size_t nalSize;
- if (offset + 3 >= size) {
- nalSize = size - startOffset;
- } else {
- nalSize = offset - startOffset;
- }
-
- sp<ABuffer> nal = new ABuffer(nalSize);
- memcpy(nal->data(), &data[startOffset], nalSize);
-
- if (stopOffset != NULL) {
- *stopOffset = startOffset + nalSize;
- }
-
- return nal;
- }
-
- if (offset + 4 >= size) {
- return NULL;
- }
-
- if ((data[offset + 4] & 0x1f) == nalType) {
- foundStart = true;
- startOffset = offset + 4;
- }
-
- offset += 4;
- }
-}
-
-static sp<ABuffer> MakeAVCCodecSpecificData(
- const sp<ABuffer> &buffer, int32_t *width, int32_t *height) {
- const uint8_t *data = buffer->data();
- size_t size = buffer->size();
-
- sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
- if (seqParamSet == NULL) {
- return NULL;
- }
-
- FindAVCDimensions(seqParamSet, width, height);
-
- size_t stopOffset;
- sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
- CHECK(picParamSet != NULL);
-
- buffer->setRange(stopOffset, size - stopOffset);
- LOGV("buffer has %d bytes left.", buffer->size());
-
- size_t csdSize =
- 1 + 3 + 1 + 1
- + 2 * 1 + seqParamSet->size()
- + 1 + 2 * 1 + picParamSet->size();
-
- sp<ABuffer> csd = new ABuffer(csdSize);
- uint8_t *out = csd->data();
-
- *out++ = 0x01; // configurationVersion
- memcpy(out, seqParamSet->data() + 1, 3); // profile/level...
- out += 3;
- *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
- *out++ = 0xe0 | 1;
-
- *out++ = seqParamSet->size() >> 8;
- *out++ = seqParamSet->size() & 0xff;
- memcpy(out, seqParamSet->data(), seqParamSet->size());
- out += seqParamSet->size();
-
- *out++ = 1;
-
- *out++ = picParamSet->size() >> 8;
- *out++ = picParamSet->size() & 0xff;
- memcpy(out, picParamSet->data(), picParamSet->size());
-
- return csd;
-}
-
-static bool getNextNALUnit(
- const uint8_t **_data, size_t *_size,
- const uint8_t **nalStart, size_t *nalSize) {
- const uint8_t *data = *_data;
- size_t size = *_size;
-
- // hexdump(data, size);
-
- *nalStart = NULL;
- *nalSize = 0;
-
- if (size == 0) {
- return false;
- }
-
- size_t offset = 0;
- for (;;) {
- CHECK_LT(offset + 2, size);
-
- if (!memcmp("\x00\x00\x01", &data[offset], 3)) {
- break;
- }
-
- CHECK_EQ((unsigned)data[offset], 0x00u);
- ++offset;
- }
-
- offset += 3;
- size_t startOffset = offset;
-
- while (offset + 2 < size
- && memcmp("\x00\x00\x00", &data[offset], 3)
- && memcmp("\x00\x00\x01", &data[offset], 3)) {
- ++offset;
- }
-
- if (offset + 2 >= size) {
- *nalStart = &data[startOffset];
- *nalSize = size - startOffset;
-
- *_data = NULL;
- *_size = 0;
-
- return true;
- }
-
- size_t endOffset = offset;
-
- while (offset + 2 < size && memcmp("\x00\x00\x01", &data[offset], 3)) {
- CHECK_EQ((unsigned)data[offset], 0x00u);
- ++offset;
- }
-
- *nalStart = &data[startOffset];
- *nalSize = endOffset - startOffset;
-
- if (offset + 2 < size) {
- *_data = &data[offset];
- *_size = size - offset;
- } else {
- *_data = NULL;
- *_size = 0;
- }
-
- return true;
-}
-
-sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
- // hexdump(data, size);
-
- const uint8_t *tmpData = data;
- size_t tmpSize = size;
-
- size_t totalSize = 0;
- const uint8_t *nalStart;
- size_t nalSize;
- while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) {
- // hexdump(nalStart, nalSize);
- totalSize += 4 + nalSize;
- }
-
- sp<ABuffer> buffer = new ABuffer(totalSize);
- size_t offset = 0;
- while (getNextNALUnit(&data, &size, &nalStart, &nalSize)) {
- memcpy(buffer->data() + offset, "\x00\x00\x00\x01", 4);
- memcpy(buffer->data() + offset + 4, nalStart, nalSize);
-
- offset += 4 + nalSize;
- }
-
- return buffer;
-}
-
-static sp<ABuffer> FindMPEG2ADTSConfig(
- const sp<ABuffer> &buffer, int32_t *sampleRate, int32_t *channelCount) {
- ABitReader br(buffer->data(), buffer->size());
-
- CHECK_EQ(br.getBits(12), 0xfffu);
- CHECK_EQ(br.getBits(1), 0u);
- CHECK_EQ(br.getBits(2), 0u);
- br.getBits(1); // protection_absent
- unsigned profile = br.getBits(2);
- LOGV("profile = %u", profile);
- CHECK_NE(profile, 3u);
- unsigned sampling_freq_index = br.getBits(4);
- br.getBits(1); // private_bit
- unsigned channel_configuration = br.getBits(3);
- CHECK_NE(channel_configuration, 0u);
-
- LOGV("sampling_freq_index = %u", sampling_freq_index);
- LOGV("channel_configuration = %u", channel_configuration);
-
- CHECK_LE(sampling_freq_index, 11u);
- static const int32_t kSamplingFreq[] = {
- 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
- 16000, 12000, 11025, 8000
- };
- *sampleRate = kSamplingFreq[sampling_freq_index];
-
- *channelCount = channel_configuration;
-
- static const uint8_t kStaticESDS[] = {
- 0x03, 22,
- 0x00, 0x00, // ES_ID
- 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
- 0x04, 17,
- 0x40, // Audio ISO/IEC 14496-3
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- 0x05, 2,
- // AudioSpecificInfo follows
-
- // oooo offf fccc c000
- // o - audioObjectType
- // f - samplingFreqIndex
- // c - channelConfig
- };
- sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
- memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
-
- csd->data()[sizeof(kStaticESDS)] =
- ((profile + 1) << 3) | (sampling_freq_index >> 1);
-
- csd->data()[sizeof(kStaticESDS) + 1] =
- ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
-
- // hexdump(csd->data(), csd->size());
- return csd;
-}
-
void ATSParser::Stream::onPayloadData(
unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
const uint8_t *data, size_t size) {
LOGV("onPayloadData mStreamType=0x%02x", mStreamType);
- sp<ABuffer> buffer;
-
- if (mStreamType == 0x1b) {
- buffer = MakeCleanAVCData(data, size);
- } else {
- // hexdump(data, size);
-
- buffer = new ABuffer(size);
- memcpy(buffer->data(), data, size);
- }
-
- if (mSource == NULL) {
- sp<MetaData> meta = new MetaData;
-
- if (mStreamType == 0x1b) {
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-
- int32_t width, height;
- sp<ABuffer> csd = MakeAVCCodecSpecificData(buffer, &width, &height);
-
- if (csd == NULL) {
- return;
- }
-
- meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
- meta->setInt32(kKeyWidth, width);
- meta->setInt32(kKeyHeight, height);
- } else {
- CHECK_EQ(mStreamType, 0x0fu);
-
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
-
- int32_t sampleRate, channelCount;
- sp<ABuffer> csd =
- FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount);
-
- LOGV("sampleRate = %d", sampleRate);
- LOGV("channelCount = %d", channelCount);
-
- meta->setInt32(kKeySampleRate, sampleRate);
- meta->setInt32(kKeyChannelCount, channelCount);
-
- meta->setData(kKeyESDS, 0, csd->data(), csd->size());
- }
-
- LOGV("created source!");
- mSource = new AnotherPacketSource(meta);
-
- // fall through
- }
-
CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
- buffer->meta()->setInt64("time", (PTS * 100) / 9);
+ int64_t timeUs = (PTS * 100) / 9;
- if (mStreamType == 0x0f) {
- extractAACFrames(buffer);
- }
+ status_t err = mQueue.appendData(data, size, timeUs);
+ CHECK_EQ(err, (status_t)OK);
- mSource->queueAccessUnit(buffer);
-}
+ sp<ABuffer> accessUnit;
+ while ((accessUnit = mQueue.dequeueAccessUnit()) != NULL) {
+ if (mSource == NULL) {
+ sp<MetaData> meta = mQueue.getFormat();
-// Disassemble one or more ADTS frames into their constituent parts and
-// leave only the concatenated raw_data_blocks in the buffer.
-void ATSParser::Stream::extractAACFrames(const sp<ABuffer> &buffer) {
- size_t dstOffset = 0;
-
- size_t offset = 0;
- while (offset < buffer->size()) {
- CHECK_LE(offset + 7, buffer->size());
-
- ABitReader bits(buffer->data() + offset, buffer->size() - offset);
-
- // adts_fixed_header
-
- CHECK_EQ(bits.getBits(12), 0xfffu);
- bits.skipBits(3); // ID, layer
- bool protection_absent = bits.getBits(1) != 0;
-
- // profile_ObjectType, sampling_frequency_index, private_bits,
- // channel_configuration, original_copy, home
- bits.skipBits(12);
-
- // adts_variable_header
-
- // copyright_identification_bit, copyright_identification_start
- bits.skipBits(2);
-
- unsigned aac_frame_length = bits.getBits(13);
-
- bits.skipBits(11); // adts_buffer_fullness
-
- unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
-
- if (number_of_raw_data_blocks_in_frame == 0) {
- size_t scan = offset + aac_frame_length;
-
- offset += 7;
- if (!protection_absent) {
- offset += 2;
+ if (meta != NULL) {
+ LOGV("created source!");
+ mSource = new AnotherPacketSource(meta);
+ mSource->queueAccessUnit(accessUnit);
}
-
- CHECK_LE(scan, buffer->size());
-
- LOGV("found aac raw data block at [0x%08x ; 0x%08x)", offset, scan);
-
- memmove(&buffer->data()[dstOffset], &buffer->data()[offset],
- scan - offset);
-
- dstOffset += scan - offset;
- offset = scan;
} else {
- // To be implemented.
- TRESPASS();
+ mSource->queueAccessUnit(accessUnit);
}
}
- CHECK_EQ(offset, buffer->size());
-
- buffer->setRange(buffer->offset(), dstOffset);
}
sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 3544b4c..4dfc0f7 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -5,6 +5,7 @@
LOCAL_SRC_FILES:= \
AnotherPacketSource.cpp \
ATSParser.cpp \
+ ESQueue.cpp \
MPEG2TSExtractor.cpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
new file mode 100644
index 0000000..d87040b
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -0,0 +1,504 @@
+/*
+ * 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 "ESQueue"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "ESQueue.h"
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+
+#include "include/avc_utils.h"
+
+namespace android {
+
+ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
+ : mMode(mode) {
+}
+
+sp<MetaData> ElementaryStreamQueue::getFormat() {
+ return mFormat;
+}
+
+static status_t getNextNALUnit(
+ const uint8_t **_data, size_t *_size,
+ const uint8_t **nalStart, size_t *nalSize,
+ bool startCodeFollows = false) {
+ const uint8_t *data = *_data;
+ size_t size = *_size;
+
+ *nalStart = NULL;
+ *nalSize = 0;
+
+ if (size == 0) {
+ return -EAGAIN;
+ }
+
+ // Skip any number of leading 0x00.
+
+ size_t offset = 0;
+ while (offset < size && data[offset] == 0x00) {
+ ++offset;
+ }
+
+ if (offset == size) {
+ return -EAGAIN;
+ }
+
+ // A valid startcode consists of at least two 0x00 bytes followed by 0x01.
+
+ if (offset < 2 || data[offset] != 0x01) {
+ return ERROR_MALFORMED;
+ }
+
+ ++offset;
+
+ size_t startOffset = offset;
+
+ for (;;) {
+ while (offset < size && data[offset] != 0x01) {
+ ++offset;
+ }
+
+ if (offset == size) {
+ if (startCodeFollows) {
+ offset = size + 2;
+ break;
+ }
+
+ return -EAGAIN;
+ }
+
+ if (data[offset - 1] == 0x00 && data[offset - 2] == 0x00) {
+ break;
+ }
+
+ ++offset;
+ }
+
+ size_t endOffset = offset - 2;
+ while (data[endOffset - 1] == 0x00) {
+ --endOffset;
+ }
+
+ *nalStart = &data[startOffset];
+ *nalSize = endOffset - startOffset;
+
+ if (offset + 2 < size) {
+ *_data = &data[offset - 2];
+ *_size = size - offset + 2;
+ } else {
+ *_data = NULL;
+ *_size = 0;
+ }
+
+ return OK;
+}
+
+status_t ElementaryStreamQueue::appendData(
+ const void *data, size_t size, int64_t timeUs) {
+ if (mBuffer == NULL || mBuffer->size() == 0) {
+ switch (mMode) {
+ case H264:
+ {
+ if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
+ return ERROR_MALFORMED;
+ }
+ break;
+ }
+
+ case AAC:
+ {
+ uint8_t *ptr = (uint8_t *)data;
+
+ if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
+ return ERROR_MALFORMED;
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+ }
+
+ size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
+ if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
+ neededSize = (neededSize + 65535) & ~65535;
+
+ LOGI("resizing buffer to size %d", neededSize);
+
+ sp<ABuffer> buffer = new ABuffer(neededSize);
+ if (mBuffer != NULL) {
+ memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
+ buffer->setRange(0, mBuffer->size());
+ } else {
+ buffer->setRange(0, 0);
+ }
+
+ mBuffer = buffer;
+ }
+
+ memcpy(mBuffer->data() + mBuffer->size(), data, size);
+ mBuffer->setRange(0, mBuffer->size() + size);
+
+ mTimestamps.push_back(timeUs);
+
+ return OK;
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
+ if (mMode == H264) {
+ return dequeueAccessUnitH264();
+ } else {
+ CHECK_EQ((unsigned)mMode, (unsigned)AAC);
+ return dequeueAccessUnitAAC();
+ }
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
+ Vector<size_t> frameOffsets;
+ Vector<size_t> frameSizes;
+ size_t auSize = 0;
+
+ size_t offset = 0;
+ while (offset + 7 <= mBuffer->size()) {
+ ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset);
+
+ // adts_fixed_header
+
+ CHECK_EQ(bits.getBits(12), 0xfffu);
+ bits.skipBits(3); // ID, layer
+ bool protection_absent = bits.getBits(1) != 0;
+
+ if (mFormat == NULL) {
+ unsigned profile = bits.getBits(2);
+ CHECK_NE(profile, 3u);
+ unsigned sampling_freq_index = bits.getBits(4);
+ bits.getBits(1); // private_bit
+ unsigned channel_configuration = bits.getBits(3);
+ CHECK_NE(channel_configuration, 0u);
+ bits.skipBits(2); // original_copy, home
+
+ mFormat = MakeAACCodecSpecificData(
+ profile, sampling_freq_index, channel_configuration);
+ } else {
+ // profile_ObjectType, sampling_frequency_index, private_bits,
+ // channel_configuration, original_copy, home
+ bits.skipBits(12);
+ }
+
+ // adts_variable_header
+
+ // copyright_identification_bit, copyright_identification_start
+ bits.skipBits(2);
+
+ unsigned aac_frame_length = bits.getBits(13);
+
+ bits.skipBits(11); // adts_buffer_fullness
+
+ unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
+
+ if (number_of_raw_data_blocks_in_frame != 0) {
+ // To be implemented.
+ TRESPASS();
+ }
+
+ if (offset + aac_frame_length > mBuffer->size()) {
+ break;
+ }
+
+ size_t headerSize = protection_absent ? 7 : 9;
+
+ frameOffsets.push(offset + headerSize);
+ frameSizes.push(aac_frame_length - headerSize);
+ auSize += aac_frame_length - headerSize;
+
+ offset += aac_frame_length;
+ }
+
+ if (offset == 0) {
+ return NULL;
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(auSize);
+ size_t dstOffset = 0;
+ for (size_t i = 0; i < frameOffsets.size(); ++i) {
+ memcpy(accessUnit->data() + dstOffset,
+ mBuffer->data() + frameOffsets.itemAt(i),
+ frameSizes.itemAt(i));
+
+ dstOffset += frameSizes.itemAt(i);
+ }
+
+ memmove(mBuffer->data(), mBuffer->data() + offset,
+ mBuffer->size() - offset);
+ mBuffer->setRange(0, mBuffer->size() - offset);
+
+ CHECK_GT(mTimestamps.size(), 0u);
+ int64_t timeUs = *mTimestamps.begin();
+ mTimestamps.erase(mTimestamps.begin());
+
+ accessUnit->meta()->setInt64("time", timeUs);
+
+ return accessUnit;
+}
+
+// static
+sp<MetaData> ElementaryStreamQueue::MakeAACCodecSpecificData(
+ unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration) {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+ CHECK_LE(sampling_freq_index, 11u);
+ static const int32_t kSamplingFreq[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000
+ };
+ meta->setInt32(kKeySampleRate, kSamplingFreq[sampling_freq_index]);
+ meta->setInt32(kKeyChannelCount, channel_configuration);
+
+ static const uint8_t kStaticESDS[] = {
+ 0x03, 22,
+ 0x00, 0x00, // ES_ID
+ 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+ 0x04, 17,
+ 0x40, // Audio ISO/IEC 14496-3
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x05, 2,
+ // AudioSpecificInfo follows
+
+ // oooo offf fccc c000
+ // o - audioObjectType
+ // f - samplingFreqIndex
+ // c - channelConfig
+ };
+ sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
+ memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
+
+ csd->data()[sizeof(kStaticESDS)] =
+ ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+ csd->data()[sizeof(kStaticESDS) + 1] =
+ ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+ meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+
+ return meta;
+}
+
+struct NALPosition {
+ size_t nalOffset;
+ size_t nalSize;
+};
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
+ const uint8_t *data = mBuffer->data();
+ size_t size = mBuffer->size();
+
+ Vector<NALPosition> nals;
+
+ size_t totalSize = 0;
+
+ status_t err;
+ const uint8_t *nalStart;
+ size_t nalSize;
+ bool foundSlice = false;
+ while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
+ CHECK_GT(nalSize, 0u);
+
+ unsigned nalType = nalStart[0] & 0x1f;
+ bool flush = false;
+
+ if (nalType == 1 || nalType == 5) {
+ if (foundSlice) {
+ ABitReader br(nalStart + 1, nalSize);
+ unsigned first_mb_in_slice = parseUE(&br);
+
+ if (first_mb_in_slice == 0) {
+ // This slice starts a new frame.
+
+ flush = true;
+ }
+ }
+
+ foundSlice = true;
+ } else if ((nalType == 9 || nalType == 7) && foundSlice) {
+ // Access unit delimiter and SPS will be associated with the
+ // next frame.
+
+ flush = true;
+ }
+
+ if (flush) {
+ // The access unit will contain all nal units up to, but excluding
+ // the current one, separated by 0x00 0x00 0x00 0x01 startcodes.
+
+ size_t auSize = 4 * nals.size() + totalSize;
+ sp<ABuffer> accessUnit = new ABuffer(auSize);
+
+#if !LOG_NDEBUG
+ AString out;
+#endif
+
+ size_t dstOffset = 0;
+ for (size_t i = 0; i < nals.size(); ++i) {
+ const NALPosition &pos = nals.itemAt(i);
+
+ unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
+
+#if !LOG_NDEBUG
+ char tmp[128];
+ sprintf(tmp, "0x%02x", nalType);
+ if (i > 0) {
+ out.append(", ");
+ }
+ out.append(tmp);
+#endif
+
+ memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4);
+
+ memcpy(accessUnit->data() + dstOffset + 4,
+ mBuffer->data() + pos.nalOffset,
+ pos.nalSize);
+
+ dstOffset += pos.nalSize + 4;
+ }
+
+ LOGV("accessUnit contains nal types %s", out.c_str());
+
+ const NALPosition &pos = nals.itemAt(nals.size() - 1);
+ size_t nextScan = pos.nalOffset + pos.nalSize;
+
+ memmove(mBuffer->data(),
+ mBuffer->data() + nextScan,
+ mBuffer->size() - nextScan);
+
+ mBuffer->setRange(0, mBuffer->size() - nextScan);
+
+ CHECK_GT(mTimestamps.size(), 0u);
+ int64_t timeUs = *mTimestamps.begin();
+ mTimestamps.erase(mTimestamps.begin());
+
+ accessUnit->meta()->setInt64("time", timeUs);
+
+ if (mFormat == NULL) {
+ mFormat = MakeAVCCodecSpecificData(accessUnit);
+ }
+
+ return accessUnit;
+ }
+
+ NALPosition pos;
+ pos.nalOffset = nalStart - mBuffer->data();
+ pos.nalSize = nalSize;
+
+ nals.push(pos);
+
+ totalSize += nalSize;
+ }
+ CHECK_EQ(err, (status_t)-EAGAIN);
+
+ return NULL;
+}
+
+static sp<ABuffer> FindNAL(
+ const uint8_t *data, size_t size, unsigned nalType,
+ size_t *stopOffset) {
+ const uint8_t *nalStart;
+ size_t nalSize;
+ while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+ if ((nalStart[0] & 0x1f) == nalType) {
+ sp<ABuffer> buffer = new ABuffer(nalSize);
+ memcpy(buffer->data(), nalStart, nalSize);
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+sp<MetaData> ElementaryStreamQueue::MakeAVCCodecSpecificData(
+ const sp<ABuffer> &accessUnit) {
+ const uint8_t *data = accessUnit->data();
+ size_t size = accessUnit->size();
+
+ sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+ if (seqParamSet == NULL) {
+ return NULL;
+ }
+
+ int32_t width, height;
+ FindAVCDimensions(seqParamSet, &width, &height);
+
+ size_t stopOffset;
+ sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+ CHECK(picParamSet != NULL);
+
+ size_t csdSize =
+ 1 + 3 + 1 + 1
+ + 2 * 1 + seqParamSet->size()
+ + 1 + 2 * 1 + picParamSet->size();
+
+ sp<ABuffer> csd = new ABuffer(csdSize);
+ uint8_t *out = csd->data();
+
+ *out++ = 0x01; // configurationVersion
+ memcpy(out, seqParamSet->data() + 1, 3); // profile/level...
+ out += 3;
+ *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
+ *out++ = 0xe0 | 1;
+
+ *out++ = seqParamSet->size() >> 8;
+ *out++ = seqParamSet->size() & 0xff;
+ memcpy(out, seqParamSet->data(), seqParamSet->size());
+ out += seqParamSet->size();
+
+ *out++ = 1;
+
+ *out++ = picParamSet->size() >> 8;
+ *out++ = picParamSet->size() & 0xff;
+ memcpy(out, picParamSet->data(), picParamSet->size());
+
+#if 0
+ LOGI("AVC seq param set");
+ hexdump(seqParamSet->data(), seqParamSet->size());
+#endif
+
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+ meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+ meta->setInt32(kKeyWidth, width);
+ meta->setInt32(kKeyHeight, height);
+
+ return meta;
+}
+
+} // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
new file mode 100644
index 0000000..d2e87f2
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -0,0 +1,66 @@
+/*
+ * 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 ES_QUEUE_H_
+
+#define ES_QUEUE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct ABuffer;
+struct MetaData;
+
+struct ElementaryStreamQueue {
+ enum Mode {
+ H264,
+ AAC
+ };
+ ElementaryStreamQueue(Mode mode);
+
+ status_t appendData(const void *data, size_t size, int64_t timeUs);
+
+ sp<ABuffer> dequeueAccessUnit();
+
+ sp<MetaData> getFormat();
+
+private:
+ Mode mMode;
+
+ sp<ABuffer> mBuffer;
+ List<int64_t> mTimestamps;
+
+ sp<MetaData> mFormat;
+
+ sp<ABuffer> dequeueAccessUnitH264();
+ sp<ABuffer> dequeueAccessUnitAAC();
+
+ static sp<MetaData> MakeAACCodecSpecificData(
+ unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration);
+
+ static sp<MetaData> MakeAVCCodecSpecificData(
+ const sp<ABuffer> &accessUnit);
+
+ DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
+};
+
+} // namespace android
+
+#endif // ES_QUEUE_H_
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 2417305..c5257bb 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -157,7 +157,7 @@
}
}
- if (++numPacketsParsed > 1500) {
+ if (++numPacketsParsed > 2500) {
break;
}
}
diff --git a/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png b/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png
new file mode 100644
index 0000000..f70f079
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png b/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png
new file mode 100644
index 0000000..f70f079
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 12d1d5c..c3f4205 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -57,7 +57,7 @@
style="?android:attr/buttonStyle"
android:paddingLeft="15dp"
android:paddingRight="15dp"
- android:background="@drawable/btn_default_small"
+ android:background="@android:drawable/btn_default_small"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_latest_event.xml b/packages/SystemUI/res/layout/status_bar_latest_event.xml
index 65c731b..b8a1cbe 100644
--- a/packages/SystemUI/res/layout/status_bar_latest_event.xml
+++ b/packages/SystemUI/res/layout/status_bar_latest_event.xml
@@ -17,7 +17,7 @@
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/divider_horizontal_dark_opaque"
+ android:background="@drawable/divider_horizontal_light_opaque"
/>
</LinearLayout>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 384f527..538dae9 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1500,7 +1500,9 @@
}
if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW
- && win.fillsScreenLw(mW, mH, false, false)) {
+ && attrs.x == 0 && attrs.y == 0
+ && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+ && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d6ee075..8e5cdc2 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1599,20 +1599,23 @@
addObbState(obbState);
}
- final MessageDigest md;
- try {
- md = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Could not load MD5 algorithm", e);
+ String hashedKey = null;
+ if (key != null) {
+ final MessageDigest md;
try {
- token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
- } catch (RemoteException e1) {
- Slog.d(TAG, "Could not send unmount notification for: " + filename);
+ md = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Could not load MD5 algorithm", e);
+ try {
+ token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
+ } catch (RemoteException e1) {
+ Slog.d(TAG, "Could not send unmount notification for: " + filename);
+ }
+ return;
}
- return;
- }
- String hashedKey = HexDump.toHexString(md.digest(key.getBytes()));
+ hashedKey = HexDump.toHexString(md.digest(key.getBytes()));
+ }
ObbAction action = new MountObbAction(obbState, hashedKey);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
@@ -1956,10 +1959,6 @@
throw new IllegalArgumentException("Caller package does not match OBB file");
}
- if (mKey == null) {
- mKey = "none";
- }
-
boolean mounted = false;
int rc;
synchronized (mObbState) {
@@ -1969,7 +1968,8 @@
}
rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
+ String cmd = String.format("obb mount %s %s %d", mObbState.filename,
+ mKey != null ? mKey : "none",
mObbState.callerUid);
try {
mConnector.doCommand(cmd);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d7a3596..713524a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6965,31 +6965,6 @@
&& (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
}
- public boolean fillsScreenLw(int screenWidth, int screenHeight,
- boolean shownFrame, boolean onlyOpaque) {
- if (mSurface == null) {
- return false;
- }
- if (mAppToken != null && !mAppToken.appFullscreen) {
- return false;
- }
- if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
- return false;
- }
- final Rect frame = shownFrame ? mShownFrame : mFrame;
-
- if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
- return frame.left <= mCompatibleScreenFrame.left &&
- frame.top <= mCompatibleScreenFrame.top &&
- frame.right >= mCompatibleScreenFrame.right &&
- frame.bottom >= mCompatibleScreenFrame.bottom;
- } else {
- return frame.left <= 0 && frame.top <= 0
- && frame.right >= screenWidth
- && frame.bottom >= screenHeight;
- }
- }
-
/**
* Return true if the window is opaque and fully drawn. This indicates
* it may obscure windows behind it.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 6f52f24..6b3df38 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -182,7 +182,6 @@
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation);
- virtual void virtualKeyDownFeedback();
virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags);
virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
@@ -464,17 +463,6 @@
return android_server_PowerManagerService_isScreenBright();
}
-void NativeInputManager::virtualKeyDownFeedback() {
-#if DEBUG_INPUT_READER_POLICY
- LOGD("virtualKeyDownFeedback");
-#endif
-
- JNIEnv* env = jniEnv();
-
- env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
- checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
-}
-
int32_t NativeInputManager::interceptKey(nsecs_t when,
int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
#if DEBUG_INPUT_READER_POLICY
@@ -483,6 +471,12 @@
when, deviceId, down, keyCode, scanCode, policyFlags);
#endif
+ if (down && (policyFlags & POLICY_FLAG_VIRTUAL)) {
+ JNIEnv* env = jniEnv();
+ env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
+ checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
+ }
+
const int32_t WM_ACTION_PASS_TO_USER = 1;
const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
const int32_t WM_ACTION_GO_TO_SLEEP = 4;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 7c3508f..09b7d05 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -861,6 +861,25 @@
}
/**
+ * Enables or disables echo suppression.
+ */
+ public void setEchoSuppressionEnabled(boolean enabled) {
+ if (VDBG) {
+ Log.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
+ Log.d(LOG_TAG, this.toString());
+ }
+
+ if (hasActiveFgCall()) {
+ getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
+ }
+
+ if (VDBG) {
+ Log.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
+ Log.d(LOG_TAG, this.toString());
+ }
+ }
+
+ /**
* Play a DTMF tone on the active call.
*
* @param c should be one of 0-9, '*' or '#'. Other values will be
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 9afade3..d5791eb 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1169,6 +1169,11 @@
boolean getMute();
/**
+ * Enables or disables echo suppression.
+ */
+ void setEchoSuppressionEnabled(boolean enabled);
+
+ /**
* Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation.
*
* @param data The data for the request.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index ff28773..53503a53 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -505,6 +505,10 @@
mCM.unregisterForResendIncallMute(h);
}
+ public void setEchoSuppressionEnabled(boolean enabled) {
+ // no need for regular phone
+ }
+
/**
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index e1511e6..6f08868 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -568,6 +568,10 @@
return mActivePhone.getMute();
}
+ public void setEchoSuppressionEnabled(boolean enabled) {
+ mActivePhone.setEchoSuppressionEnabled(enabled);
+ }
+
public void invokeOemRilRequestRaw(byte[] data, Message response) {
mActivePhone.invokeOemRilRequestRaw(data, response);
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index af3e0886..e3c3d65 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -327,6 +327,20 @@
Log.e(LOG_TAG, "call waiting not supported");
}
+ @Override
+ public void setEchoSuppressionEnabled(boolean enabled) {
+ synchronized (SipPhone.class) {
+ AudioGroup audioGroup = foregroundCall.getAudioGroup();
+ if (audioGroup == null) return;
+ int mode = audioGroup.getMode();
+ audioGroup.setMode(enabled
+ ? AudioGroup.MODE_ECHO_SUPPRESSION
+ : AudioGroup.MODE_NORMAL);
+ Log.d(LOG_TAG, String.format("audioGroup mode change: %d --> %d",
+ mode, audioGroup.getMode()));
+ }
+ }
+
public void setMute(boolean muted) {
synchronized (SipPhone.class) {
foregroundCall.setMute(muted);
diff --git a/tools/obbtool/mkobb.sh b/tools/obbtool/mkobb.sh
index 1987696..ba5256f 100755
--- a/tools/obbtool/mkobb.sh
+++ b/tools/obbtool/mkobb.sh
@@ -161,11 +161,10 @@
while true; do \
case "$1" in
- -c) use_crypto=1; shift;;
-d) directory=$2; shift 2;;
-h) usage; exit 1;;
- -k) key=$2; shift 2;;
- -K) prompt_key=1; shift;;
+ -k) key=$2; use_crypto=1; shift 2;;
+ -K) prompt_key=1; use_crypto=1; shift;;
-v) verbose=1; shift;;
-o) filename=$2; shift 2;;
--) shift; break;;