Merge "Support for 64-bit integer type."
diff --git a/api/current.xml b/api/current.xml
index 403820d..84407e0 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -6928,6 +6928,17 @@
visibility="public"
>
</field>
+<field name="loopViews"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843592"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="manageSpaceActivity"
type="int"
transient="false"
@@ -61109,6 +61120,16 @@
visibility="public"
>
</field>
+<field name="filename"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="flags"
type="int"
transient="false"
@@ -139862,7 +139883,7 @@
visibility="public"
>
<method name="allowThreadDiskReads"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
abstract="false"
native="false"
synchronized="false"
@@ -139873,7 +139894,7 @@
>
</method>
<method name="allowThreadDiskWrites"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
abstract="false"
native="false"
synchronized="false"
@@ -139884,7 +139905,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"
@@ -139904,86 +139936,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"
@@ -140545,8 +140804,6 @@
</parameter>
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
-<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
-</exception>
</method>
<method name="unregisterListener"
return="void"
@@ -189612,6 +189869,217 @@
>
</field>
</class>
+<class name="DragEvent"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAction"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getClipData"
+ return="android.content.ClipData"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getClipDescription"
+ return="android.content.ClipDescription"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="obtain"
+ return="android.view.DragEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="obtain"
+ return="android.view.DragEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="action" type="int">
+</parameter>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="description" type="android.content.ClipDescription">
+</parameter>
+<parameter name="data" type="android.content.ClipData">
+</parameter>
+</method>
+<method name="recycle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="ACTION_DRAG_ENDED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DRAG_ENTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DRAG_EXITED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DRAG_LOCATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DRAG_STARTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DROP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="FocusFinder"
extends="java.lang.Object"
abstract="false"
@@ -198568,6 +199036,19 @@
<parameter name="hint" type="int">
</parameter>
</method>
+<method name="dispatchDragEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.DragEvent">
+</parameter>
+</method>
<method name="dispatchDraw"
return="void"
abstract="false"
@@ -200533,6 +201014,19 @@
<parameter name="hint" type="int">
</parameter>
</method>
+<method name="onDragEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="event" type="android.view.DragEvent">
+</parameter>
+</method>
<method name="onDraw"
return="void"
abstract="false"
@@ -200546,6 +201040,19 @@
<parameter name="canvas" type="android.graphics.Canvas">
</parameter>
</method>
+<method name="onDrawDragThumbnail"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="canvas" type="android.graphics.Canvas">
+</parameter>
+</method>
<method name="onDrawScrollBars"
return="void"
abstract="false"
@@ -200739,6 +201246,17 @@
<parameter name="heightMeasureSpec" type="int">
</parameter>
</method>
+<method name="onMeasureDragThumbnail"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
<method name="onRestoreInstanceState"
return="void"
abstract="false"
@@ -201404,6 +201922,21 @@
<parameter name="contentDescription" type="java.lang.CharSequence">
</parameter>
</method>
+<method name="setDragThumbnailDimension"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+</method>
<method name="setDrawingCacheBackgroundColor"
return="void"
abstract="false"
@@ -249475,7 +250008,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/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 6ce5b86..bc5e10d 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -17,32 +17,21 @@
#include <unistd.h>
#include <fcntl.h>
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
#include <binder/IMemory.h>
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
using namespace android;
int main(int argc, char** argv)
{
- const String16 name("SurfaceFlinger");
- sp<ISurfaceComposer> composer;
- if (getService(name, &composer) != NO_ERROR)
+ ScreenshotClient screenshot;
+ if (screenshot.update() != NO_ERROR)
return 0;
- sp<IMemoryHeap> heap;
- uint32_t w, h;
- PixelFormat f;
- status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
- if (err != NO_ERROR)
- return 0;
-
- uint8_t* base = (uint8_t*)heap->getBase();
+ void const* base = screenshot.getPixels();
+ uint32_t w = screenshot.getWidth();
+ uint32_t h = screenshot.getHeight();
+ uint32_t f = screenshot.getFormat();
int fd = dup(STDOUT_FILENO);
write(fd, &w, 4);
write(fd, &h, 4);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 9a97284..cbdf119 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -53,6 +53,31 @@
LOCAL_SRC_FILES:= \
SineSource.cpp \
+ recordvideo.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright liblog libutils libbinder
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= recordvideo
+
+include $(BUILD_EXECUTABLE)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
new file mode 100644
index 0000000..330fbc2
--- /dev/null
+++ b/cmds/stagefright/recordvideo.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SineSource.h"
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/MediaPlayerInterface.h>
+
+using namespace android;
+
+// print usage showing how to use this utility to record videos
+static void usage(const char *me) {
+ fprintf(stderr, "usage: %s\n", me);
+ fprintf(stderr, " -h(elp)\n");
+ fprintf(stderr, " -b bit rate in bits per second (default 300000)\n");
+ fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar (default 1)\n");
+ fprintf(stderr, " -f frame rate in frames per second (default 30)\n");
+ fprintf(stderr, " -i I frame interval in seconds (default 1)\n");
+ fprintf(stderr, " -n number of frames to be recorded (default 300)\n");
+ fprintf(stderr, " -w width in pixels (default 176)\n");
+ fprintf(stderr, " -t height in pixels (default 144)\n");
+ fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default 0)\n");
+ exit(1);
+}
+
+class DummySource : public MediaSource {
+
+public:
+ DummySource(int width, int height, int nFrames, int fps, int colorFormat)
+ : mWidth(width),
+ mHeight(height),
+ mMaxNumFrames(nFrames),
+ mFrameRate(fps),
+ mColorFormat(colorFormat),
+ mSize((width * height * 3) / 2) {
+ mGroup.add_buffer(new MediaBuffer(mSize));
+
+ // Check the color format to make sure
+ // that the buffer size mSize it set correctly above.
+ CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
+ colorFormat == OMX_COLOR_FormatYUV420Planar);
+ }
+
+ virtual sp<MetaData> getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setInt32(kKeyColorFormat, mColorFormat);
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+
+ return meta;
+ }
+
+ virtual status_t start(MetaData *params) {
+ mNumFramesOutput = 0;
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(
+ MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+
+ if (mNumFramesOutput % 10 == 0) {
+ fprintf(stderr, ".");
+ }
+ if (mNumFramesOutput == mMaxNumFrames) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ status_t err = mGroup.acquire_buffer(buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ char x = (char)((double)rand() / RAND_MAX * 255);
+ memset((*buffer)->data(), x, mSize);
+ (*buffer)->set_range(0, mSize);
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt64(
+ kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate);
+ ++mNumFramesOutput;
+
+ return OK;
+ }
+
+protected:
+ virtual ~DummySource() {}
+
+private:
+ MediaBufferGroup mGroup;
+ int mWidth, mHeight;
+ int mMaxNumFrames;
+ int mFrameRate;
+ int mColorFormat;
+ size_t mSize;
+ int64_t mNumFramesOutput;;
+
+ DummySource(const DummySource &);
+ DummySource &operator=(const DummySource &);
+};
+
+sp<MediaSource> createSource(const char *filename) {
+ sp<MediaSource> source;
+
+ sp<MediaExtractor> extractor =
+ MediaExtractor::Create(new FileSource(filename));
+ if (extractor == NULL) {
+ return NULL;
+ }
+
+ size_t num_tracks = extractor->countTracks();
+
+ sp<MetaData> meta;
+ for (size_t i = 0; i < num_tracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
+ CHECK(meta.get() != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ if (strncasecmp(mime, "video/", 6)) {
+ continue;
+ }
+
+ source = extractor->getTrack(i);
+ break;
+ }
+
+ return source;
+}
+
+enum {
+ kYUV420SP = 0,
+ kYUV420P = 1,
+};
+
+// returns -1 if mapping of the given color is unsuccessful
+// returns an omx color enum value otherwise
+static int translateColorToOmxEnumValue(int color) {
+ switch (color) {
+ case kYUV420SP:
+ return OMX_COLOR_FormatYUV420SemiPlanar;
+ case kYUV420P:
+ return OMX_COLOR_FormatYUV420Planar;
+ default:
+ fprintf(stderr, "Unsupported color: %d\n", color);
+ return -1;
+ }
+}
+
+int main(int argc, char **argv) {
+
+ // Default values for the program if not overwritten
+ int frameRateFps = 30;
+ int width = 176;
+ int height = 144;
+ int bitRateBps = 300000;
+ int iFramesIntervalSeconds = 1;
+ int colorFormat = OMX_COLOR_FormatYUV420Planar;
+ int nFrames = 300;
+ int codec = 0;
+ const char *fileName = "/sdcard/output.mp4";
+
+ android::ProcessState::self()->startThreadPool();
+ int res;
+ while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:v:o:h")) >= 0) {
+ switch (res) {
+ case 'b':
+ {
+ bitRateBps = atoi(optarg);
+ break;
+ }
+
+ case 'c':
+ {
+ colorFormat = translateColorToOmxEnumValue(atoi(optarg));
+ if (colorFormat == -1) {
+ usage(argv[0]);
+ }
+ break;
+ }
+
+ case 'f':
+ {
+ frameRateFps = atoi(optarg);
+ break;
+ }
+
+ case 'i':
+ {
+ iFramesIntervalSeconds = atoi(optarg);
+ break;
+ }
+
+ case 'n':
+ {
+ nFrames = atoi(optarg);
+ break;
+ }
+
+ case 'w':
+ {
+ width = atoi(optarg);
+ break;
+ }
+
+ case 't':
+ {
+ height = atoi(optarg);
+ break;
+ }
+
+ case 'v':
+ {
+ codec = atoi(optarg);
+ if (codec < 0 || codec > 2) {
+ usage(argv[0]);
+ }
+ break;
+ }
+
+ case 'h':
+ default:
+ {
+ usage(argv[0]);
+ break;
+ }
+ }
+ }
+
+ OMXClient client;
+ CHECK_EQ(client.connect(), OK);
+
+ status_t err = OK;
+ sp<MediaSource> decoder = new DummySource(width, height, nFrames, frameRateFps, colorFormat);
+
+ sp<MetaData> enc_meta = new MetaData;
+ switch (codec) {
+ case 1:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ break;
+ case 2:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+ break;
+ default:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ break;
+ }
+ enc_meta->setInt32(kKeyWidth, width);
+ enc_meta->setInt32(kKeyHeight, height);
+ enc_meta->setInt32(kKeySampleRate, frameRateFps);
+ enc_meta->setInt32(kKeyBitRate, bitRateBps);
+ enc_meta->setInt32(kKeyStride, width);
+ enc_meta->setInt32(kKeySliceHeight, height);
+ enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
+ enc_meta->setInt32(kKeyColorFormat, colorFormat);
+
+ sp<MediaSource> encoder =
+ OMXCodec::Create(
+ client.interface(), enc_meta, true /* createEncoder */, decoder);
+
+ sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
+ writer->addSource(encoder);
+ int64_t start = systemTime();
+ CHECK_EQ(OK, writer->start());
+ while (!writer->reachedEOS()) {
+ }
+ err = writer->stop();
+ int64_t end = systemTime();
+
+ printf("$\n");
+ client.disconnect();
+
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ fprintf(stderr, "record failed: %d\n", err);
+ return 1;
+ }
+ fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
+ fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
+ return 0;
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b8bbc88..df18ce7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3352,7 +3352,7 @@
while (i.hasNext()) {
ProviderInfo cpi = i.next();
StringBuilder buf = new StringBuilder(128);
- buf.append("Publishing provider ");
+ buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 0398b36..013032c 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) {
@@ -923,7 +929,11 @@
if (destinationType == Downloads.Impl.DESTINATION_EXTERNAL) {
// return stored destination for legacy external download
- return Uri.fromFile(new File(getUnderlyingString(Downloads.Impl._DATA))).toString();
+ String localPath = getUnderlyingString(Downloads.Impl._DATA);
+ if (localPath == null) {
+ return null;
+ }
+ return Uri.fromFile(new File(localPath)).toString();
}
// return content URI for cache download
diff --git a/core/java/android/bluetooth/AtCommandResult.java b/core/java/android/bluetooth/AtCommandResult.java
index 638be2d..375a6dd 100644
--- a/core/java/android/bluetooth/AtCommandResult.java
+++ b/core/java/android/bluetooth/AtCommandResult.java
@@ -16,8 +16,6 @@
package android.bluetooth;
-import java.util.*;
-
/**
* The result of execution of an single AT command.<p>
*
diff --git a/core/java/android/bluetooth/AtParser.java b/core/java/android/bluetooth/AtParser.java
index 1ea3150..328fb2b 100644
--- a/core/java/android/bluetooth/AtParser.java
+++ b/core/java/android/bluetooth/AtParser.java
@@ -16,16 +16,13 @@
package android.bluetooth;
-import android.bluetooth.AtCommandHandler;
-import android.bluetooth.AtCommandResult;
-
import java.util.*;
/**
* An AT (Hayes command) Parser based on (a subset of) the ITU-T V.250 standard.
* <p>
*
- * Conforment with the subset of V.250 required for implementation of the
+ * Conformant with the subset of V.250 required for implementation of the
* Bluetooth Headset and Handsfree Profiles, as per Bluetooth SIP
* specifications. Also implements some V.250 features not required by
* Bluetooth - such as chained commands.<p>
@@ -48,7 +45,7 @@
* are no arguments for get commands.
* <li>Set Command. For example "AT+VGM=14". The command name is "VGM", and
* there is a single integer argument in this case. In the general case then
- * can be zero or more arguments (comma deliminated) each of integer or string
+ * can be zero or more arguments (comma delimited) each of integer or string
* form.
* <li>Test Command. For example "AT+VGM=?. No arguments.
* </ul>
@@ -60,7 +57,7 @@
* headset/handsfree use this is acceptable, because they only use the basic
* commands ATA and ATD, which are not allowed to be chained. For general V.250
* use we would need to improve this class to allow Basic command chaining -
- * however its tricky to get right becuase there is no deliminator for Basic
+ * however it's tricky to get right because there is no delimiter for Basic
* command chaining.<p>
*
* Extended commands can be chained. For example:<p>
@@ -71,7 +68,7 @@
* AT+CIMI
* Except that only one final result code is return (although several
* intermediate responses may be returned), and as soon as one command in the
- * chain fails the rest are abandonded.<p>
+ * chain fails the rest are abandoned.<p>
*
* Handlers are registered by there command name via register(Char c, ...) or
* register(String s, ...). Handlers for Basic command should be registered by
@@ -80,7 +77,7 @@
*
* Refer to:<ul>
* <li>ITU-T Recommendation V.250
- * <li>ETSI TS 127.007 (AT Comannd set for User Equipment, 3GPP TS 27.007)
+ * <li>ETSI TS 127.007 (AT Command set for User Equipment, 3GPP TS 27.007)
* <li>Bluetooth Headset Profile Spec (K6)
* <li>Bluetooth Handsfree Profile Spec (HFP 1.5)
* </ul>
@@ -188,7 +185,7 @@
}
/**
- * Break an argument string into individual arguments (comma deliminated).
+ * Break an argument string into individual arguments (comma delimited).
* Integer arguments are turned into Integer objects. Otherwise a String
* object is used.
*/
@@ -212,7 +209,7 @@
}
/**
- * Return the index of the end of character after the last characeter in
+ * Return the index of the end of character after the last character in
* the extended command name. Uses the V.250 spec for allowed command
* names.
*/
@@ -244,7 +241,7 @@
* Processes an incoming AT command line.<p>
* This method will invoke zero or one command handler methods for each
* command in the command line.<p>
- * @param raw_input The AT input, without EOL deliminator (e.g. <CR>).
+ * @param raw_input The AT input, without EOL delimiter (e.g. <CR>).
* @return Result object for this command line. This can be
* converted to a String[] response with toStrings().
*/
@@ -297,8 +294,8 @@
if (c == '+') {
// Option 2: Extended Command
- // Search for first non-name character. Shortcircuit if we dont
- // handle this command name.
+ // Search for first non-name character. Short-circuit if
+ // we don't handle this command name.
int i = findEndExtendedName(input, index + 1);
String commandName = input.substring(index, i);
if (!mExtHandlers.containsKey(commandName)) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 21a4bd6..c66b2de 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -341,7 +341,7 @@
private static final int ADDRESS_LENGTH = 17;
/**
- * Lazyily initialized singleton. Guaranteed final after first object
+ * Lazily initialized singleton. Guaranteed final after first object
* constructed.
*/
private static BluetoothAdapter sAdapter;
@@ -466,7 +466,7 @@
* user action to turn off Bluetooth.
* <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
* system services, and powers down the underlying Bluetooth hardware.
- * <p class="caution"><strong>Bluetooth should never be disbled without
+ * <p class="caution"><strong>Bluetooth should never be disabled without
* direct user consent</strong>. The {@link #disable()} method is
* provided only for applications that include a user interface for changing
* system settings, such as a "power manager" app.</p>
@@ -932,8 +932,8 @@
public Pair<byte[], byte[]> readOutOfBandData() {
if (getState() != STATE_ON) return null;
try {
- byte[] hash = new byte[16];
- byte[] randomizer = new byte[16];
+ byte[] hash;
+ byte[] randomizer;
byte[] ret = mService.readOutOfBandData();
diff --git a/core/java/android/bluetooth/BluetoothAudioGateway.java b/core/java/android/bluetooth/BluetoothAudioGateway.java
index bc32060..9351393 100644
--- a/core/java/android/bluetooth/BluetoothAudioGateway.java
+++ b/core/java/android/bluetooth/BluetoothAudioGateway.java
@@ -23,7 +23,7 @@
import android.util.Log;
/**
- * Listen's for incoming RFCOMM connection for the headset / handsfree service.
+ * Listens for incoming RFCOMM connection for the headset / handsfree service.
*
* TODO: Use the new generic BluetoothSocket class instead of this legacy code
*
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index c8381c9..e604e6b 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -34,8 +34,8 @@
* Bluetooth profiles or services are actually supported by a device. Accurate
* service discovery is done through SDP requests, which are automatically
* performed when creating an RFCOMM socket with {@link
- * BluetoothDevice#createRfcommSocketToServiceRecord(UUID)} and {@link
- * BluetoothAdapter#listenUsingRfcommWithServiceRecord(String,UUID)}</p>
+ * BluetoothDevice#createRfcommSocketToServiceRecord} and {@link
+ * BluetoothAdapter#listenUsingRfcommWithServiceRecord}</p>
*
* <p>Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for
* a remote device.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e577ec4..ada3c24 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -32,7 +32,7 @@
/**
* Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
- * create a connection with the repective device or query information about
+ * create a connection with the respective device or query information about
* it, such as the name, address, class, and bonding state.
*
* <p>This class is really just a thin wrapper for a Bluetooth hardware
@@ -48,7 +48,7 @@
* {@link BluetoothAdapter}) or get one from the set of bonded devices
* returned by {@link BluetoothAdapter#getBondedDevices()
* BluetoothAdapter.getBondedDevices()}. You can then open a
- * {@link BluetoothSocket} for communciation with the remote device, using
+ * {@link BluetoothSocket} for communication with the remote device, using
* {@link #createRfcommSocketToServiceRecord(UUID)}.
*
* <p class="note"><strong>Note:</strong>
@@ -226,8 +226,8 @@
* <p>A shared link keys exists locally for the remote device, so
* communication can be authenticated and encrypted.
* <p><i>Being bonded (paired) with a remote device does not necessarily
- * mean the device is currently connected. It just means that the ponding
- * procedure was compeleted at some earlier time, and the link key is still
+ * mean the device is currently connected. It just means that the pending
+ * procedure was completed at some earlier time, and the link key is still
* stored locally, ready to use on the next connection.
* </i>
*/
@@ -283,7 +283,7 @@
* not respond to pin request in time
* @hide */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
- /** A bond attempt failed because the other side explicilty rejected
+ /** A bond attempt failed because the other side explicitly rejected
* bonding
* @hide */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
@@ -515,7 +515,7 @@
* Cancel an in-progress bonding request started with {@link #createBond}.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
- * @return true on sucess, false on error
+ * @return true on success, false on error
* @hide
*/
public boolean cancelBondProcess() {
@@ -532,7 +532,7 @@
* authentication and encryption.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
- * @return true on sucess, false on error
+ * @return true on success, false on error
* @hide
*/
public boolean removeBond() {
@@ -617,7 +617,7 @@
* with the UUIDs supported by the remote end. If there is an error
* in getting the SDP records or if the process takes a long time,
* an Intent is sent with the UUIDs that is currently present in the
- * cache. Clients should use the {@link getUuids} to get UUIDs
+ * cache. Clients should use the {@link #getUuids} to get UUIDs
* is SDP is not to be performed.
*
* @return False if the sanity check fails, True if the process
@@ -693,7 +693,7 @@
* outgoing connection to this remote device on given channel.
* <p>The remote device will be authenticated and communication on this
* socket will be encrypted.
- * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid RFCOMM channels are in range 1 to 30.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
@@ -715,7 +715,7 @@
* <p>This is designed to be used with {@link
* BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
* Bluetooth applications.
- * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection. This will also perform an SDP lookup of the given uuid to
* determine which channel to connect to.
* <p>The remote device will be authenticated and communication on this
@@ -772,9 +772,9 @@
/**
* Check that a pin is valid and convert to byte array.
*
- * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
+ * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
* @param pin pin as java String
- * @return the pin code as a UTF8 byte array, or null if it is an invalid
+ * @return the pin code as a UTF-8 byte array, or null if it is an invalid
* Bluetooth pin.
* @hide
*/
@@ -784,9 +784,9 @@
}
byte[] pinBytes;
try {
- pinBytes = pin.getBytes("UTF8");
+ pinBytes = pin.getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
- Log.e(TAG, "UTF8 not supported?!?"); // this should not happen
+ Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen
return null;
}
if (pinBytes.length <= 0 || pinBytes.length > 16) {
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java
index 7415721..c794be2 100644
--- a/core/java/android/bluetooth/BluetoothDevicePicker.java
+++ b/core/java/android/bluetooth/BluetoothDevicePicker.java
@@ -36,7 +36,8 @@
/**
* Broadcast when one BT device is selected from BT device picker screen.
- * Selected BT device address is contained in extra string {@link BluetoothIntent}
+ * Selected {@link BluetoothDevice} is returned in extra data named
+ * {@link BluetoothDevice#EXTRA_DEVICE}.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DEVICE_SELECTED =
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index b48f48e..4be077c 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -197,7 +197,7 @@
/**
* Disconnects the current Pbap client (PCE). Currently this call blocks,
- * it may soon be made asynchornous. Returns false if this proxy object is
+ * it may soon be made asynchronous. Returns false if this proxy object is
* not currently connected to the Pbap service.
*/
public boolean disconnect() {
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index c9c6c0a..83e59e2 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -29,14 +29,14 @@
* side, use a {@link BluetoothServerSocket} to create a listening server
* socket. When a connection is accepted by the {@link BluetoothServerSocket},
* it will return a new {@link BluetoothSocket} to manage the connection.
- * On the client side, use a single {@link BluetoothSocket} to both intiate
+ * On the client side, use a single {@link BluetoothSocket} to both initiate
* an outgoing connection and to manage the connection.
*
* <p>The most common type of Bluetooth socket is RFCOMM, which is the type
* supported by the Android APIs. RFCOMM is a connection-oriented, streaming
* transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
*
- * <p>To create a listenting {@link BluetoothServerSocket} that's ready for
+ * <p>To create a listening {@link BluetoothServerSocket} that's ready for
* incoming connections, use
* {@link BluetoothAdapter#listenUsingRfcommWithServiceRecord
* BluetoothAdapter.listenUsingRfcommWithServiceRecord()}. Then call
@@ -70,7 +70,7 @@
* @param encrypt require the connection to be encrypted
* @param port remote port
* @throws IOException On error, for example Bluetooth not available, or
- * insufficient priveleges
+ * insufficient privileges
*/
/*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
throws IOException {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index ad03399..719d730 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -35,7 +35,7 @@
* side, use a {@link BluetoothServerSocket} to create a listening server
* socket. When a connection is accepted by the {@link BluetoothServerSocket},
* it will return a new {@link BluetoothSocket} to manage the connection.
- * On the client side, use a single {@link BluetoothSocket} to both intiate
+ * On the client side, use a single {@link BluetoothSocket} to both initiate
* an outgoing connection and to manage the connection.
*
* <p>The most common type of Bluetooth socket is RFCOMM, which is the type
@@ -113,7 +113,7 @@
* @param port remote port
* @param uuid SDP uuid
* @throws IOException On error, for example Bluetooth not available, or
- * insufficient priveleges
+ * insufficient privileges
*/
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
@@ -158,7 +158,7 @@
* @param address remote device that this socket can connect to
* @param port remote port
* @throws IOException On error, for example Bluetooth not available, or
- * insufficient priveleges
+ * insufficient privileges
*/
private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
int port) throws IOException {
@@ -226,7 +226,7 @@
}
// all native calls are guaranteed to immediately return after
- // abortNative(), so this lock should immediatley acquire
+ // abortNative(), so this lock should immediately acquire
mLock.writeLock().lock();
try {
mClosed = true;
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/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8ef639b..eaf1e33 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1730,6 +1730,11 @@
XmlUtils.skipCurrentTag(parser);
+ } else if (tagName.equals("uses-package")) {
+ // Dependencies for app installers; we don't currently try to
+ // enforce this.
+ XmlUtils.skipCurrentTag(parser);
+
} else {
if (!RIGID_PARSER) {
Log.w(TAG, "Unknown element under <application>: " + tagName
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index d0ba590..406b091 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -18,6 +18,7 @@
import android.content.pm.ApplicationInfo;
import android.graphics.Canvas;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.DisplayMetrics;
@@ -363,6 +364,17 @@
}
/**
+ * Translate a Point in screen coordinates into the app window's coordinates.
+ */
+ public void translatePointInScreenToAppWindow(PointF point) {
+ final float scale = applicationInvertedScale;
+ if (scale != 1.0f) {
+ point.x *= scale;
+ point.y *= scale;
+ }
+ }
+
+ /**
* Translate the location of the sub window.
* @param params
*/
diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java
index 7b962e5..5d6ed44 100644
--- a/core/java/android/content/res/ObbInfo.java
+++ b/core/java/android/content/res/ObbInfo.java
@@ -29,6 +29,11 @@
public static final int OBB_OVERLAY = 1 << 0;
/**
+ * The canonical filename of the OBB.
+ */
+ public String filename;
+
+ /**
* The name of the package to which the OBB file belongs.
*/
public String packageName;
@@ -66,6 +71,7 @@
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(filename);
dest.writeString(packageName);
dest.writeInt(version);
dest.writeInt(flags);
@@ -83,6 +89,7 @@
};
private ObbInfo(Parcel source) {
+ filename = source.readString();
packageName = source.readString();
version = source.readInt();
flags = source.readInt();
diff --git a/core/java/android/content/res/ObbScanner.java b/core/java/android/content/res/ObbScanner.java
index 572b75e..1b38eea 100644
--- a/core/java/android/content/res/ObbScanner.java
+++ b/core/java/android/content/res/ObbScanner.java
@@ -45,9 +45,14 @@
throw new IllegalArgumentException("OBB file does not exist: " + filePath);
}
+ /*
+ * XXX This will fail to find the real canonical path if bind mounts are
+ * used, but we don't use any bind mounts right now.
+ */
final String canonicalFilePath = obbFile.getCanonicalPath();
ObbInfo obbInfo = new ObbInfo();
+ obbInfo.filename = canonicalFilePath;
getObbInfo_native(canonicalFilePath, obbInfo);
return obbInfo;
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 6ed1a90..a7ad757 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;
/**
@@ -106,11 +107,13 @@
// but if the database itself is not closed and is GC'ed, then
// all sub-objects attached to the database could end up getting GC'ed too.
// in that case, don't print any warning.
- if (mInUse) {
+ if (mInUse && StrictMode.vmSqliteObjectLeaksEnabled()) {
int len = mSqlStmt.length();
- Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
- "that you explicitly call close() on your cursor: " +
- mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
+ 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);
}
releaseSqlStatement();
} finally {
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index fa7763d..89e8ab7 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -25,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
+import android.os.StrictMode;
import android.util.Config;
import android.util.Log;
@@ -505,11 +506,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 = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable +
", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len),
mStackTrace);
+ }
close();
SQLiteDebug.notifyActiveCursorFinalized();
} else {
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 3df8ec0..ad7289d 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -45,7 +45,7 @@
public class MobileDataStateTracker implements NetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private Phone.DataState mMobileDataState;
private ITelephony mPhoneService;
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/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4268618..8554ece 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -424,7 +424,6 @@
* @param key secret used to encrypt the OBB; may be <code>null</code> if no
* encryption was used on the OBB.
* @return whether the mount call was successfully queued or not
- * @throws IllegalArgumentException when the OBB is already mounted
*/
public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
try {
@@ -458,10 +457,8 @@
* @param force whether to kill any programs using this in order to unmount
* it
* @return whether the unmount call was successfully queued or not
- * @throws IllegalArgumentException when OBB is not already mounted
*/
- public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener)
- throws IllegalArgumentException {
+ public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener) {
try {
mObbActionListener.addListener(listener);
mMountService.unmountObb(filename, force, mObbActionListener);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index d2620d7..4edc01f 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -39,7 +39,7 @@
/**
* TODO: Move this to
* java/services/com/android/server/BluetoothEventLoop.java
- * and make the contructor package private again.
+ * and make the constructor package private again.
*
* @hide
*/
@@ -754,7 +754,7 @@
private void onRestartRequired() {
if (mBluetoothService.isEnabled()) {
- Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
+ Log.e(TAG, "*** A serious error occurred (did bluetoothd crash?) - " +
"restarting Bluetooth ***");
mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index bd105a7..f8caa2c 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -500,7 +500,7 @@
// forked multiple times in a row, probably because there is
// some race in sdptool or bluez when operated in parallel.
// As a workaround, delay 500ms between each fork of sdptool.
- // TODO: Don't fork sdptool in order to regsiter service
+ // TODO: Don't fork sdptool in order to register service
// records, use a DBUS call instead.
switch (msg.arg1) {
case 1:
@@ -713,7 +713,7 @@
/** local cache of bonding state.
/* we keep our own state to track the intermediate state BONDING, which
/* bluez does not track.
- * All addreses must be passed in upper case.
+ * All addresses must be passed in upper case.
*/
public class BondState {
private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
@@ -976,7 +976,7 @@
}
}
- // This function adds a bluetooth address to the auto pairing blacklis
+ // This function adds a bluetooth address to the auto pairing blacklist
// file. These addresses are added to DynamicAddressBlacklistSection
private void updateAutoPairingData(String address) {
BufferedWriter out = null;
@@ -1106,7 +1106,7 @@
* a device discoverable; you need to call setMode() to make the device
* explicitly discoverable.
*
- * @param timeout_s The discoverable timeout in seconds.
+ * @param timeout The discoverable timeout in seconds.
*/
public synchronized boolean setDiscoverableTimeout(int timeout) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
@@ -2565,12 +2565,12 @@
/*package*/ String getAddressFromObjectPath(String objectPath) {
String adapterObjectPath = getPropertyInternal("ObjectPath");
if (adapterObjectPath == null || objectPath == null) {
- Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
" or deviceObjectPath:" + objectPath + " is null");
return null;
}
if (!objectPath.startsWith(adapterObjectPath)) {
- Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
" is not a prefix of deviceObjectPath:" + objectPath +
"bluetoothd crashed ?");
return null;
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/DragEvent.aidl b/core/java/android/view/DragEvent.aidl
new file mode 100644
index 0000000..f08943f
--- /dev/null
+++ b/core/java/android/view/DragEvent.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 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.view;
+
+parcelable DragEvent;
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
new file mode 100644
index 0000000..47c6d3c
--- /dev/null
+++ b/core/java/android/view/DragEvent.java
@@ -0,0 +1,186 @@
+/*
+ * 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.view;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** !!! TODO: real docs */
+public class DragEvent implements Parcelable {
+ private static final boolean TRACK_RECYCLED_LOCATION = false;
+
+ int mAction;
+ float mX, mY;
+ ClipDescription mClipDescription;
+ ClipData mClipData;
+
+ private DragEvent mNext;
+ private RuntimeException mRecycledLocation;
+ private boolean mRecycled;
+
+ private static final int MAX_RECYCLED = 10;
+ private static final Object gRecyclerLock = new Object();
+ private static int gRecyclerUsed = 0;
+ private static DragEvent gRecyclerTop = null;
+
+ /**
+ * action constants for DragEvent dispatch
+ */
+ public static final int ACTION_DRAG_STARTED = 1;
+ public static final int ACTION_DRAG_LOCATION = 2;
+ public static final int ACTION_DROP = 3;
+ public static final int ACTION_DRAG_ENDED = 4;
+ public static final int ACTION_DRAG_ENTERED = 5;
+ public static final int ACTION_DRAG_EXITED = 6;
+
+ /* hide the constructor behind package scope */
+ DragEvent() {
+ }
+
+ public static DragEvent obtain() {
+ return DragEvent.obtain(0, 0f, 0f, null, null);
+ }
+
+ public static DragEvent obtain(int action, float x, float y,
+ ClipDescription description, ClipData data) {
+ final DragEvent ev;
+ synchronized (gRecyclerLock) {
+ if (gRecyclerTop == null) {
+ return new DragEvent();
+ }
+ ev = gRecyclerTop;
+ gRecyclerTop = ev.mNext;
+ gRecyclerUsed -= 1;
+ }
+ ev.mRecycledLocation = null;
+ ev.mRecycled = false;
+ ev.mNext = null;
+
+ ev.mAction = action;
+ ev.mX = x;
+ ev.mY = y;
+ ev.mClipDescription = description;
+ ev.mClipData = data;
+
+ return ev;
+ }
+
+ public int getAction() {
+ return mAction;
+ }
+
+ public float getX() {
+ return mX;
+ }
+
+ public float getY() {
+ return mY;
+ }
+
+ public ClipData getClipData() {
+ return mClipData;
+ }
+
+ public ClipDescription getClipDescription() {
+ return mClipDescription;
+ }
+
+ /**
+ * Recycle the DragEvent, to be re-used by a later caller. After calling
+ * this function you must never touch the event again.
+ */
+ public final void recycle() {
+ // Ensure recycle is only called once!
+ if (TRACK_RECYCLED_LOCATION) {
+ if (mRecycledLocation != null) {
+ throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
+ }
+ mRecycledLocation = new RuntimeException("Last recycled here");
+ } else {
+ if (mRecycled) {
+ throw new RuntimeException(toString() + " recycled twice!");
+ }
+ mRecycled = true;
+ }
+
+ mClipData = null;
+ mClipDescription = null;
+
+ synchronized (gRecyclerLock) {
+ if (gRecyclerUsed < MAX_RECYCLED) {
+ gRecyclerUsed++;
+ mNext = gRecyclerTop;
+ gRecyclerTop = this;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
+ + " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
+ + " data=" + mClipData
+ + "}";
+ }
+
+ /* Parcelable interface */
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAction);
+ dest.writeFloat(mX);
+ dest.writeFloat(mY);
+ if (mClipData == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ mClipData.writeToParcel(dest, flags);
+ }
+ if (mClipDescription == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ mClipDescription.writeToParcel(dest, flags);
+ }
+ }
+
+ public static final Parcelable.Creator<DragEvent> CREATOR =
+ new Parcelable.Creator<DragEvent>() {
+ public DragEvent createFromParcel(Parcel in) {
+ DragEvent event = DragEvent.obtain();
+ event.mAction = in.readInt();
+ event.mX = in.readFloat();
+ event.mY = in.readFloat();
+ if (in.readInt() != 0) {
+ event.mClipData = ClipData.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
+ }
+ return event;
+ }
+
+ public DragEvent[] newArray(int size) {
+ return new DragEvent[size];
+ }
+ };
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 921018a..6b9cda0 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,10 +17,13 @@
package android.view;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -64,4 +67,9 @@
void dispatchWallpaperCommand(String action, int x, int y,
int z, in Bundle extras, boolean sync);
+
+ /**
+ * Drag/drop events
+ */
+ void dispatchDragEvent(in DragEvent event);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7f10b76..79ea5b6 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -17,6 +17,7 @@
package android.view;
+import android.content.ClipData;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -116,6 +117,30 @@
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
/**
+ * Allocate the drag's thumbnail surface. Also assigns a token that identifies
+ * the drag to the OS and passes that as the return value. A return value of
+ * null indicates failure.
+ */
+ IBinder prepareDrag(IWindow window, boolean localOnly,
+ int thumbnailWidth, int thumbnailHeight, out Surface outSurface);
+
+ /**
+ * Initiate the drag operation itself
+ */
+ boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
+ float thumbCenterX, float thumbCenterY, in ClipData data);
+
+ /**
+ * Tell the OS that we've just dragged into a View that is willing to accept the drop
+ */
+ void dragRecipientEntered(IWindow window);
+
+ /**
+ * Tell the OS that we've just dragged *off* of a View that was willing to accept the drop
+ */
+ void dragRecipientExited(IWindow window);
+
+ /**
* For windows with the wallpaper behind them, and the wallpaper is
* larger than the screen, set the offset within the screen.
* For multi screen launcher type applications, xstep and ystep indicate
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f2d134b..4c01f4f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,7 @@
package android.view;
+import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -614,6 +615,7 @@
*/
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
private static final boolean DBG = false;
+ static final boolean DEBUG_DRAG = true;
/**
* The logging tag used by this class with android.util.Log.
@@ -1681,7 +1683,7 @@
* The transform matrix for the View. This transform is calculated internally
* based on the rotation, scaleX, and scaleY properties. The identity matrix
* is used by default. Do *not* use this variable directly; instead call
- * getMatrix(), which will automatically recalculate the matrix if necessary
+ * getInverseMatrix(), which will automatically recalculate the matrix if necessary
* to get the correct matrix based on the latest rotation and scale properties.
*/
private Matrix mInverseMatrix;
@@ -1704,7 +1706,8 @@
* A variable that tracks whether we need to recalculate the
* transform matrix, based on whether the rotation or scaleX/Y properties
* have changed since the matrix was last calculated. This variable
- * is only valid after a call to getMatrix().
+ * is only valid after a call to updateMatrix() or to a function that
+ * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
*/
private boolean mMatrixIsIdentity = true;
@@ -2030,6 +2033,14 @@
private int mTouchSlop;
/**
+ * Cache drag/drop state
+ *
+ */
+ boolean mCanAcceptDrop;
+ private int mThumbnailWidth;
+ private int mThumbnailHeight;
+
+ /**
* Simple constructor to use when creating a view from code.
*
* @param context The Context the view is running in, through which it can
@@ -5108,7 +5119,7 @@
* @return The current transform matrix for the view
*/
public Matrix getMatrix() {
- hasIdentityMatrix();
+ updateMatrix();
return mMatrix;
}
@@ -5123,11 +5134,20 @@
}
/**
- * Recomputes the transform matrix if necessary.
+ * Returns true if the transform matrix is the identity matrix.
+ * Recomputes the matrix if necessary.
*
* @return True if the transform matrix is the identity matrix, false otherwise.
*/
- boolean hasIdentityMatrix() {
+ final boolean hasIdentityMatrix() {
+ updateMatrix();
+ return mMatrixIsIdentity;
+ }
+
+ /**
+ * Recomputes the transform matrix if necessary.
+ */
+ private final void updateMatrix() {
if (mMatrixDirty) {
// transform-related properties have changed since the last time someone
// asked for the matrix; recalculate it with the current values
@@ -5166,7 +5186,6 @@
mMatrixIsIdentity = mMatrix.isIdentity();
mInverseMatrixDirty = true;
}
- return mMatrixIsIdentity;
}
/**
@@ -5176,7 +5195,8 @@
*
* @return The inverse of the current matrix of this view.
*/
- Matrix getInverseMatrix() {
+ final Matrix getInverseMatrix() {
+ updateMatrix();
if (mInverseMatrixDirty) {
if (mInverseMatrix == null) {
mInverseMatrix = new Matrix();
@@ -5209,11 +5229,11 @@
public void setRotation(float rotation) {
if (mRotation != rotation) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mRotation = rotation;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5240,11 +5260,11 @@
public void setRotationY(float rotationY) {
if (mRotationY != rotationY) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mRotationY = rotationY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5271,11 +5291,11 @@
public void setRotationX(float rotationX) {
if (mRotationX != rotationX) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mRotationX = rotationX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5304,11 +5324,11 @@
public void setScaleX(float scaleX) {
if (mScaleX != scaleX) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mScaleX = scaleX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5337,11 +5357,11 @@
public void setScaleY(float scaleY) {
if (mScaleY != scaleY) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mScaleY = scaleY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5376,11 +5396,11 @@
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
if (mPivotX != pivotX) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mPivotX = pivotX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5414,11 +5434,11 @@
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
if (mPivotY != pivotY) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mPivotY = pivotY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5441,8 +5461,12 @@
*/
public void setAlpha(float alpha) {
mAlpha = alpha;
- onSetAlpha((int) (alpha * 255));
- invalidate();
+ if (onSetAlpha((int) (alpha * 255))) {
+ // subclass is handling alpha - don't optimize rendering cache invalidation
+ invalidate();
+ } else {
+ invalidate(false);
+ }
}
/**
@@ -5464,7 +5488,8 @@
*/
public final void setTop(int top) {
if (top != mTop) {
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5485,8 +5510,13 @@
invalidate();
}
+ int width = mRight - mLeft;
+ int oldHeight = mBottom - mTop;
+
mTop = top;
+ onSizeChanged(width, mBottom - mTop, width, oldHeight);
+
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate();
@@ -5513,7 +5543,8 @@
*/
public final void setBottom(int bottom) {
if (bottom != mBottom) {
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5531,8 +5562,13 @@
invalidate();
}
+ int width = mRight - mLeft;
+ int oldHeight = mBottom - mTop;
+
mBottom = bottom;
+ onSizeChanged(width, mBottom - mTop, width, oldHeight);
+
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate();
@@ -5559,8 +5595,8 @@
*/
public final void setLeft(int left) {
if (left != mLeft) {
- System.out.println("view " + this + " left = " + left);
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5581,12 +5617,18 @@
invalidate();
}
+ int oldWidth = mRight - mLeft;
+ int height = mBottom - mTop;
+
mLeft = left;
+ onSizeChanged(mRight - mLeft, height, oldWidth, height);
+
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate();
}
+
}
}
@@ -5609,7 +5651,8 @@
*/
public final void setRight(int right) {
if (right != mRight) {
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5627,8 +5670,13 @@
invalidate();
}
+ int oldWidth = mRight - mLeft;
+ int height = mBottom - mTop;
+
mRight = right;
+ onSizeChanged(mRight - mLeft, height, oldWidth, height);
+
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate();
@@ -5703,11 +5751,11 @@
public void setTranslationX(float translationX) {
if (mTranslationX != translationX) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mTranslationX = translationX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5734,11 +5782,11 @@
public void setTranslationY(float translationY) {
if (mTranslationY != translationY) {
// Double-invalidation is necessary to capture view's old and new areas
- invalidate();
+ invalidate(false);
mTranslationY = translationY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
@@ -5748,13 +5796,13 @@
* @param outRect The hit rectangle of the view.
*/
public void getHitRect(Rect outRect) {
- if (hasIdentityMatrix() || mAttachInfo == null) {
+ updateMatrix();
+ if (mMatrixIsIdentity || mAttachInfo == null) {
outRect.set(mLeft, mTop, mRight, mBottom);
} else {
- Matrix m = getMatrix();
final RectF tmpRect = mAttachInfo.mTmpTransformRect;
tmpRect.set(-mPivotX, -mPivotY, getWidth() - mPivotX, getHeight() - mPivotY);
- m.mapRect(tmpRect);
+ mMatrix.mapRect(tmpRect);
outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
(int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
}
@@ -5840,7 +5888,8 @@
*/
public void offsetTopAndBottom(int offset) {
if (offset != 0) {
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5860,7 +5909,7 @@
p.invalidateChild(this, r);
}
} else {
- invalidate();
+ invalidate(false);
}
mTop += offset;
@@ -5868,7 +5917,7 @@
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
}
@@ -5880,7 +5929,8 @@
*/
public void offsetLeftAndRight(int offset) {
if (offset != 0) {
- if (hasIdentityMatrix()) {
+ updateMatrix();
+ if (mMatrixIsIdentity) {
final ViewParent p = mParent;
if (p != null && mAttachInfo != null) {
final Rect r = mAttachInfo.mTmpInvalRect;
@@ -5897,7 +5947,7 @@
p.invalidateChild(this, r);
}
} else {
- invalidate();
+ invalidate(false);
}
mLeft += offset;
@@ -5905,7 +5955,7 @@
if (!mMatrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
- invalidate();
+ invalidate(false);
}
}
}
@@ -6203,12 +6253,30 @@
* UI thread. To call from a non-UI thread, call {@link #postInvalidate()}.
*/
public void invalidate() {
+ invalidate(true);
+ }
+
+ /**
+ * This is where the invalidate() work actually happens. A full invalidate()
+ * causes the drawing cache to be invalidated, but this function can be called with
+ * invalidateCache set to false to skip that invalidation step for cases that do not
+ * need it (for example, a component that remains at the same dimensions with the same
+ * content).
+ *
+ * @param invalidateCache Whether the drawing cache for this view should be invalidated as
+ * well. This is usually true for a full invalidate, but may be set to false if the
+ * View's contents or dimensions have not changed.
+ */
+ private void invalidate(boolean invalidateCache) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
}
if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
- mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~DRAWN;
+ if (invalidateCache) {
+ mPrivateFlags &= ~DRAWING_CACHE_VALID;
+ }
final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
if (p != null && ai != null) {
@@ -9762,6 +9830,140 @@
}
/**
+ * Drag and drop. App calls startDrag(), then callbacks to onMeasureDragThumbnail()
+ * and onDrawDragThumbnail() happen, then the drag operation is handed over to the
+ * OS.
+ * !!! TODO: real docs
+ * @hide
+ */
+ public final boolean startDrag(ClipData data, float touchX, float touchY,
+ float thumbnailTouchX, float thumbnailTouchY, boolean myWindowOnly) {
+ if (DEBUG_DRAG) {
+ Log.d(VIEW_LOG_TAG, "startDrag: touch=(" + touchX + "," + touchY
+ + ") thumb=(" + thumbnailTouchX + "," + thumbnailTouchY
+ + ") data=" + data + " local=" + myWindowOnly);
+ }
+ boolean okay = false;
+
+ measureThumbnail(); // throws if the view fails to specify dimensions
+
+ Surface surface = new Surface();
+ try {
+ IBinder token = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
+ myWindowOnly, mThumbnailWidth, mThumbnailHeight, surface);
+ if (DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token
+ + " surface=" + surface);
+ if (token != null) {
+ Canvas canvas = surface.lockCanvas(null);
+ try {
+ onDrawDragThumbnail(canvas);
+ } finally {
+ surface.unlockCanvasAndPost(canvas);
+ }
+
+ okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
+ touchX, touchY, thumbnailTouchX, thumbnailTouchY, data);
+ if (DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+ }
+ } catch (Exception e) {
+ Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
+ surface.destroy();
+ }
+
+ return okay;
+ }
+
+ private void measureThumbnail() {
+ mPrivateFlags &= ~MEASURED_DIMENSION_SET;
+
+ onMeasureDragThumbnail();
+
+ // flag not set, setDragThumbnailDimension() was not invoked, we raise
+ // an exception to warn the developer
+ if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
+ throw new IllegalStateException("onMeasureDragThumbnail() did not set the"
+ + " measured dimension by calling setDragThumbnailDimension()");
+ }
+
+ if (DEBUG_DRAG) {
+ Log.d(VIEW_LOG_TAG, "Drag thumb measured: w=" + mThumbnailWidth
+ + " h=" + mThumbnailHeight);
+ }
+ }
+
+ /**
+ * The View must call this method from onMeasureDragThumbnail() in order to
+ * specify the dimensions of the drag thumbnail image.
+ *
+ * @param width The desired thumbnail width.
+ * @param height The desired thumbnail height.
+ */
+ protected final void setDragThumbnailDimension(int width, int height) {
+ mPrivateFlags |= MEASURED_DIMENSION_SET;
+ mThumbnailWidth = width;
+ mThumbnailHeight = height;
+ }
+
+ /**
+ * The default implementation specifies a drag thumbnail that matches the
+ * View's current size and appearance.
+ */
+ protected void onMeasureDragThumbnail() {
+ setDragThumbnailDimension(getWidth(), getHeight());
+ }
+
+ /**
+ * The default implementation just draws the current View appearance as the thumbnail
+ * @param canvas
+ */
+ protected void onDrawDragThumbnail(Canvas canvas) {
+ draw(canvas);
+ }
+
+ /**
+ * Drag-and-drop event dispatch. The event.getAction() verb is one of the DragEvent
+ * constants DRAG_STARTED_EVENT, DRAG_EVENT, DROP_EVENT, and DRAG_ENDED_EVENT.
+ *
+ * For DRAG_STARTED_EVENT, event.getClipDescription() describes the content
+ * being dragged. onDragEvent() should return 'true' if the view can handle
+ * a drop of that content. A view that returns 'false' here will receive no
+ * further calls to onDragEvent() about the drag/drop operation.
+ *
+ * For DRAG_ENTERED, event.getClipDescription() describes the content being
+ * dragged. This will be the same content description passed in the
+ * DRAG_STARTED_EVENT invocation.
+ *
+ * For DRAG_EXITED, event.getClipDescription() describes the content being
+ * dragged. This will be the same content description passed in the
+ * DRAG_STARTED_EVENT invocation. The view should return to its approriate
+ * drag-acceptance visual state.
+ *
+ * For DRAG_LOCATION_EVENT, event.getX() and event.getY() give the location in View
+ * coordinates of the current drag point. The view must return 'true' if it
+ * can accept a drop of the current drag content, false otherwise.
+ *
+ * For DROP_EVENT, event.getX() and event.getY() give the location of the drop
+ * within the view; also, event.getClipData() returns the full data payload
+ * being dropped. The view should return 'true' if it consumed the dropped
+ * content, 'false' if it did not.
+ *
+ * For DRAG_ENDED_EVENT, the 'event' argument may be null. The view should return
+ * to its normal visual state.
+ */
+ protected boolean onDragEvent(DragEvent event) {
+ return false;
+ }
+
+ /**
+ * Views typically don't need to override dispatchDragEvent(); it just calls
+ * onDragEvent(what, event) and passes the result up appropriately.
+ *
+ */
+ public boolean dispatchDragEvent(DragEvent event) {
+ return onDragEvent(event);
+ }
+
+ /**
* This needs to be a better API (NOT ON VIEW) before it is exposed. If
* it is ever exposed at all.
* @hide
@@ -9829,30 +10031,6 @@
ViewConfiguration.getLongPressTimeout() - delayOffset);
}
- private static int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2) {
- final int stateSet1Length = stateSet1.length;
- final int stateSet2Length = stateSet2.length;
- final int[] newSet = new int[stateSet1Length + stateSet2Length];
- int k = 0;
- int i = 0;
- int j = 0;
- // This is a merge of the two input state sets and assumes that the
- // input sets are sorted by the order imposed by ViewDrawableStates.
- for (int viewState : R.styleable.ViewDrawableStates) {
- if (i < stateSet1Length && stateSet1[i] == viewState) {
- newSet[k++] = viewState;
- i++;
- } else if (j < stateSet2Length && stateSet2[j] == viewState) {
- newSet[k++] = viewState;
- j++;
- }
- if (k > 1) {
- assert(newSet[k - 1] > newSet[k - 2]);
- }
- }
- return newSet;
- }
-
/**
* Inflate a view from an XML resource. This convenience method wraps the {@link
* LayoutInflater} class, which provides a full range of options for view inflation.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1e86f74..8a3db38 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -19,6 +19,8 @@
import android.animation.LayoutTransition;
import com.android.internal.R;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -26,6 +28,7 @@
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -33,6 +36,7 @@
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
@@ -68,6 +72,7 @@
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
private static final boolean DBG = false;
+ private static final String TAG = "ViewGroup";
/**
* Views which have been hidden or removed which need to be animated on
@@ -105,6 +110,15 @@
*/
private Transformation mInvalidationTransformation;
+ // View currently under an ongoing drag
+ private View mCurrentDragView;
+
+ // Does this group have a child that can accept the current drag payload?
+ private boolean mChildAcceptsDrag;
+
+ // Used during drag dispatch
+ private final PointF mLocalPoint = new PointF();
+
// Layout animation
private LayoutAnimationController mLayoutAnimationController;
private Animation.AnimationListener mAnimationListener;
@@ -815,6 +829,136 @@
/**
* {@inheritDoc}
+ *
+ * !!! TODO: write real docs
+ */
+ @Override
+ public boolean dispatchDragEvent(DragEvent event) {
+ boolean retval = false;
+ final float tx = event.mX;
+ final float ty = event.mY;
+
+ // !!! BUGCHECK: If we have a ViewGroup, we must necessarily have a ViewRoot,
+ // so we don't need to check getRootView() for null here?
+ ViewRoot root = (ViewRoot)(getRootView().getParent());
+
+ // Dispatch down the view hierarchy
+ switch (event.mAction) {
+ case DragEvent.ACTION_DRAG_STARTED: {
+ // clear state to recalculate which views we drag over
+ root.setDragFocus(event, null);
+
+ // Now dispatch down to our children, caching the responses
+ mChildAcceptsDrag = false;
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ final boolean handled = children[i].dispatchDragEvent(event);
+ children[i].mCanAcceptDrop = handled;
+ if (handled) {
+ mChildAcceptsDrag = true;
+ }
+ }
+
+ // Return HANDLED if one of our children can accept the drag
+ if (mChildAcceptsDrag) {
+ retval = true;
+ }
+ } break;
+
+ case DragEvent.ACTION_DRAG_ENDED: {
+ // Notify all of our children that the drag is over
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchDragEvent(event);
+ }
+ // We consider drag-ended to have been handled if one of our children
+ // had offered to handle the drag.
+ if (mChildAcceptsDrag) {
+ retval = true;
+ }
+ } break;
+
+ case DragEvent.ACTION_DRAG_LOCATION: {
+ // Find the [possibly new] drag target
+ final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
+
+ // If we've changed apparent drag target, tell the view root which view
+ // we're over now. This will in turn send out DRAG_ENTERED / DRAG_EXITED
+ // notifications as appropriate.
+ if (mCurrentDragView != target) {
+ root.setDragFocus(event, target);
+ mCurrentDragView = target;
+ }
+
+ // Dispatch the actual drag location notice, localized into its coordinates
+ if (target != null) {
+ event.mX = mLocalPoint.x;
+ event.mY = mLocalPoint.y;
+
+ retval = target.dispatchDragEvent(event);
+
+ event.mX = tx;
+ event.mY = ty;
+ }
+ } break;
+
+ case DragEvent.ACTION_DROP: {
+ if (View.DEBUG_DRAG) Slog.d(TAG, "Drop event: " + event);
+ View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
+ if (target != null) {
+ event.mX = mLocalPoint.x;
+ event.mY = mLocalPoint.y;
+ retval = target.dispatchDragEvent(event);
+ event.mX = tx;
+ event.mY = ty;
+ }
+ } break;
+ }
+
+ // If none of our children could handle the event, try here
+ if (!retval) {
+ retval = onDragEvent(event);
+ }
+ return retval;
+ }
+
+ // Find the frontmost child view that lies under the given point, and calculate
+ // the position within its own local coordinate system.
+ View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
+ final float scrolledX = x + mScrollX;
+ final float scrolledY = y + mScrollY;
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = count - 1; i >= 0; i--) {
+ final View child = children[i];
+ if (child.mCanAcceptDrop == false) {
+ continue;
+ }
+
+ float localX = scrolledX - child.mLeft;
+ float localY = scrolledY - child.mTop;
+ if (!child.hasIdentityMatrix() && mAttachInfo != null) {
+ // non-identity matrix: transform the point into the view's coordinates
+ final float[] localXY = mAttachInfo.mTmpTransformLocation;
+ localXY[0] = localX;
+ localXY[1] = localY;
+ child.getInverseMatrix().mapPoints(localXY);
+ localX = localXY[0];
+ localY = localXY[1];
+ }
+ if (localX >= 0 && localY >= 0 && localX < (child.mRight - child.mLeft) &&
+ localY < (child.mBottom - child.mTop)) {
+ outLocalPoint.set(localX, localY);
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
*/
@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 77ba6fe..c63f7d6 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -24,6 +24,7 @@
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.*;
@@ -45,6 +46,8 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.app.ActivityManagerNative;
@@ -198,6 +201,11 @@
final ViewConfiguration mViewConfiguration;
+ /* Drag/drop */
+ ClipDescription mDragDescription;
+ View mCurrentDragView;
+ final PointF mDragPoint = new PointF();
+
/**
* see {@link #playSoundEffect(int)}
*/
@@ -1670,6 +1678,7 @@
public final static int FINISH_INPUT_CONNECTION = 1012;
public final static int CHECK_FOCUS = 1013;
public final static int CLOSE_SYSTEM_DIALOGS = 1014;
+ public final static int DISPATCH_DRAG_EVENT = 1015;
@Override
public void handleMessage(Message msg) {
@@ -1845,6 +1854,9 @@
mView.onCloseSystemDialogs((String)msg.obj);
}
} break;
+ case DISPATCH_DRAG_EVENT: {
+ handleDragEvent((DragEvent)msg.obj);
+ } break;
}
}
@@ -2434,6 +2446,87 @@
}
}
+ /* drag/drop */
+ private void handleDragEvent(DragEvent event) {
+ // From the root, only drag start/end/location are dispatched. entered/exited
+ // are determined and dispatched by the viewgroup hierarchy, who then report
+ // that back here for ultimate reporting back to the framework.
+ if (mView != null && mAdded) {
+ final int what = event.mAction;
+
+ if (what == DragEvent.ACTION_DRAG_EXITED) {
+ // A direct EXITED event means that the window manager knows we've just crossed
+ // a window boundary, so the current drag target within this one must have
+ // just been exited. Send it the usual notifications and then we're done
+ // for now.
+ setDragFocus(event, null);
+ } else {
+ // Cache the drag description when the operation starts, then fill it in
+ // on subsequent calls as a convenience
+ if (what == DragEvent.ACTION_DRAG_STARTED) {
+ mDragDescription = event.mClipDescription;
+ } else {
+ event.mClipDescription = mDragDescription;
+ }
+
+ // For events with a [screen] location, translate into window coordinates
+ if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
+ mDragPoint.set(event.mX, event.mY);
+ if (mTranslator != null) {
+ mTranslator.translatePointInScreenToAppWindow(mDragPoint);
+ }
+
+ if (mCurScrollY != 0) {
+ mDragPoint.offset(0, mCurScrollY);
+ }
+
+ event.mX = mDragPoint.x;
+ event.mY = mDragPoint.y;
+ }
+
+ // Remember who the current drag target is pre-dispatch
+ final View prevDragView = mCurrentDragView;
+
+ // Now dispatch the drag/drop event
+ mView.dispatchDragEvent(event);
+
+ // If we changed apparent drag target, tell the OS about it
+ if (prevDragView != mCurrentDragView) {
+ try {
+ if (prevDragView != null) {
+ sWindowSession.dragRecipientExited(mWindow);
+ }
+ if (mCurrentDragView != null) {
+ sWindowSession.dragRecipientEntered(mWindow);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to note drag target change");
+ }
+ mCurrentDragView = prevDragView;
+ }
+ }
+ }
+ event.recycle();
+ }
+
+ public void setDragFocus(DragEvent event, View newDragTarget) {
+ final int action = event.mAction;
+ // If we've dragged off of a view, send it the EXITED message
+ if (mCurrentDragView != newDragTarget) {
+ if (mCurrentDragView != null) {
+ event.mAction = DragEvent.ACTION_DRAG_EXITED;
+ mCurrentDragView.dispatchDragEvent(event);
+ }
+ }
+ // If we've dragged over a new view, send it the ENTERED message
+ if (newDragTarget != null) {
+ event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+ newDragTarget.dispatchDragEvent(event);
+ }
+ mCurrentDragView = newDragTarget;
+ event.mAction = action; // restore the event's original state
+ }
+
private AudioManager getAudioManager() {
if (mView == null) {
throw new IllegalStateException("getAudioManager called when there is no mView");
@@ -2725,7 +2818,12 @@
msg.obj = reason;
sendMessage(msg);
}
-
+
+ public void dispatchDragEvent(DragEvent event) {
+ Message msg = obtainMessage(DISPATCH_DRAG_EVENT, event);
+ sendMessage(msg);
+ }
+
/**
* The window is getting focus so if there is anything focused/selected
* send an {@link AccessibilityEvent} to announce that.
@@ -2936,6 +3034,14 @@
}
}
}
+
+ /* Drag/drop */
+ public void dispatchDragEvent(DragEvent event) {
+ final ViewRoot viewRoot = mViewRoot.get();
+ if (viewRoot != null) {
+ viewRoot.dispatchDragEvent(event);
+ }
+ }
}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index dc3b44d..eddd04e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -347,6 +347,13 @@
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;
/**
+ * Window type: the drag-and-drop pseudowindow. There is only one
+ * drag layer (at most), and it is placed on top of all other windows.
+ * @hide
+ */
+ public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+15;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
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/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7944807..fedb873 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1291,6 +1291,7 @@
private void clearHelpers() {
clearTextEntry();
clearActionModes();
+ dismissFullScreenMode();
}
/**
@@ -4911,6 +4912,13 @@
return mFullScreenHolder != null;
}
+ private void dismissFullScreenMode() {
+ if (inFullScreenMode()) {
+ mFullScreenHolder.dismiss();
+ mFullScreenHolder = null;
+ }
+ }
+
void onPinchToZoomAnimationStart() {
// cancel the single touch handling
cancelTouch();
@@ -6878,9 +6886,9 @@
View view = (View) msg.obj;
int npp = msg.arg1;
- if (mFullScreenHolder != null) {
+ if (inFullScreenMode()) {
Log.w(LOGTAG, "Should not have another full screen.");
- mFullScreenHolder.dismiss();
+ dismissFullScreenMode();
}
mFullScreenHolder = new PluginFullScreenHolder(WebView.this, npp);
mFullScreenHolder.setContentView(view);
@@ -6891,10 +6899,7 @@
break;
}
case HIDE_FULLSCREEN:
- if (inFullScreenMode()) {
- mFullScreenHolder.dismiss();
- mFullScreenHolder = null;
- }
+ dismissFullScreenMode();
break;
case DOM_FOCUS_CHANGED:
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index b4efb92..9983d54 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -17,6 +17,7 @@
package android.widget;
import java.util.ArrayList;
+import java.util.HashMap;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -40,6 +41,7 @@
* @attr ref android.R.styleable#AdapterViewAnimator_inAnimation
* @attr ref android.R.styleable#AdapterViewAnimator_outAnimation
* @attr ref android.R.styleable#AdapterViewAnimator_animateFirstView
+ * @attr ref android.R.styleable#AdapterViewAnimator_loopViews
*/
public abstract class AdapterViewAnimator extends AdapterView<Adapter>
implements RemoteViewsAdapter.RemoteAdapterConnectionCallback {
@@ -69,15 +71,14 @@
int mNumActiveViews = 1;
/**
- * Array of the children of the {@link AdapterViewAnimator}. This array
- * is accessed in a circular fashion
+ * Map of the children of the {@link AdapterViewAnimator}.
*/
- View[] mActiveViews;
+ private HashMap<Integer, ViewAndIndex> mViewsMap = new HashMap<Integer, ViewAndIndex>();
/**
* List of views pending removal from the {@link AdapterViewAnimator}
*/
- ArrayList<View> mPreviousViews;
+ ArrayList<Integer> mPreviousViews;
/**
* The index, relative to the adapter, of the beginning of the window of views
@@ -124,7 +125,7 @@
* Specifies if the animator should wrap from 0 to the end and vice versa
* or have hard boundaries at the beginning and end
*/
- boolean mShouldLoop = true;
+ boolean mLoopViews = true;
/**
* The width and height of some child, used as a size reference in-case our
@@ -149,22 +150,25 @@
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.ViewAnimator);
+ com.android.internal.R.styleable.AdapterViewAnimator);
int resource = a.getResourceId(
- com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
+ com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0);
if (resource > 0) {
setInAnimation(context, resource);
}
- resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);
+ resource = a.getResourceId(com.android.internal.R.styleable.AdapterViewAnimator_outAnimation, 0);
if (resource > 0) {
setOutAnimation(context, resource);
}
boolean flag = a.getBoolean(
- com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);
+ com.android.internal.R.styleable.AdapterViewAnimator_animateFirstView, true);
setAnimateFirstView(flag);
+ mLoopViews = a.getBoolean(
+ com.android.internal.R.styleable.AdapterViewAnimator_loopViews, false);
+
a.recycle();
initViewAnimator();
@@ -175,11 +179,19 @@
*/
private void initViewAnimator() {
mMainQueue = new Handler(Looper.myLooper());
- mActiveViews = new View[mNumActiveViews];
- mPreviousViews = new ArrayList<View>();
+ mPreviousViews = new ArrayList<Integer>();
mViewsToBringToFront = new ArrayList<View>();
}
+ private class ViewAndIndex {
+ ViewAndIndex(View v, int i) {
+ view = v;
+ index = i;
+ }
+ View view;
+ int index;
+ }
+
/**
* This method is used by subclasses to configure the animator to display the
* desired number of views, and specify the offset
@@ -193,18 +205,17 @@
* @param shouldLoop If the animator is show view 0, and setPrevious() is called, do we
* we loop back to the end, or do we do nothing
*/
- void configureViewAnimator(int numVisibleViews, int activeOffset, boolean shouldLoop) {
+ void configureViewAnimator(int numVisibleViews, int activeOffset) {
if (activeOffset > numVisibleViews - 1) {
// Throw an exception here.
}
mNumActiveViews = numVisibleViews;
mActiveOffset = activeOffset;
- mActiveViews = new View[mNumActiveViews];
mPreviousViews.clear();
+ mViewsMap.clear();
removeAllViewsInLayout();
mCurrentWindowStart = 0;
mCurrentWindowEnd = -1;
- mShouldLoop = shouldLoop;
}
/**
@@ -238,9 +249,9 @@
if (mAdapter != null) {
mWhichChild = whichChild;
if (whichChild >= mAdapter.getCount()) {
- mWhichChild = mShouldLoop ? 0 : mAdapter.getCount() - 1;
+ mWhichChild = mLoopViews ? 0 : mAdapter.getCount() - 1;
} else if (whichChild < 0) {
- mWhichChild = mShouldLoop ? mAdapter.getCount() - 1 : 0;
+ mWhichChild = mLoopViews ? mAdapter.getCount() - 1 : 0;
}
boolean hasFocus = getFocusedChild() != null;
@@ -323,9 +334,10 @@
* @return View at this index, null if the index is outside the bounds
*/
View getViewAtRelativeIndex(int relativeIndex) {
- if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1) {
- int index = mCurrentWindowStartUnbounded + relativeIndex;
- return mActiveViews[modulo(index, mNumActiveViews)];
+ if (relativeIndex >= 0 && relativeIndex <= mNumActiveViews - 1 && mAdapter != null) {
+ int adapterCount = mAdapter.getCount();
+ int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, adapterCount);
+ return mViewsMap.get(i).view;
}
return null;
}
@@ -346,8 +358,8 @@
// get the fresh child from the adapter
View updatedChild = mAdapter.getView(i, null, this);
- if (mActiveViews[index] != null) {
- FrameLayout fl = (FrameLayout) mActiveViews[index];
+ if (mViewsMap.containsKey(index)) {
+ FrameLayout fl = (FrameLayout) mViewsMap.get(index).view;
// flush out the old child
fl.removeAllViewsInLayout();
// add the new child to the frame, if it exists
@@ -373,7 +385,8 @@
if (mAdapter == null) return;
for (int i = 0; i < mPreviousViews.size(); i++) {
- View viewToRemove = mPreviousViews.get(i);
+ View viewToRemove = mViewsMap.get(mPreviousViews.get(i)).view;
+ mViewsMap.remove(mPreviousViews.get(i));
viewToRemove.clearAnimation();
if (viewToRemove instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) viewToRemove;
@@ -386,64 +399,74 @@
removeViewInLayout(viewToRemove);
}
mPreviousViews.clear();
+ int adapterCount = mAdapter.getCount();
int newWindowStartUnbounded = childIndex - mActiveOffset;
int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1;
int newWindowStart = Math.max(0, newWindowStartUnbounded);
- int newWindowEnd = Math.min(mAdapter.getCount() - 1, newWindowEndUnbounded);
+ int newWindowEnd = Math.min(adapterCount - 1, newWindowEndUnbounded);
- // This section clears out any items that are in our mActiveViews list
+ if (mLoopViews) {
+ newWindowStart = newWindowStartUnbounded;
+ newWindowEnd = newWindowEndUnbounded;
+ }
+ int rangeStart = modulo(newWindowStart, adapterCount);
+ int rangeEnd = modulo(newWindowEnd, adapterCount);
+
+ boolean wrap = false;
+ if (rangeStart > rangeEnd) {
+ wrap = true;
+ }
+
+ // This section clears out any items that are in our active views list
// but are outside the effective bounds of our window (this is becomes an issue
// at the extremities of the list, eg. where newWindowStartUnbounded < 0 or
// newWindowEndUnbounded > mAdapter.getCount() - 1
- for (int i = newWindowStartUnbounded; i < newWindowEndUnbounded; i++) {
- if (i < newWindowStart || i > newWindowEnd) {
- int index = modulo(i, mNumActiveViews);
- if (mActiveViews[index] != null) {
- View previousView = mActiveViews[index];
- mPreviousViews.add(previousView);
- int previousViewRelativeIndex = modulo(index - mCurrentWindowStart,
- mNumActiveViews);
- animateViewForTransition(previousViewRelativeIndex, -1, previousView);
- mActiveViews[index] = null;
- }
+ for (Integer index : mViewsMap.keySet()) {
+ boolean remove = false;
+ if (!wrap && (index < rangeStart || index > rangeEnd)) {
+ remove = true;
+ } else if (wrap && (index > rangeEnd && index < rangeStart)) {
+ remove = true;
+ }
+
+ if (remove) {
+ View previousView = mViewsMap.get(index).view;
+ int oldRelativeIndex = mViewsMap.get(index).index;
+
+ mPreviousViews.add(index);
+ animateViewForTransition(oldRelativeIndex, -1, previousView);
}
}
// If the window has changed
- if (! (newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd)) {
+ if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd)) {
// Run through the indices in the new range
for (int i = newWindowStart; i <= newWindowEnd; i++) {
- int oldRelativeIndex = i - mCurrentWindowStartUnbounded;
+ int index = modulo(i, adapterCount);
+ int oldRelativeIndex;
+ if (mViewsMap.containsKey(index)) {
+ oldRelativeIndex = mViewsMap.get(index).index;
+ } else {
+ oldRelativeIndex = -1;
+ }
int newRelativeIndex = i - newWindowStartUnbounded;
- int index = modulo(i, mNumActiveViews);
// If this item is in the current window, great, we just need to apply
// the transform for it's new relative position in the window, and animate
// between it's current and new relative positions
- if (i >= mCurrentWindowStart && i <= mCurrentWindowEnd) {
- View view = mActiveViews[index];
+ boolean inOldRange = mViewsMap.containsKey(index) && !mPreviousViews.contains(index);
+
+ if (inOldRange) {
+ View view = mViewsMap.get(index).view;
+ mViewsMap.get(index).index = newRelativeIndex;
applyTransformForChildAtIndex(view, newRelativeIndex);
animateViewForTransition(oldRelativeIndex, newRelativeIndex, view);
- // Otherwise this view is new, so first we have to displace the view that's
- // taking the new view's place within our cache (a circular array)
+ // Otherwise this view is new to the window
} else {
- if (mActiveViews[index] != null) {
- View previousView = mActiveViews[index];
- mPreviousViews.add(previousView);
- int previousViewRelativeIndex = modulo(index - mCurrentWindowStart,
- mNumActiveViews);
- animateViewForTransition(previousViewRelativeIndex, -1, previousView);
-
- if (mCurrentWindowStart > newWindowStart) {
- mViewsToBringToFront.add(previousView);
- }
- }
-
- // We've cleared a spot for the new view. Get it from the adapter, add it
- // and apply any transform / animation
- View newView = mAdapter.getView(i, null, this);
+ // Get the new view from the adapter, add it and apply any transform / animation
+ View newView = mAdapter.getView(modulo(i, adapterCount), null, this);
// We wrap the new view in a FrameLayout so as to respect the contract
// with the adapter, that is, that we don't modify this view directly
@@ -453,12 +476,12 @@
if (newView != null) {
fl.addView(newView);
}
- mActiveViews[index] = fl;
+ mViewsMap.put(index, new ViewAndIndex(fl, newRelativeIndex));
addChild(fl);
applyTransformForChildAtIndex(fl, newRelativeIndex);
animateViewForTransition(-1, newRelativeIndex, fl);
}
- mActiveViews[index].bringToFront();
+ mViewsMap.get(index).view.bringToFront();
}
for (int i = 0; i < mViewsToBringToFront.size(); i++) {
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 895683d..95ebdd3 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -68,6 +68,11 @@
com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
mAutoStart = a.getBoolean(
com.android.internal.R.styleable.ViewFlipper_autoStart, false);
+
+ // By default we want the flipper to loop
+ mLoopViews = a.getBoolean(
+ com.android.internal.R.styleable.AdapterViewAnimator_loopViews, true);
+
a.recycle();
initDefaultAnimations();
}
@@ -194,8 +199,6 @@
super.showPrevious();
}
- /**
-
/**
* Internal method to start or stop dispatching flip {@link Message} based
* on {@link #mRunning} and {@link #mVisible} state.
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 40a5b29..839de7d 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -132,7 +132,7 @@
}
private void initStackView() {
- configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2, false);
+ configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2);
setStaticTransformationsEnabled(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
@@ -287,7 +287,6 @@
// framework level support for drawing outside of a parent's bounds.
private void disableParentalClipping() {
if (mAncestorContainingAllChildren != null) {
- Log.v(TAG, "Disabling parental clipping.");
ViewGroup vg = this;
while (vg.getParent() != null && vg.getParent() instanceof ViewGroup) {
if (vg == mAncestorContainingAllChildren) break;
@@ -363,7 +362,9 @@
if (mAdapter == null) return;
- if (mCurrentWindowStartUnbounded + activeIndex == 0) {
+ if (mLoopViews) {
+ mStackSlider.setMode(StackSlider.NORMAL_MODE);
+ } else if (mCurrentWindowStartUnbounded + activeIndex == 0) {
mStackSlider.setMode(StackSlider.BEGINNING_OF_STACK_MODE);
} else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount()) {
activeIndex--;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f5e806f..5a2cebe 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7594,28 +7594,28 @@
if (canSelectAll()) {
menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
- setIcon(com.android.internal.R.drawable.ic_menu_chat_dashboard).
+ setIcon(com.android.internal.R.drawable.ic_menu_select_all).
setAlphabeticShortcut('a');
atLeastOne = true;
}
if (canCut()) {
menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut).
- setIcon(com.android.internal.R.drawable.ic_menu_compose).
+ setIcon(com.android.internal.R.drawable.ic_menu_cut).
setAlphabeticShortcut('x');
atLeastOne = true;
}
if (canCopy()) {
menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
- setIcon(com.android.internal.R.drawable.ic_menu_attachment).
+ setIcon(com.android.internal.R.drawable.ic_menu_copy).
setAlphabeticShortcut('c');
atLeastOne = true;
}
if (canPaste()) {
menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
- setIcon(com.android.internal.R.drawable.ic_menu_camera).
+ setIcon(com.android.internal.R.drawable.ic_menu_paste).
setAlphabeticShortcut('v');
atLeastOne = true;
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 6e11cff..2a8cd94 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -180,7 +180,7 @@
Log.d(TAG, "Found gdbserver: " + entry.getName());
}
- final String installGdbServerPath = APK_LIB + GDBSERVER;
+ final String installGdbServerPath = GDBSERVER;
nativeFiles.add(Pair.create(entry, installGdbServerPath));
return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 4da74e6..d5213db 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,11 +16,14 @@
package com.android.internal.view;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.view.DragEvent;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.KeyEvent;
@@ -66,7 +69,10 @@
}
}
}
-
+
+ public void dispatchDragEvent(DragEvent event) {
+ }
+
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
diff --git a/core/res/res/drawable-hdpi/ic_menu_copy.png b/core/res/res/drawable-hdpi/ic_menu_copy.png
new file mode 100644
index 0000000..8f11153
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_copy.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cut.png b/core/res/res/drawable-hdpi/ic_menu_cut.png
new file mode 100644
index 0000000..6ad379e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_cut.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_paste.png b/core/res/res/drawable-hdpi/ic_menu_paste.png
new file mode 100644
index 0000000..5a3850f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_paste.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_select_all.png b/core/res/res/drawable-hdpi/ic_menu_select_all.png
new file mode 100644
index 0000000..dde6741
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_select_all.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_copy.png b/core/res/res/drawable-mdpi/ic_menu_copy.png
new file mode 100644
index 0000000..89d626f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_copy.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cut.png b/core/res/res/drawable-mdpi/ic_menu_cut.png
new file mode 100644
index 0000000..1b4733e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_cut.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_paste.png b/core/res/res/drawable-mdpi/ic_menu_paste.png
new file mode 100755
index 0000000..cdf7ca3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_paste.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_select_all.png b/core/res/res/drawable-mdpi/ic_menu_select_all.png
new file mode 100644
index 0000000..37fd3cbd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_select_all.png
Binary files differ
diff --git a/core/res/res/menu/webview_copy.xml b/core/res/res/menu/webview_copy.xml
index 224f54f..adba563 100644
--- a/core/res/res/menu/webview_copy.xml
+++ b/core/res/res/menu/webview_copy.xml
@@ -16,7 +16,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/copy"
- android:icon="@drawable/ic_menu_attachment"
+ android:icon="@drawable/ic_menu_copy"
android:showAsAction="always"
/>
<item android:id="@+id/share"
@@ -24,7 +24,7 @@
android:showAsAction="always"
/>
<item android:id="@+id/select_all"
- android:icon="@drawable/ic_menu_chat_dashboard"
+ android:icon="@drawable/ic_menu_select_all"
android:showAsAction="always"
/>
<item android:id="@+id/find"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index b618756..830fb01 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -71,20 +71,6 @@
<item>@drawable/indicator_code_lock_point_area_default</item>
<item>@drawable/indicator_code_lock_point_area_green</item>
<item>@drawable/indicator_code_lock_point_area_red</item>
- <!-- SlidingTab drawables shared by InCallScreen and LockScreen -->
- <item>@drawable/jog_tab_bar_left_end_confirm_gray</item>
- <item>@drawable/jog_tab_bar_left_end_normal</item>
- <item>@drawable/jog_tab_bar_left_end_pressed</item>
- <item>@drawable/jog_tab_bar_right_end_confirm_gray</item>
- <item>@drawable/jog_tab_bar_right_end_normal</item>
- <item>@drawable/jog_tab_bar_right_end_pressed</item>
- <item>@drawable/jog_tab_left_confirm_gray</item>
- <item>@drawable/jog_tab_left_normal</item>
- <item>@drawable/jog_tab_left_pressed</item>
- <item>@drawable/jog_tab_right_confirm_gray</item>
- <item>@drawable/jog_tab_right_normal</item>
- <item>@drawable/jog_tab_right_pressed</item>
- <item>@drawable/jog_tab_target_gray</item>
</array>
<!-- Do not translate. These are all of the color state list resources that should be
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 317b3f3..5df95de 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2384,8 +2384,11 @@
<attr name="inAnimation" />
<!-- Identifier for the animation to use when a view is hidden. -->
<attr name="outAnimation" />
+ <!--Defines whether the animator loops to the first view once it
+ has reached the end of the list. -->
+ <attr name="loopViews" format="boolean" />
<!-- Defines whether to animate the current View when the ViewAnimation
- is first displayed. -->
+ is first displayed. -->
<attr name="animateFirstView" />
</declare-styleable>
<declare-styleable name="AdapterViewFlipper">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index adcbb10..8592820 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1360,6 +1360,7 @@
<public type="attr" name="breadCrumbShortTitle" />
<public type="attr" name="listDividerAlertDialog" />
<public type="attr" name="textColorAlertDialogListItem" />
+ <public type="attr" name="loopViews" />
<public type="anim" name="animator_fade_in" />
<public type="anim" name="animator_fade_out" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
old mode 100644
new mode 100755
index 16d35b4..8b4f91f
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1249,31 +1249,29 @@
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
- <string name="policylab_limitPassword">Limit password</string>
+ <string name="policylab_limitPassword">Set password rules</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_limitPassword">Restrict the types of passwords you
- are allowed to use.</string>
+ <string name="policydesc_limitPassword">Control the length and the characters
+ allowed in screen-unlock passwords</string>
<!-- Title of policy access to watch user login attempts -->
- <string name="policylab_watchLogin">Watch login attempts</string>
+ <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
<!-- Description of policy access to watch user login attempts -->
- <string name="policydesc_watchLogin">Monitor failed attempts to login to
- the device, to perform some action.</string>
+ <string name="policydesc_watchLogin">Monitor the number of incorrect passwords
+ entered when unlocking the screen, and lock the phone or erase all the phone\'s
+ data if too many incorrect passwords are entered</string>
<!-- Title of policy access to reset user's password -->
- <string name="policylab_resetPassword">Reset password</string>
+ <string name="policylab_resetPassword">Change the screen-unlock password</string>
<!-- Description of policy access to reset user's password -->
- <string name="policydesc_resetPassword">Force your password
- to a new value, requiring the administrator give it to you
- before you can log in.</string>
+ <string name="policydesc_resetPassword">Change the screen-unlock password</string>
<!-- Title of policy access to force lock the device -->
- <string name="policylab_forceLock">Force lock</string>
+ <string name="policylab_forceLock">Lock the screen</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_forceLock">Control when device locks,
- requiring you re-enter its password.</string>
+ <string name="policydesc_forceLock">Control how and when the screen locks</string>
<!-- Title of policy access to wipe the user's data -->
<string name="policylab_wipeData">Erase all data</string>
<!-- Description of policy access to wipe the user's data -->
- <string name="policydesc_wipeData">Perform a factory reset, deleting
- all of your data without any confirmation.</string>
+ <string name="policydesc_wipeData">Erase the phone\'s data without warning,
+ by performing a factory data reset</string>
<string name="policylab_setGlobalProxy">Set the device global proxy</string>
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_setGlobalProxy">Set the device global proxy
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/Path.java b/graphics/java/android/graphics/Path.java
index c3416a0..1324431 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -236,6 +236,7 @@
* @param y The y-coordinate of the end of a line
*/
public void lineTo(float x, float y) {
+ isSimplePath = false;
native_lineTo(mNativePath, x, y);
}
@@ -250,6 +251,7 @@
* this contour, to specify a line
*/
public void rLineTo(float dx, float dy) {
+ isSimplePath = false;
native_rLineTo(mNativePath, dx, dy);
}
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1510f87..c6990bf 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -42,8 +42,11 @@
#define CBLK_FORCEREADY_ON 0x0004 // track is considered ready immediately by AudioFlinger
#define CBLK_FORCEREADY_OFF 0x0000 // track is ready when buffer full
#define CBLK_INVALID_MSK 0x0008
-#define CBLK_INVALID_ON 0x0008 // track buffer is invalidated by AudioFlinger: must be re-created
-#define CBLK_INVALID_OFF 0x0000
+#define CBLK_INVALID_ON 0x0008 // track buffer is invalidated by AudioFlinger:
+#define CBLK_INVALID_OFF 0x0000 // must be re-created
+#define CBLK_DISABLED_MSK 0x0010
+#define CBLK_DISABLED_ON 0x0010 // track disabled by AudioFlinger due to underrun:
+#define CBLK_DISABLED_OFF 0x0000 // must be re-started
struct audio_track_cblk_t
{
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 76307b2..6533600 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -115,7 +115,8 @@
*/
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format) = 0;
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth, uint32_t reqHeight) = 0;
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 8773d71..a80832d 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -170,6 +170,36 @@
};
// ---------------------------------------------------------------------------
+
+class ScreenshotClient
+{
+ sp<IMemoryHeap> mHeap;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+public:
+ ScreenshotClient();
+
+ // frees the previous screenshot and capture a new one
+ status_t update();
+ status_t update(uint32_t reqWidth, uint32_t reqHeight);
+
+ // release memory occupied by the screenshot
+ void release();
+
+ // pixels are valid until this object is freed or
+ // release() or update() is called
+ void const* getPixels() const;
+
+ uint32_t getWidth() const;
+ uint32_t getHeight() const;
+ PixelFormat getFormat() const;
+ uint32_t getStride() const;
+ // size of allocated memory in bytes
+ size_t getSize() const;
+};
+
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H
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 e85735a..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.
@@ -308,9 +304,6 @@
GetStateFunc getStateFunc);
bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
-
- // dump state
- void dumpDeviceInfo(String8& dump);
};
@@ -340,6 +333,7 @@
inline bool isIgnored() { return mMappers.isEmpty(); }
+ void dump(String8& dump);
void addMapper(InputMapper* mapper);
void configure();
void reset();
@@ -393,6 +387,7 @@
virtual uint32_t getSources() = 0;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent) = 0;
@@ -436,6 +431,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -484,6 +480,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -540,6 +537,7 @@
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
virtual void configure();
virtual void reset();
@@ -761,15 +759,16 @@
} mLocked;
virtual void configureParameters();
- virtual void logParameters();
+ virtual void dumpParameters(String8& dump);
virtual void configureRawAxes();
- virtual void logRawAxes();
+ virtual void dumpRawAxes(String8& dump);
virtual bool configureSurfaceLocked();
- virtual void logMotionRangesLocked();
+ virtual void dumpSurfaceLocked(String8& dump);
virtual void configureVirtualKeysLocked();
+ virtual void dumpVirtualKeysLocked(String8& dump);
virtual void parseCalibration();
virtual void resolveCalibration();
- virtual void logCalibration();
+ virtual void dumpCalibration(String8& dump);
enum TouchResult {
// Dispatch the touch normally.
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/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index ee90702..ce85d46 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -22,6 +22,62 @@
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define PATH_HEAP_SIZE 64
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+PathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) {
+}
+
+PathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) {
+ int count = buffer.readS32();
+
+ mPaths.setCount(count);
+ SkPath** ptr = mPaths.begin();
+ SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath));
+
+ for (int i = 0; i < count; i++) {
+ new (p) SkPath;
+ p->unflatten(buffer);
+ *ptr++ = p;
+ p++;
+ }
+}
+
+PathHeap::~PathHeap() {
+ SkPath** iter = mPaths.begin();
+ SkPath** stop = mPaths.end();
+ while (iter < stop) {
+ (*iter)->~SkPath();
+ iter++;
+ }
+}
+
+int PathHeap::append(const SkPath& path) {
+ SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath));
+ new (p) SkPath(path);
+ *mPaths.append() = p;
+ return mPaths.count();
+}
+
+void PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const {
+ int count = mPaths.count();
+
+ buffer.write32(count);
+ SkPath** iter = mPaths.begin();
+ SkPath** stop = mPaths.end();
+ while (iter < stop) {
+ (*iter)->flatten(buffer);
+ iter++;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 735f0e7..5d02bd7 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -45,39 +45,11 @@
class PathHeap: public SkRefCnt {
public:
- PathHeap(): mHeap(64 * sizeof(SkPath)) {
- };
+ PathHeap();
+ PathHeap(SkFlattenableReadBuffer& buffer);
+ ~PathHeap();
- PathHeap(SkFlattenableReadBuffer& buffer): mHeap(64 * sizeof(SkPath)) {
- int count = buffer.readS32();
-
- mPaths.setCount(count);
- SkPath** ptr = mPaths.begin();
- SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath));
-
- for (int i = 0; i < count; i++) {
- new (p) SkPath;
- p->unflatten(buffer);
- *ptr++ = p;
- p++;
- }
- }
-
- ~PathHeap() {
- SkPath** iter = mPaths.begin();
- SkPath** stop = mPaths.end();
- while (iter < stop) {
- (*iter)->~SkPath();
- iter++;
- }
- }
-
- int append(const SkPath& path) {
- SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath));
- new (p) SkPath(path);
- *mPaths.append() = p;
- return mPaths.count();
- }
+ int append(const SkPath& path);
int count() const { return mPaths.count(); }
@@ -85,17 +57,7 @@
return *mPaths[index];
}
- void flatten(SkFlattenableWriteBuffer& buffer) const {
- int count = mPaths.count();
-
- buffer.write32(count);
- SkPath** iter = mPaths.begin();
- SkPath** stop = mPaths.end();
- while (iter < stop) {
- (*iter)->flatten(buffer);
- iter++;
- }
- }
+ void flatten(SkFlattenableWriteBuffer& buffer) const;
private:
SkChunkAlloc mHeap;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b66696d..4e4a277 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -435,25 +435,25 @@
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Split up our cache texture into lines of certain widths
int nextLine = 0;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 16, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 40, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0));
nextLine += mCacheLines.top()->mMaxHeight;
mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
}
@@ -631,6 +631,7 @@
precacheLatin(paint);
}
}
+
FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) {
checkInit();
@@ -713,7 +714,7 @@
float normalizeFactor = 0.0f;
for(int32_t r = -radius; r <= radius; r ++) {
- float floatR = (float)r;
+ float floatR = (float) r;
weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
normalizeFactor += weights[r + radius];
}
@@ -742,7 +743,7 @@
if ((x > radius) && (x < (width - radius))) {
const uint8_t *i = input + (x - radius);
for(int r = -radius; r <= radius; r ++) {
- currentPixel = (float)(*i);
+ currentPixel = (float) (*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
i++;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index de5c019..4fb8f8d 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -183,14 +183,14 @@
}
bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
- if (glyph.fHeight > mMaxHeight) {
+ if (glyph.fHeight + 2 > mMaxHeight) {
return false;
}
- if (mCurrentCol + glyph.fWidth < mMaxWidth) {
- *retOriginX = mCurrentCol;
- *retOriginY = mCurrentRow;
- mCurrentCol += glyph.fWidth;
+ if (mCurrentCol + glyph.fWidth + 2 < mMaxWidth) {
+ *retOriginX = mCurrentCol + 1;
+ *retOriginY = mCurrentRow + 1;
+ mCurrentCol += glyph.fWidth + 2;
mDirty = true;
return true;
}
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 60523db..a0cc5d6 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -44,7 +44,7 @@
uint32_t id;
bool operator<(const LayerSize& rhs) const {
- if (id != 0 && rhs.id != 0) {
+ if (id != 0 && rhs.id != 0 && id != rhs.id) {
return id < rhs.id;
}
if (width == rhs.width) {
@@ -54,7 +54,7 @@
}
bool operator==(const LayerSize& rhs) const {
- return width == rhs.width && height == rhs.height;
+ return id == rhs.id && width == rhs.width && height == rhs.height;
}
}; // struct LayerSize
@@ -83,7 +83,7 @@
*/
bool blend;
/**
- * Indicates that this layer has never been used before.
+ * Indicates whether this layer has been used already.
*/
bool empty;
}; // struct Layer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 2770868..8c70cf9 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -114,6 +114,8 @@
glGenTextures(1, &layer->texture);
glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 23de3a5..0810fb8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -366,6 +366,8 @@
return false;
}
+ glActiveTexture(GL_TEXTURE0);
+
LayerSize size(bounds.getWidth(), bounds.getHeight());
Layer* layer = mCaches.layerCache.get(size);
if (!layer) {
@@ -383,17 +385,22 @@
// Copy the framebuffer into the layer
glBindTexture(GL_TEXTURE_2D, layer->texture);
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
- bounds.getWidth(), bounds.getHeight(), 0);
- layer->empty = false;
- } else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
- bounds.getWidth(), bounds.getHeight());
- }
+ // TODO: Workaround for b/3054204
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
+ bounds.getWidth(), bounds.getHeight(), 0);
- if (flags & SkCanvas::kClipToLayer_SaveFlag) {
- if (mSnapshot->clipTransformed(bounds)) setScissorFromClip();
+ // TODO: Waiting for b/3054204 to be fixed
+// if (layer->empty) {
+// glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
+// bounds.getWidth(), bounds.getHeight(), 0);
+// layer->empty = false;
+// } else {
+// glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
+// bounds.getWidth(), bounds.getHeight());
+// }
+
+ if (flags & SkCanvas::kClipToLayer_SaveFlag && mSnapshot->clipTransformed(bounds)) {
+ setScissorFromClip();
}
// Enqueue the buffer coordinates to clear the corresponding region later
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 70e06a1..377727b 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -138,8 +138,8 @@
const SkPath *path, const SkPaint* paint) {
const SkRect& bounds = path->getBounds();
- const float pathWidth = bounds.width();
- const float pathHeight = bounds.height();
+ const float pathWidth = fmax(bounds.width(), 1.0f);
+ const float pathHeight = fmax(bounds.height(), 1.0f);
if (pathWidth > mMaxTextureSize || pathHeight > mMaxTextureSize) {
LOGW("Path too large to be rendered into a texture");
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
index 33945a5..f5fecba 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -65,7 +65,6 @@
static void copyInput() {
- RS_DEBUG_MARKER;
rs_allocation ain = rsGetAllocation(InPixel);
uint32_t dimx = rsAllocationGetDimX(ain);
uint32_t dimy = rsAllocationGetDimY(ain);
@@ -74,7 +73,6 @@
ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]);
}
}
- RS_DEBUG_MARKER;
}
void filter() {
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cfd6479..6940033 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -241,6 +241,10 @@
return true;
}
+void Context::setupProgramStore() {
+ mFragmentStore->setupGL2(this, &mStateFragmentStore);
+}
+
static bool getProp(const char *str)
{
char buf[PROPERTY_VALUE_MAX];
@@ -282,14 +286,14 @@
rsc->props.mLogShadersUniforms = getProp("debug.rs.shader.uniforms");
rsc->props.mLogVisual = getProp("debug.rs.visual");
- ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
- if (!tlsStruct) {
+ rsc->mTlsStruct = new ScriptTLSStruct;
+ if (!rsc->mTlsStruct) {
LOGE("Error allocating tls storage");
return NULL;
}
- tlsStruct->mContext = rsc;
- tlsStruct->mScript = NULL;
- int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct);
+ rsc->mTlsStruct->mContext = rsc;
+ rsc->mTlsStruct->mScript = NULL;
+ int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct);
if (status) {
LOGE("pthread_setspecific %i", status);
}
@@ -361,6 +365,7 @@
rsc->deinitEGL();
pthread_mutex_unlock(&gInitMutex);
}
+ delete rsc->mTlsStruct;
LOGV("%p, RS Thread exited", rsc);
return NULL;
@@ -387,6 +392,11 @@
#endif
setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority);
+ int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct);
+ if (status) {
+ LOGE("pthread_setspecific %i", status);
+ }
+
while(rsc->mRunning) {
rsc->mWorkers.mLaunchSignals[idx].wait();
if (rsc->mWorkers.mLaunchCallback) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 2e84930..dabe196 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -49,6 +49,24 @@
namespace renderscript {
+#if 0
+#define CHECK_OBJ(o) { \
+ GET_TLS(); \
+ if(!ObjectBase::isValid(rsc, (const ObjectBase *)o)) { \
+ LOGE("Bad object %p at %s, %i", o, __FILE__, __LINE__); \
+ } \
+}
+#define CHECK_OBJ_OR_NULL(o) { \
+ GET_TLS(); \
+ if(o && !ObjectBase::isValid(rsc, (const ObjectBase *)o)) { \
+ LOGE("Bad object %p at %s, %i", o, __FILE__, __LINE__); \
+ } \
+}
+#else
+#define CHECK_OBJ(o)
+#define CHECK_OBJ_OR_NULL(o)
+#endif
+
class Context
{
public:
@@ -64,6 +82,7 @@
Context * mContext;
Script * mScript;
};
+ ScriptTLSStruct *mTlsStruct;
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -99,6 +118,7 @@
Font * getFont() {return mFont.get();}
bool setupCheck();
+ void setupProgramStore();
bool checkDriver() const {return mEGL.mSurface != 0;}
void pause();
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 12dedac..c516ea9 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -23,6 +23,7 @@
#include "rsFont.h"
#include "rsProgramFragment.h"
+#include <cutils/properties.h>
#include FT_BITMAP_H
#include <GLES/gl.h>
@@ -268,6 +269,44 @@
mRSC = NULL;
mLibrary = NULL;
setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
+
+ // Get the renderer properties
+ char property[PROPERTY_VALUE_MAX];
+
+ // Get the gamma
+ float gamma = DEFAULT_TEXT_GAMMA;
+ if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
+ LOGD(" Setting text gamma to %s", property);
+ gamma = atof(property);
+ } else {
+ LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
+ }
+
+ // Get the black gamma threshold
+ int blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
+ if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
+ LOGD(" Setting text black gamma threshold to %s", property);
+ blackThreshold = atoi(property);
+ } else {
+ LOGD(" Using default text black gamma threshold of %d",
+ DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
+ }
+ mBlackThreshold = (float)(blackThreshold) / 255.0f;
+
+ // Get the white gamma threshold
+ int whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
+ if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
+ LOGD(" Setting text white gamma threshold to %s", property);
+ whiteThreshold = atoi(property);
+ } else {
+ LOGD(" Using default white black gamma threshold of %d",
+ DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
+ }
+ mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
+
+ // Compute the gamma tables
+ mBlackGamma = gamma;
+ mWhiteGamma = 1.0f / gamma;
}
FontState::~FontState()
@@ -391,12 +430,15 @@
shaderString.append("void main() {\n");
shaderString.append(" lowp vec4 col = UNI_Color;\n");
shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
+ shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
shaderString.append(" gl_FragColor = col;\n");
shaderString.append("}\n");
const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
+ const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
mRSC->mStateElement.elementBuilderBegin();
mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
+ mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
Type *inputType = new Type(mRSC);
@@ -558,9 +600,9 @@
ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
mRSC->setFragmentStore(mFontProgramStore.get());
- if(mFontColorDirty) {
- mFontShaderFConstant->data(mRSC, &mFontColor, 4*sizeof(float));
- mFontColorDirty = false;
+ if(mConstantsDirty) {
+ mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
+ mConstantsDirty = false;
}
if (!mRSC->setupCheck()) {
@@ -725,18 +767,26 @@
}
void FontState::setFontColor(float r, float g, float b, float a) {
- mFontColor[0] = r;
- mFontColor[1] = g;
- mFontColor[2] = b;
- mFontColor[3] = a;
- mFontColorDirty = true;
+ mConstants.mFontColor[0] = r;
+ mConstants.mFontColor[1] = g;
+ mConstants.mFontColor[2] = b;
+ mConstants.mFontColor[3] = a;
+
+ mConstants.mGamma = 1.0f;
+ const int luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
+ if (luminance <= mBlackThreshold) {
+ mConstants.mGamma = mBlackGamma;
+ } else if (luminance >= mWhiteThreshold) {
+ mConstants.mGamma = mWhiteGamma;
+ }
+ mConstantsDirty = true;
}
void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
- *r = mFontColor[0];
- *g = mFontColor[1];
- *b = mFontColor[2];
- *a = mFontColor[3];
+ *r = mConstants.mFontColor[0];
+ *g = mConstants.mFontColor[1];
+ *b = mConstants.mFontColor[2];
+ *a = mConstants.mFontColor[3];
}
void FontState::deinit(Context *rsc)
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 027ed1d..16009ef 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -31,6 +31,15 @@
namespace renderscript {
+// Gamma (>= 1.0, <= 10.0)
+#define PROPERTY_TEXT_GAMMA "ro.text_gamma"
+#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
+#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
+
+#define DEFAULT_TEXT_GAMMA 1.4f
+#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
+#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
+
class FontState;
class Font : public ObjectBase
@@ -162,8 +171,17 @@
Context *mRSC;
- float mFontColor[4];
- bool mFontColorDirty;
+ struct {
+ float mFontColor[4];
+ float mGamma;
+ } mConstants;
+ bool mConstantsDirty;
+
+ float mBlackGamma;
+ float mWhiteGamma;
+
+ float mBlackThreshold;
+ float mWhiteThreshold;
// Free type library, we only need one copy
FT_Library mLibrary;
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 713d61e..f69cb15 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -195,3 +195,15 @@
}
}
+bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj)
+{
+ const ObjectBase * o = rsc->mObjHead;
+ while (o) {
+ if (o == obj) {
+ return true;
+ }
+ o = o->mNext;
+ }
+ return false;
+}
+
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
index ad95b81..59fb4a6 100644
--- a/libs/rs/rsObjectBase.h
+++ b/libs/rs/rsObjectBase.h
@@ -56,6 +56,8 @@
virtual void serialize(OStream *stream) const = 0;
virtual RsA3DClassID getClassId() const = 0;
+ static bool isValid(const Context *rsc, const ObjectBase *obj);
+
protected:
const char *mAllocFile;
uint32_t mAllocLine;
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 2531a9b..10e00e6 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -115,6 +115,14 @@
Program::~Program()
{
+ if(mRSC->props.mLogShaders) {
+ LOGV("Program::~Program with shader id %u", mShaderID);
+ }
+
+ if(mShaderID) {
+ glDeleteShader(mShaderID);
+ }
+
for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) {
bindAllocation(NULL, NULL, ct);
}
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 275a1df..c94f294 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -49,6 +49,9 @@
ProgramFragment::~ProgramFragment()
{
+ if(mShaderID) {
+ mRSC->mShaderCache.cleanupFragment(mShaderID);
+ }
}
void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a)
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index bd12989..d3dbfb2 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -45,15 +45,9 @@
ProgramVertex::~ProgramVertex()
{
-}
-
-static void logMatrix(const char *txt, const float *f)
-{
- LOGV("Matrix %s, %p", txt, f);
- LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[0], f[4], f[8], f[12]);
- LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[1], f[5], f[9], f[13]);
- LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[2], f[6], f[10], f[14]);
- LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[3], f[7], f[11], f[15]);
+ if(mShaderID) {
+ mRSC->mShaderCache.cleanupVertex(mShaderID);
+ }
}
void ProgramVertex::loadShader(Context *rsc) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 22fd421..e0de867 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -203,45 +203,46 @@
static uint32_t SC_allocGetDimX(RsAllocation va)
{
- GET_TLS();
const Allocation *a = static_cast<const Allocation *>(va);
- //LOGE("SC_allocGetDimX a=%p", a);
- //LOGE(" type=%p", a->getType());
+ CHECK_OBJ(a);
+ //LOGE("SC_allocGetDimX a=%p type=%p", a, a->getType());
return a->getType()->getDimX();
}
static uint32_t SC_allocGetDimY(RsAllocation va)
{
- GET_TLS();
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
return a->getType()->getDimY();
}
static uint32_t SC_allocGetDimZ(RsAllocation va)
{
- GET_TLS();
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
return a->getType()->getDimZ();
}
static uint32_t SC_allocGetDimLOD(RsAllocation va)
{
- GET_TLS();
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
return a->getType()->getDimLOD();
}
static uint32_t SC_allocGetDimFaces(RsAllocation va)
{
- GET_TLS();
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
return a->getType()->getDimFaces();
}
static const void * SC_getElementAtX(RsAllocation va, uint32_t x)
{
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
const Type *t = a->getType();
+ CHECK_OBJ(t);
const uint8_t *p = (const uint8_t *)a->getPtr();
return &p[t->getElementSizeBytes() * x];
}
@@ -249,7 +250,9 @@
static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y)
{
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
const Type *t = a->getType();
+ CHECK_OBJ(t);
const uint8_t *p = (const uint8_t *)a->getPtr();
return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
}
@@ -257,7 +260,9 @@
static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z)
{
const Allocation *a = static_cast<const Allocation *>(va);
+ CHECK_OBJ(a);
const Type *t = a->getType();
+ CHECK_OBJ(t);
const uint8_t *p = (const uint8_t *)a->getPtr();
return &p[t->getElementSizeBytes() * (x + y*t->getDimX())];
}
@@ -265,9 +270,11 @@
static void SC_setObject(void **vdst, void * vsrc) {
//LOGE("SC_setObject %p,%p %p", vdst, *vdst, vsrc);
if (vsrc) {
+ CHECK_OBJ(vsrc);
static_cast<ObjectBase *>(vsrc)->incSysRef();
}
if (vdst[0]) {
+ CHECK_OBJ(vdst[0]);
static_cast<ObjectBase *>(vdst[0])->decSysRef();
}
*vdst = vsrc;
@@ -276,6 +283,7 @@
static void SC_clearObject(void **vdst) {
//LOGE("SC_clearObject %p,%p", vdst, *vdst);
if (vdst[0]) {
+ CHECK_OBJ(vdst[0]);
static_cast<ObjectBase *>(vdst[0])->decSysRef();
}
*vdst = NULL;
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index fd4c379..88db761 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -44,6 +44,8 @@
static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
{
+ CHECK_OBJ_OR_NULL(va);
+ CHECK_OBJ(vpf);
GET_TLS();
rsi_ProgramBindTexture(rsc,
static_cast<ProgramFragment *>(vpf),
@@ -54,6 +56,8 @@
static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
{
+ CHECK_OBJ_OR_NULL(vs);
+ CHECK_OBJ(vpf);
GET_TLS();
rsi_ProgramBindSampler(rsc,
static_cast<ProgramFragment *>(vpf),
@@ -64,24 +68,28 @@
static void SC_bindProgramStore(RsProgramStore pfs)
{
+ CHECK_OBJ_OR_NULL(pfs);
GET_TLS();
rsi_ContextBindProgramStore(rsc, pfs);
}
static void SC_bindProgramFragment(RsProgramFragment pf)
{
+ CHECK_OBJ_OR_NULL(pf);
GET_TLS();
rsi_ContextBindProgramFragment(rsc, pf);
}
static void SC_bindProgramVertex(RsProgramVertex pv)
{
+ CHECK_OBJ_OR_NULL(pv);
GET_TLS();
rsi_ContextBindProgramVertex(rsc, pv);
}
static void SC_bindProgramRaster(RsProgramRaster pv)
{
+ CHECK_OBJ_OR_NULL(pv);
GET_TLS();
rsi_ContextBindProgramRaster(rsc, pv);
}
@@ -112,6 +120,7 @@
static void SC_pfConstantColor(RsProgramFragment vpf, float r, float g, float b, float a)
{
GET_TLS();
+ CHECK_OBJ(vpf);
ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
pf->setConstantColor(rsc, r, g, b, a);
}
@@ -228,6 +237,7 @@
static void SC_drawMesh(RsMesh vsm)
{
+ CHECK_OBJ(vsm);
GET_TLS();
Mesh *sm = static_cast<Mesh *>(vsm);
if (!rsc->setupCheck()) {
@@ -238,6 +248,7 @@
static void SC_drawMeshPrimitive(RsMesh vsm, uint32_t primIndex)
{
+ CHECK_OBJ(vsm);
GET_TLS();
Mesh *sm = static_cast<Mesh *>(vsm);
if (!rsc->setupCheck()) {
@@ -248,6 +259,7 @@
static void SC_drawMeshPrimitiveRange(RsMesh vsm, uint32_t primIndex, uint32_t start, uint32_t len)
{
+ CHECK_OBJ(vsm);
GET_TLS();
Mesh *sm = static_cast<Mesh *>(vsm);
if (!rsc->setupCheck()) {
@@ -259,6 +271,7 @@
static void SC_meshComputeBoundingBox(RsMesh vsm, float *minX, float *minY, float *minZ,
float *maxX, float *maxY, float *maxZ)
{
+ CHECK_OBJ(vsm);
GET_TLS();
Mesh *sm = static_cast<Mesh *>(vsm);
sm->computeBBox();
@@ -285,17 +298,20 @@
static void SC_uploadToTexture2(RsAllocation va, uint32_t baseMipLevel)
{
+ CHECK_OBJ(va);
GET_TLS();
rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel);
}
static void SC_uploadToTexture(RsAllocation va)
{
+ CHECK_OBJ(va);
GET_TLS();
rsi_AllocationUploadToTexture(rsc, va, false, 0);
}
static void SC_uploadToBufferObject(RsAllocation va)
{
+ CHECK_OBJ(va);
GET_TLS();
rsi_AllocationUploadToBufferObject(rsc, va);
}
@@ -303,9 +319,7 @@
static void SC_ClearColor(float r, float g, float b, float a)
{
GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
+ rsc->setupProgramStore();
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT);
@@ -314,9 +328,7 @@
static void SC_ClearDepth(float v)
{
GET_TLS();
- if (!rsc->setupCheck()) {
- return;
- }
+ rsc->setupProgramStore();
glClearDepthf(v);
glClear(GL_DEPTH_BUFFER_BIT);
@@ -336,6 +348,7 @@
static void SC_DrawTextAlloc(RsAllocation va, int x, int y)
{
+ CHECK_OBJ(va);
GET_TLS();
Allocation *alloc = static_cast<Allocation *>(va);
rsc->mStateFont.renderText(alloc, x, y);
@@ -349,6 +362,7 @@
static void SC_BindFont(RsFont font)
{
+ CHECK_OBJ(font);
GET_TLS();
rsi_ContextBindFont(rsc, font);
}
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 28e3b1d..45f6207 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -29,20 +29,15 @@
ShaderCache::ShaderCache()
{
- mEntryCount = 0;
- mEntryAllocationCount = 16;
- mEntries = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t));
+ mEntries.setCapacity(16);
}
ShaderCache::~ShaderCache()
{
- for (uint32_t ct=0; ct < mEntryCount; ct++) {
- glDeleteProgram(mEntries[ct].program);
+ for (uint32_t ct=0; ct < mEntries.size(); ct++) {
+ glDeleteProgram(mEntries[ct]->program);
+ free(mEntries[ct]);
}
-
- mEntryCount = 0;
- mEntryAllocationCount = 0;
- free(mEntries);
}
bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag)
@@ -59,44 +54,30 @@
return false;
}
//LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+ uint32_t entryCount = mEntries.size();
+ for(uint32_t ct = 0; ct < entryCount; ct ++) {
+ if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
+ (mEntries[ct]->frag == frag->getShaderID())) {
- for (uint32_t ct=0; ct < mEntryCount; ct++) {
- if ((mEntries[ct].vtx == vtx->getShaderID()) &&
- (mEntries[ct].frag == frag->getShaderID())) {
-
- //LOGV("SC using program %i", mEntries[ct].program);
- glUseProgram(mEntries[ct].program);
- mCurrent = &mEntries[ct];
+ //LOGV("SC using program %i", mEntries[ct]->program);
+ glUseProgram(mEntries[ct]->program);
+ mCurrent = mEntries[ct];
//LOGV("ShaderCache hit, using %i", ct);
rsc->checkError("ShaderCache::lookup (hit)");
return true;
}
}
- // Not in cache, add it.
- if (mEntryAllocationCount == mEntryCount) {
- // Out of space, make some.
- mEntryAllocationCount *= 2;
- entry_t *e = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t));
- if (!e) {
- LOGE("Out of memory for ShaderCache::lookup");
- return false;
- }
- memcpy(e, mEntries, sizeof(entry_t) * mEntryCount);
- free(mEntries);
- mEntries = e;
- }
-
- //LOGV("ShaderCache miss, using %i", mEntryCount);
+ //LOGV("ShaderCache miss");
//LOGE("e0 %x", glGetError());
-
- entry_t *e = &mEntries[mEntryCount];
+ entry_t *e = (entry_t *)malloc(sizeof(entry_t));
+ mEntries.push(e);
mCurrent = e;
e->vtx = vtx->getShaderID();
e->frag = frag->getShaderID();
e->program = glCreateProgram();
e->vtxAttrCount = vtx->getAttribCount();
- if (mEntries[mEntryCount].program) {
+ if (e->program) {
GLuint pgm = e->program;
glAttachShader(pgm, vtx->getShaderID());
//LOGE("e1 %x", glGetError());
@@ -155,7 +136,6 @@
e->mIsValid = true;
//LOGV("SC made program %i", e->program);
glUseProgram(e->program);
- mEntryCount++;
rsc->checkError("ShaderCache::lookup (miss)");
return true;
}
@@ -171,10 +151,32 @@
void ShaderCache::cleanupVertex(uint32_t id)
{
+ int32_t numEntries = (int32_t)mEntries.size();
+ for(int32_t ct = 0; ct < numEntries; ct ++) {
+ if (mEntries[ct]->vtx == id) {
+ glDeleteProgram(mEntries[ct]->program);
+
+ free(mEntries[ct]);
+ mEntries.removeAt(ct);
+ numEntries = (int32_t)mEntries.size();
+ ct --;
+ }
+ }
}
void ShaderCache::cleanupFragment(uint32_t id)
{
+ int32_t numEntries = (int32_t)mEntries.size();
+ for(int32_t ct = 0; ct < numEntries; ct ++) {
+ if (mEntries[ct]->frag == id) {
+ glDeleteProgram(mEntries[ct]->program);
+
+ free(mEntries[ct]);
+ mEntries.removeAt(ct);
+ numEntries = (int32_t)mEntries.size();
+ ct --;
+ }
+ }
}
void ShaderCache::cleanupAll()
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/rsShaderCache.h
index 312c251..35ff95b 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/rsShaderCache.h
@@ -58,11 +58,12 @@
int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
bool mIsValid;
} entry_t;
- entry_t *mEntries;
+ //entry_t *mEntries;
+ Vector<entry_t*> mEntries;
entry_t *mCurrent;
- uint32_t mEntryCount;
- uint32_t mEntryAllocationCount;
+ /*uint32_t mEntryCount;
+ uint32_t mEntryAllocationCount;*/
};
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 040060e..d676f5e 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -126,11 +126,14 @@
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format)
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth, uint32_t reqHeight)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeInt32(dpy);
+ data.writeInt32(reqWidth);
+ data.writeInt32(reqHeight);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
*width = reply.readInt32();
@@ -208,10 +211,13 @@
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
+ uint32_t reqWidth = data.readInt32();
+ uint32_t reqHeight = data.readInt32();
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
- status_t res = captureScreen(dpy, &heap, &w, &h, &f);
+ status_t res = captureScreen(dpy, &heap, &w, &h, &f,
+ reqWidth, reqHeight);
reply->writeStrongBinder(heap->asBinder());
reply->writeInt32(w);
reply->writeInt32(h);
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 4096ac6..f270461 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -545,5 +545,55 @@
}
// ----------------------------------------------------------------------------
+
+ScreenshotClient::ScreenshotClient()
+ : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+}
+
+status_t ScreenshotClient::update() {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, 0, 0);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight);
+}
+
+void ScreenshotClient::release() {
+ mHeap = 0;
+}
+
+void const* ScreenshotClient::getPixels() const {
+ return mHeap->getBase();
+}
+
+uint32_t ScreenshotClient::getWidth() const {
+ return mWidth;
+}
+
+uint32_t ScreenshotClient::getHeight() const {
+ return mHeight;
+}
+
+PixelFormat ScreenshotClient::getFormat() const {
+ return mFormat;
+}
+
+uint32_t ScreenshotClient::getStride() const {
+ return mWidth;
+}
+
+size_t ScreenshotClient::getSize() const {
+ return mHeap->getSize();
+}
+
+// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index f2b029a..825febc 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -33,6 +33,9 @@
#include <math.h>
#define INDENT " "
+#define INDENT2 " "
+#define INDENT3 " "
+#define INDENT4 " "
namespace android {
@@ -63,6 +66,10 @@
return sqrtf(x * x + y * y);
}
+static inline const char* toString(bool value) {
+ return value ? "true" : "false";
+}
+
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
@@ -236,16 +243,14 @@
String8 name = mEventHub->getDeviceName(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- // Write a log message about the added device as a heading for subsequent log messages.
- LOGI("Device added: id=0x%x, name=%s", deviceId, name.string());
-
InputDevice* device = createDevice(deviceId, name, classes);
device->configure();
if (device->isIgnored()) {
- LOGI(INDENT "Sources: none (device is ignored)");
+ LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string());
} else {
- LOGI(INDENT "Sources: 0x%08x", device->getSources());
+ LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(),
+ device->getSources());
}
bool added = false;
@@ -287,7 +292,6 @@
return;
}
- // Write a log message about the removed device as a heading for subsequent log messages.
if (device->isIgnored()) {
LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
device->getId(), device->getName().string());
@@ -571,59 +575,15 @@
}
void InputReader::dump(String8& dump) {
- dumpDeviceInfo(dump);
-}
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
-static void dumpMotionRange(String8& dump,
- const char* name, const InputDeviceInfo::MotionRange* range) {
- if (range) {
- dump.appendFormat(" %s = { min: %0.3f, max: %0.3f, flat: %0.3f, fuzz: %0.3f }\n",
- name, range->min, range->max, range->flat, range->fuzz);
- }
-}
-
-#define DUMP_MOTION_RANGE(range) \
- dumpMotionRange(dump, #range, deviceInfo.getMotionRange(AINPUT_MOTION_RANGE_##range));
-
-void InputReader::dumpDeviceInfo(String8& dump) {
- Vector<int32_t> deviceIds;
- getInputDeviceIds(deviceIds);
-
- InputDeviceInfo deviceInfo;
- for (size_t i = 0; i < deviceIds.size(); i++) {
- int32_t deviceId = deviceIds[i];
-
- status_t result = getInputDeviceInfo(deviceId, & deviceInfo);
- if (result == NAME_NOT_FOUND) {
- continue;
- } else if (result != OK) {
- dump.appendFormat(" ** Unexpected error %d getting information about input devices.\n",
- result);
- continue;
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ mDevices.valueAt(i)->dump(dump);
}
-
- dump.appendFormat(" Device %d: '%s'\n",
- deviceInfo.getId(), deviceInfo.getName().string());
- dump.appendFormat(" sources = 0x%08x\n",
- deviceInfo.getSources());
- dump.appendFormat(" keyboardType = %d\n",
- deviceInfo.getKeyboardType());
-
- dump.append(" motion ranges:\n");
- DUMP_MOTION_RANGE(X);
- DUMP_MOTION_RANGE(Y);
- DUMP_MOTION_RANGE(PRESSURE);
- DUMP_MOTION_RANGE(SIZE);
- DUMP_MOTION_RANGE(TOUCH_MAJOR);
- DUMP_MOTION_RANGE(TOUCH_MINOR);
- DUMP_MOTION_RANGE(TOOL_MAJOR);
- DUMP_MOTION_RANGE(TOOL_MINOR);
- DUMP_MOTION_RANGE(ORIENTATION);
- }
+ } // release device registy reader lock
}
-#undef DUMP_MOTION_RANGE
-
// --- InputReaderThread ---
@@ -654,6 +614,43 @@
mMappers.clear();
}
+static void dumpMotionRange(String8& dump, const InputDeviceInfo& deviceInfo,
+ int32_t rangeType, const char* name) {
+ const InputDeviceInfo::MotionRange* range = deviceInfo.getMotionRange(rangeType);
+ if (range) {
+ dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+ name, range->min, range->max, range->flat, range->fuzz);
+ }
+}
+
+void InputDevice::dump(String8& dump) {
+ InputDeviceInfo deviceInfo;
+ getDeviceInfo(& deviceInfo);
+
+ dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(),
+ deviceInfo.getName().string());
+ dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+ dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+ if (!deviceInfo.getMotionRanges().isEmpty()) {
+ dump.append(INDENT2 "Motion Ranges:\n");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_X, "X");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_Y, "Y");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_PRESSURE, "Pressure");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_SIZE, "Size");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MAJOR, "TouchMajor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MINOR, "TouchMinor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MAJOR, "ToolMajor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MINOR, "ToolMinor");
+ dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_ORIENTATION, "Orientation");
+ }
+
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->dump(dump);
+ }
+}
+
void InputDevice::addMapper(InputMapper* mapper) {
mMappers.add(mapper);
}
@@ -763,6 +760,9 @@
info->addSource(getSources());
}
+void InputMapper::dump(String8& dump) {
+}
+
void InputMapper::configure() {
}
@@ -856,6 +856,19 @@
info->setKeyboardType(mKeyboardType);
}
+void KeyboardInputMapper::dump(String8& dump) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ dump.append(INDENT2 "Keyboard Input Mapper:\n");
+ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dump.appendFormat(INDENT3 "Sources: 0x%x\n", mSources);
+ dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
+ dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size());
+ dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState);
+ dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
+ } // release lock
+}
+
void KeyboardInputMapper::reset() {
for (;;) {
int32_t keyCode, scanCode;
@@ -980,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,
@@ -1044,6 +1060,18 @@
info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
}
+void TrackballInputMapper::dump(String8& dump) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ dump.append(INDENT2 "Trackball Input Mapper:\n");
+ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
+ dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
+ dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
+ dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
+ } // release lock
+}
+
void TrackballInputMapper::initializeLocked() {
mAccumulator.clear();
@@ -1275,6 +1303,21 @@
} // release lock
}
+void TouchInputMapper::dump(String8& dump) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ dump.append(INDENT2 "Touch Input Mapper:\n");
+ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dumpParameters(dump);
+ dumpVirtualKeysLocked(dump);
+ dumpRawAxes(dump);
+ dumpCalibration(dump);
+ dumpSurfaceLocked(dump);
+ dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mLocked.xPrecision);
+ dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mLocked.yPrecision);
+ } // release lock
+}
+
void TouchInputMapper::initializeLocked() {
mCurrentTouch.clear();
mLastTouch.clear();
@@ -1301,16 +1344,13 @@
// Configure basic parameters.
configureParameters();
- logParameters();
// Configure absolute axis information.
configureRawAxes();
- logRawAxes();
// Prepare input device calibration.
parseCalibration();
resolveCalibration();
- logCalibration();
{ // acquire lock
AutoMutex _l(mLock);
@@ -1326,16 +1366,13 @@
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
}
-void TouchInputMapper::logParameters() {
- if (mParameters.useBadTouchFilter) {
- LOGI(INDENT "Bad touch filter enabled.");
- }
- if (mParameters.useAveragingTouchFilter) {
- LOGI(INDENT "Averaging touch filter enabled.");
- }
- if (mParameters.useJumpyTouchFilter) {
- LOGI(INDENT "Jumpy touch filter enabled.");
- }
+void TouchInputMapper::dumpParameters(String8& dump) {
+ dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n",
+ toString(mParameters.useBadTouchFilter));
+ dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n",
+ toString(mParameters.useAveragingTouchFilter));
+ dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n",
+ toString(mParameters.useJumpyTouchFilter));
}
void TouchInputMapper::configureRawAxes() {
@@ -1349,24 +1386,25 @@
mRawAxes.orientation.clear();
}
-static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) {
+static void dumpAxisInfo(String8& dump, RawAbsoluteAxisInfo axis, const char* name) {
if (axis.valid) {
- LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d",
+ dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n",
name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
} else {
- LOGI(INDENT "Raw %s axis: unknown range", name);
+ dump.appendFormat(INDENT4 "%s: unknown range\n", name);
}
}
-void TouchInputMapper::logRawAxes() {
- logAxisInfo(mRawAxes.x, "x");
- logAxisInfo(mRawAxes.y, "y");
- logAxisInfo(mRawAxes.pressure, "pressure");
- logAxisInfo(mRawAxes.touchMajor, "touchMajor");
- logAxisInfo(mRawAxes.touchMinor, "touchMinor");
- logAxisInfo(mRawAxes.toolMajor, "toolMajor");
- logAxisInfo(mRawAxes.toolMinor, "toolMinor");
- logAxisInfo(mRawAxes.orientation, "orientation");
+void TouchInputMapper::dumpRawAxes(String8& dump) {
+ dump.append(INDENT3 "Raw Axes:\n");
+ dumpAxisInfo(dump, mRawAxes.x, "X");
+ dumpAxisInfo(dump, mRawAxes.y, "Y");
+ dumpAxisInfo(dump, mRawAxes.pressure, "Pressure");
+ dumpAxisInfo(dump, mRawAxes.touchMajor, "TouchMajor");
+ dumpAxisInfo(dump, mRawAxes.touchMinor, "TouchMinor");
+ dumpAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor");
+ dumpAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor");
+ dumpAxisInfo(dump, mRawAxes.orientation, "Orientation");
}
bool TouchInputMapper::configureSurfaceLocked() {
@@ -1391,10 +1429,8 @@
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
- LOGI("Device reconfigured (display size changed): id=0x%x, name=%s",
- getDeviceId(), getDeviceName().string());
- LOGI(INDENT "Width: %dpx", width);
- LOGI(INDENT "Height: %dpx", height);
+ LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d",
+ getDeviceId(), getDeviceName().string(), width, height);
mLocked.surfaceWidth = width;
mLocked.surfaceHeight = height;
@@ -1562,39 +1598,13 @@
mLocked.orientedRanges.y.fuzz = orientedYScale;
}
- if (sizeChanged) {
- logMotionRangesLocked();
- }
-
return true;
}
-static void logMotionRangeInfo(InputDeviceInfo::MotionRange* range, const char* name) {
- if (range) {
- LOGI(INDENT "Output %s range: min=%f, max=%f, flat=%f, fuzz=%f",
- name, range->min, range->max, range->flat, range->fuzz);
- } else {
- LOGI(INDENT "Output %s range: unsupported", name);
- }
-}
-
-void TouchInputMapper::logMotionRangesLocked() {
- logMotionRangeInfo(& mLocked.orientedRanges.x, "x");
- logMotionRangeInfo(& mLocked.orientedRanges.y, "y");
- logMotionRangeInfo(mLocked.orientedRanges.havePressure
- ? & mLocked.orientedRanges.pressure : NULL, "pressure");
- logMotionRangeInfo(mLocked.orientedRanges.haveSize
- ? & mLocked.orientedRanges.size : NULL, "size");
- logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
- ? & mLocked.orientedRanges.touchMajor : NULL, "touchMajor");
- logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea
- ? & mLocked.orientedRanges.touchMinor : NULL, "touchMinor");
- logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
- ? & mLocked.orientedRanges.toolMajor : NULL, "toolMajor");
- logMotionRangeInfo(mLocked.orientedRanges.haveToolArea
- ? & mLocked.orientedRanges.toolMinor : NULL, "toolMinor");
- logMotionRangeInfo(mLocked.orientedRanges.haveOrientation
- ? & mLocked.orientedRanges.orientation : NULL, "orientation");
+void TouchInputMapper::dumpSurfaceLocked(String8& dump) {
+ dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mLocked.surfaceWidth);
+ dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mLocked.surfaceHeight);
+ dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mLocked.surfaceOrientation);
}
void TouchInputMapper::configureVirtualKeysLocked() {
@@ -1651,9 +1661,21 @@
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
- LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
- virtualKey.scanCode, virtualKey.keyCode,
- virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+ }
+}
+
+void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) {
+ if (!mLocked.virtualKeys.isEmpty()) {
+ dump.append(INDENT3 "Virtual Keys:\n");
+
+ for (size_t i = 0; i < mLocked.virtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mLocked.virtualKeys.itemAt(i);
+ dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, "
+ "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
+ i, virtualKey.scanCode, virtualKey.keyCode,
+ virtualKey.hitLeft, virtualKey.hitRight,
+ virtualKey.hitTop, virtualKey.hitBottom);
+ }
}
}
@@ -1861,19 +1883,19 @@
}
}
-void TouchInputMapper::logCalibration() {
- LOGI(INDENT "Calibration:");
+void TouchInputMapper::dumpCalibration(String8& dump) {
+ dump.append(INDENT3 "Calibration:\n");
// Touch Area
switch (mCalibration.touchAreaCalibration) {
case Calibration::TOUCH_AREA_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.touchArea.calibration: none");
+ dump.append(INDENT4 "touch.touchArea.calibration: none\n");
break;
case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
- LOGI(INDENT INDENT "touch.touchArea.calibration: geometric");
+ dump.append(INDENT4 "touch.touchArea.calibration: geometric\n");
break;
case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
- LOGI(INDENT INDENT "touch.touchArea.calibration: pressure");
+ dump.append(INDENT4 "touch.touchArea.calibration: pressure\n");
break;
default:
assert(false);
@@ -1882,40 +1904,43 @@
// Tool Area
switch (mCalibration.toolAreaCalibration) {
case Calibration::TOOL_AREA_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.toolArea.calibration: none");
+ dump.append(INDENT4 "touch.toolArea.calibration: none\n");
break;
case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
- LOGI(INDENT INDENT "touch.toolArea.calibration: geometric");
+ dump.append(INDENT4 "touch.toolArea.calibration: geometric\n");
break;
case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
- LOGI(INDENT INDENT "touch.toolArea.calibration: linear");
+ dump.append(INDENT4 "touch.toolArea.calibration: linear\n");
break;
default:
assert(false);
}
if (mCalibration.haveToolAreaLinearScale) {
- LOGI(INDENT INDENT "touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale);
+ dump.appendFormat(INDENT4 "touch.toolArea.linearScale: %0.3f\n",
+ mCalibration.toolAreaLinearScale);
}
if (mCalibration.haveToolAreaLinearBias) {
- LOGI(INDENT INDENT "touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias);
+ dump.appendFormat(INDENT4 "touch.toolArea.linearBias: %0.3f\n",
+ mCalibration.toolAreaLinearBias);
}
if (mCalibration.haveToolAreaIsSummed) {
- LOGI(INDENT INDENT "touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed);
+ dump.appendFormat(INDENT4 "touch.toolArea.isSummed: %d\n",
+ mCalibration.toolAreaIsSummed);
}
// Pressure
switch (mCalibration.pressureCalibration) {
case Calibration::PRESSURE_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.pressure.calibration: none");
+ dump.append(INDENT4 "touch.pressure.calibration: none\n");
break;
case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
- LOGI(INDENT INDENT "touch.pressure.calibration: physical");
+ dump.append(INDENT4 "touch.pressure.calibration: physical\n");
break;
case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
- LOGI(INDENT INDENT "touch.pressure.calibration: amplitude");
+ dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
break;
default:
assert(false);
@@ -1923,10 +1948,10 @@
switch (mCalibration.pressureSource) {
case Calibration::PRESSURE_SOURCE_PRESSURE:
- LOGI(INDENT INDENT "touch.pressure.source: pressure");
+ dump.append(INDENT4 "touch.pressure.source: pressure\n");
break;
case Calibration::PRESSURE_SOURCE_TOUCH:
- LOGI(INDENT INDENT "touch.pressure.source: touch");
+ dump.append(INDENT4 "touch.pressure.source: touch\n");
break;
case Calibration::PRESSURE_SOURCE_DEFAULT:
break;
@@ -1935,16 +1960,17 @@
}
if (mCalibration.havePressureScale) {
- LOGI(INDENT INDENT "touch.pressure.scale: %f", mCalibration.pressureScale);
+ dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
+ mCalibration.pressureScale);
}
// Size
switch (mCalibration.sizeCalibration) {
case Calibration::SIZE_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.size.calibration: none");
+ dump.append(INDENT4 "touch.size.calibration: none\n");
break;
case Calibration::SIZE_CALIBRATION_NORMALIZED:
- LOGI(INDENT INDENT "touch.size.calibration: normalized");
+ dump.append(INDENT4 "touch.size.calibration: normalized\n");
break;
default:
assert(false);
@@ -1953,10 +1979,10 @@
// Orientation
switch (mCalibration.orientationCalibration) {
case Calibration::ORIENTATION_CALIBRATION_NONE:
- LOGI(INDENT INDENT "touch.orientation.calibration: none");
+ dump.append(INDENT4 "touch.orientation.calibration: none\n");
break;
case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
- LOGI(INDENT INDENT "touch.orientation.calibration: interpolated");
+ dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
break;
default:
assert(false);
@@ -2139,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/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 890786e..587c8ff 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -316,6 +316,7 @@
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
+ mCblk->flags &= ~CBLK_DISABLED_ON;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -842,6 +843,13 @@
cblk->lock.unlock();
}
+ // restart track if it was disabled by audioflinger due to previous underrun
+ if (cblk->flags & CBLK_DISABLED_MSK) {
+ cblk->flags &= ~CBLK_DISABLED_ON;
+ LOGW("obtainBuffer() track %p disabled, restarting", this);
+ mAudioTrack->start();
+ }
+
cblk->waitTimeMs = 0;
if (framesReq > framesAvail) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 97c9003..8e50d39 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -276,20 +276,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/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index e6c2f7e..546df47 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1118,7 +1118,7 @@
startTimeUs = 0;
}
- mIsRealTimeRecording = true;
+ mIsRealTimeRecording = false;
{
int32_t isNotRealTime;
if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
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/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index eb86277..ce10f5b 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -159,7 +159,7 @@
try {
return ObbScanner.getObbInfo(filename);
} catch (IOException e) {
- Log.d(TAG, "Couldn't get OBB info", e);
+ Log.d(TAG, "Couldn't get OBB info for " + filename);
return null;
}
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 3980189..8de507e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -80,7 +80,7 @@
<bool name="def_accessibility_script_injection">false</bool>
<!-- Default for Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS -->
- <string name="def_accessibility_web_content_key_bindings">
+ <string name="def_accessibility_web_content_key_bindings" translatable="false">
<!-- DPAD/Trackball UP maps to traverse previous on current axis and send an event. -->
0x13=0x01000100;
<!-- DPAD/Trackball DOWN maps to traverse next on current axis and send an event. -->
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c047522..c70f5d4 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -89,6 +89,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
@@ -152,8 +153,11 @@
// responsible for power management when displayed.
static final int KEYGUARD_LAYER = 14;
static final int KEYGUARD_DIALOG_LAYER = 15;
+ // the drag layer: input for drag-and-drop is associated with this window,
+ // which sits above all other focusable windows
+ static final int DRAG_LAYER = 16;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 16;
+ static final int SYSTEM_OVERLAY_LAYER = 17;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -839,6 +843,8 @@
return TOAST_LAYER;
case TYPE_WALLPAPER:
return WALLPAPER_LAYER;
+ case TYPE_DRAG:
+ return DRAG_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -1544,7 +1550,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/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 97b8086..8527059 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1856,6 +1856,8 @@
if (--(track->mRetryCount) <= 0) {
LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
tracksToRemove->add(track);
+ // indicate to client process that the track was disabled because of underrun
+ cblk->flags |= CBLK_DISABLED_ON;
} else if (mixerStatus != MIXER_TRACKS_READY) {
mixerStatus = MIXER_TRACKS_ENABLED;
}
@@ -2790,7 +2792,7 @@
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
+ // written to buffer (other flags are cleared)
mCblk->flags = CBLK_UNDERRUN_ON;
} else {
mBuffer = sharedBuffer->pointer();
@@ -2813,7 +2815,7 @@
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
+ // written to buffer (other flags are cleared)
mCblk->flags = CBLK_UNDERRUN_ON;
mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
@@ -3794,6 +3796,8 @@
AudioBufferProvider::Buffer buffer;
sp<RecordTrack> activeTrack;
+ nsecs_t lastWarning = 0;
+
// start recording
while (!exitPending()) {
@@ -3935,8 +3939,13 @@
}
// client isn't retrieving buffers fast enough
else {
- if (!mActiveTrack->setOverflow())
- LOGW("RecordThread: buffer overflow");
+ if (!mActiveTrack->setOverflow()) {
+ nsecs_t now = systemTime();
+ if ((now - lastWarning) > kWarningThrottle) {
+ LOGW("RecordThread: buffer overflow");
+ lastWarning = now;
+ }
+ }
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6095117..880befd 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -68,7 +68,7 @@
*/
public class ConnectivityService extends IConnectivityManager.Stub {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String TAG = "ConnectivityService";
// how long to wait before switching back to a radio's default network
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 0c3a0e6..28126b9 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -58,6 +58,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -605,6 +606,8 @@
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (XmlPullParserException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (FileNotFoundException e) {
+ // Don't be noisy, this is normal if we haven't defined any policies.
} catch (IOException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (IndexOutOfBoundsException e) {
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index fe306b3..a960097 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -342,6 +342,7 @@
if (toChannel == null) {
throw new IllegalArgumentException("toChannel must not be null.");
}
+ Slog.d(TAG, "transferring touch focus");
return nativeTransferTouchFocus(fromChannel, toChannel);
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 675760f..de28375 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -951,10 +951,11 @@
}
public void updateStatusIcon(IBinder token, String packageName, int iconId) {
+ int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
if (token == null || mCurToken != token) {
- Slog.w(TAG, "Ignoring setInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring setInputMethod of uid " + uid + " token: " + token);
return;
}
@@ -1048,6 +1049,7 @@
public boolean showSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
+ int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
synchronized (mMethodMap) {
@@ -1058,7 +1060,7 @@
// focus in the window manager, to allow this call to
// be made before input is started in it.
if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Slog.w(TAG, "Ignoring showSoftInput of: " + client);
+ Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
return false;
}
} catch (RemoteException e) {
@@ -1112,6 +1114,7 @@
public boolean hideSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
+ int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
synchronized (mMethodMap) {
@@ -1122,7 +1125,8 @@
// focus in the window manager, to allow this call to
// be made before input is started in it.
if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Slog.w(TAG, "Ignoring hideSoftInput of: " + client);
+ if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
+ + uid + ": " + client);
return false;
}
} catch (RemoteException e) {
@@ -1257,7 +1261,8 @@
synchronized (mMethodMap) {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
- Slog.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client);
+ Slog.w(TAG, "Ignoring showInputMethodDialogFromClient of uid "
+ + Binder.getCallingUid() + ": " + client);
}
mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER);
@@ -1290,7 +1295,8 @@
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
} else if (mCurToken != token) {
- Slog.w(TAG, "Ignoring setInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
+ + " token: " + token);
return;
}
@@ -1306,7 +1312,8 @@
public void hideMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
if (token == null || mCurToken != token) {
- Slog.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ if (DEBUG) Slog.w(TAG, "Ignoring hideInputMethod of uid "
+ + Binder.getCallingUid() + " token: " + token);
return;
}
long ident = Binder.clearCallingIdentity();
@@ -1321,7 +1328,8 @@
public void showMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
if (token == null || mCurToken != token) {
- Slog.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring showMySoftInput of uid "
+ + Binder.getCallingUid() + " token: " + token);
return;
}
long ident = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 8ab65e9..e47de13 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -28,6 +28,7 @@
import java.util.Set;
import android.util.Log;
+import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.LogPrinter;
import android.util.Printer;
@@ -92,10 +93,12 @@
}
boolean dumpMap(PrintWriter out, String titlePrefix, String title,
- String prefix, Map<String, ArrayList<F>> map, String packageName) {
+ String prefix, Map<String, ArrayList<F>> map, String packageName,
+ boolean printFilter) {
String eprefix = prefix + " ";
String fprefix = prefix + " ";
boolean printedSomething = false;
+ Printer printer = null;
for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) {
ArrayList<F> a = e.getValue();
final int N = a.size();
@@ -115,37 +118,44 @@
}
printedSomething = true;
dumpFilter(out, fprefix, filter);
+ if (printFilter) {
+ if (printer == null) {
+ printer = new PrintWriterPrinter(out);
+ }
+ filter.dump(printer, fprefix + " ");
+ }
}
}
return printedSomething;
}
- public boolean dump(PrintWriter out, String title, String prefix, String packageName) {
+ public boolean dump(PrintWriter out, String title, String prefix, String packageName,
+ boolean printFilter) {
String innerPrefix = prefix + " ";
String sepPrefix = "\n" + prefix;
String curPrefix = title + "\n" + prefix;
if (dumpMap(out, curPrefix, "Full MIME Types:", innerPrefix,
- mTypeToFilter, packageName)) {
+ mTypeToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
if (dumpMap(out, curPrefix, "Base MIME Types:", innerPrefix,
- mBaseTypeToFilter, packageName)) {
+ mBaseTypeToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
if (dumpMap(out, curPrefix, "Wild MIME Types:", innerPrefix,
- mWildTypeToFilter, packageName)) {
+ mWildTypeToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
if (dumpMap(out, curPrefix, "Schemes:", innerPrefix,
- mSchemeToFilter, packageName)) {
+ mSchemeToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
if (dumpMap(out, curPrefix, "Non-Data Actions:", innerPrefix,
- mActionToFilter, packageName)) {
+ mActionToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
if (dumpMap(out, curPrefix, "MIME Typed Actions:", innerPrefix,
- mTypedActionToFilter, packageName)) {
+ mTypedActionToFilter, packageName, printFilter)) {
curPrefix = sepPrefix;
}
return curPrefix == sepPrefix;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index ca8fc52..7870b06 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.internal.app.IMediaContainerService;
+import com.android.internal.util.HexDump;
import com.android.server.am.ActivityManagerService;
import android.content.BroadcastReceiver;
@@ -44,15 +45,22 @@
import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
import android.os.storage.StorageResultCode;
+import android.security.MessageDigest;
import android.util.Slog;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
/**
* MountService implements back-end services for platform storage
@@ -71,6 +79,8 @@
private static final String VOLD_TAG = "VoldConnector";
+ protected static final int MAX_OBBS = 8;
+
/*
* Internal vold volume state constants
*/
@@ -151,15 +161,19 @@
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
- final private Map<IObbActionListener, List<ObbState>> mObbMounts = new HashMap<IObbActionListener, List<ObbState>>();
+ final private Map<Integer, Integer> mObbUidUsage = new HashMap<Integer, Integer>();
+ final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
class ObbState implements IBinder.DeathRecipient {
- public ObbState(String filename, IObbActionListener token, int callerUid) {
+ public ObbState(String filename, IObbActionListener token, int callerUid)
+ throws RemoteException {
this.filename = filename;
this.token = token;
this.callerUid = callerUid;
mounted = false;
+
+ getBinder().linkToDeath(this, 0);
}
// OBB source filename
@@ -174,14 +188,33 @@
// Whether this is mounted currently.
boolean mounted;
+ public IBinder getBinder() {
+ return token.asBinder();
+ }
+
@Override
public void binderDied() {
ObbAction action = new UnmountObbAction(this, true);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
+ }
- removeObbState(this);
+ public void cleanUp() {
+ getBinder().unlinkToDeath(this, 0);
+ }
- token.asBinder().unlinkToDeath(this, 0);
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("ObbState{");
+ sb.append("filename=");
+ sb.append(filename);
+ sb.append(",token=");
+ sb.append(token.toString());
+ sb.append(",callerUid=");
+ sb.append(callerUid);
+ sb.append(",mounted=");
+ sb.append(mounted);
+ sb.append('}');
+ return sb.toString();
}
}
@@ -481,6 +514,34 @@
mPms.updateExternalMediaStatus(true, false);
}
}
+
+ // Remove all OBB mappings and listeners from this path
+ synchronized (mObbMounts) {
+ final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
+
+ final Iterator<Entry<String, ObbState>> i = mObbPathToStateMap.entrySet().iterator();
+ while (i.hasNext()) {
+ final Entry<String, ObbState> obbEntry = i.next();
+
+ // If this entry's source file is in the volume path that got
+ // unmounted, remove it because it's no longer valid.
+ if (obbEntry.getKey().startsWith(path)) {
+ obbStatesToRemove.add(obbEntry.getValue());
+ }
+ }
+
+ for (final ObbState obbState : obbStatesToRemove) {
+ removeObbState(obbState);
+
+ try {
+ obbState.token.onObbResult(obbState.filename, Environment.MEDIA_UNMOUNTED);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Couldn't send unmount notification for OBB: "
+ + obbState.filename);
+ }
+ }
+ }
+
String oldState = mLegacyState;
mLegacyState = state;
@@ -1507,11 +1568,18 @@
public boolean isObbMounted(String filename) {
synchronized (mObbMounts) {
- return mObbPathToStateMap.containsKey(filename);
+ final ObbState obbState = mObbPathToStateMap.get(filename);
+ if (obbState != null) {
+ synchronized (obbState) {
+ return obbState.mounted;
+ }
+ }
}
+ return false;
}
- public void mountObb(String filename, String key, IObbActionListener token) {
+ public void mountObb(String filename, String key, IObbActionListener token)
+ throws RemoteException {
waitForReady();
warnOnNotMounted();
@@ -1525,21 +1593,44 @@
synchronized (mObbMounts) {
if (isObbMounted(filename)) {
- throw new IllegalArgumentException("OBB file is already mounted");
+ try {
+ token.onObbResult(filename, Environment.MEDIA_MOUNTED);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Could not send unmount notification for: " + filename);
+ }
+ return;
}
final int callerUid = Binder.getCallingUid();
+
+ final Integer uidUsage = mObbUidUsage.get(callerUid);
+ if (uidUsage != null && uidUsage > MAX_OBBS) {
+ throw new IllegalStateException("Maximum number of OBBs mounted!");
+ }
+
obbState = new ObbState(filename, token, callerUid);
addObbState(obbState);
}
- try {
- token.asBinder().linkToDeath(obbState, 0);
- } catch (RemoteException rex) {
- Slog.e(TAG, "Failed to link to listener death");
+ String hashedKey = null;
+ if (key != null) {
+ final MessageDigest md;
+ try {
+ 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;
+ }
+
+ hashedKey = HexDump.toHexString(md.digest(key.getBytes()));
}
- MountObbAction action = new MountObbAction(obbState, key);
+ ObbAction action = new MountObbAction(obbState, hashedKey);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
@@ -1557,18 +1648,24 @@
synchronized (mObbMounts) {
if (!isObbMounted(filename)) {
- throw new IllegalArgumentException("OBB is not mounted");
+ try {
+ token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Could not send unmount notification for: " + filename);
+ }
+ return;
}
+
obbState = mObbPathToStateMap.get(filename);
if (Binder.getCallingUid() != obbState.callerUid) {
throw new SecurityException("caller UID does not match original mount caller UID");
- } else if (!token.asBinder().equals(obbState.token.asBinder())) {
+ } else if (!token.asBinder().equals(obbState.getBinder())) {
throw new SecurityException("caller does not match original mount caller");
}
}
- UnmountObbAction action = new UnmountObbAction(obbState, force);
+ ObbAction action = new UnmountObbAction(obbState, force);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
@@ -1577,26 +1674,57 @@
private void addObbState(ObbState obbState) {
synchronized (mObbMounts) {
- List<ObbState> obbStates = mObbMounts.get(obbState.token);
+ List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
if (obbStates == null) {
obbStates = new ArrayList<ObbState>();
- mObbMounts.put(obbState.token, obbStates);
+ mObbMounts.put(obbState.getBinder(), obbStates);
}
obbStates.add(obbState);
mObbPathToStateMap.put(obbState.filename, obbState);
+
+ // Track the number of OBBs used by this UID.
+ final int uid = obbState.callerUid;
+ final Integer uidUsage = mObbUidUsage.get(uid);
+ if (uidUsage == null) {
+ mObbUidUsage.put(uid, 1);
+ } else {
+ mObbUidUsage.put(uid, uidUsage + 1);
+ }
}
}
private void removeObbState(ObbState obbState) {
synchronized (mObbMounts) {
- final List<ObbState> obbStates = mObbMounts.get(obbState.token);
+ final List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
if (obbStates != null) {
obbStates.remove(obbState);
}
if (obbStates == null || obbStates.isEmpty()) {
- mObbMounts.remove(obbState.token);
+ mObbMounts.remove(obbState.getBinder());
+ obbState.cleanUp();
}
mObbPathToStateMap.remove(obbState.filename);
+
+ // Track the number of OBBs used by this UID.
+ final int uid = obbState.callerUid;
+ final Integer uidUsage = mObbUidUsage.get(uid);
+ if (uidUsage == null) {
+ Slog.e(TAG, "Called removeObbState for UID that isn't in map: " + uid);
+ } else {
+ final int newUsage = uidUsage - 1;
+ if (newUsage == 0) {
+ mObbUidUsage.remove(uid);
+ } else {
+ mObbUidUsage.put(uid, newUsage);
+ }
+ }
+ }
+ }
+
+ private void replaceObbState(ObbState oldObbState, ObbState newObbState) {
+ synchronized (mObbMounts) {
+ removeObbState(oldObbState);
+ addObbState(newObbState);
}
}
@@ -1627,20 +1755,16 @@
Slog.e(TAG, "Failed to bind to media container service");
action.handleError();
return;
- } else {
- // Once we bind to the service, the first
- // pending request will be processed.
- mActions.add(action);
- }
- } else {
- // Already bound to the service. Just make
- // sure we trigger off processing the first request.
- if (mActions.size() == 0) {
- mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
}
mActions.add(action);
+ break;
}
+
+ // Once we bind to the service, the first
+ // pending request will be processed.
+ mActions.add(action);
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
break;
}
case OBB_MCS_BOUND: {
@@ -1773,6 +1897,29 @@
abstract void handleExecute() throws RemoteException, IOException;
abstract void handleError();
+
+ protected ObbInfo getObbInfo() throws IOException {
+ ObbInfo obbInfo;
+ try {
+ obbInfo = mContainerService.getObbInfo(mObbState.filename);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
+ + mObbState.filename);
+ obbInfo = null;
+ }
+ if (obbInfo == null) {
+ throw new IOException("Couldn't read OBB file: " + mObbState.filename);
+ }
+ return obbInfo;
+ }
+
+ protected void sendNewStatusOrIgnore(String filename, String status) {
+ try {
+ mObbState.token.onObbResult(filename, status);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ }
+ }
}
class MountObbAction extends ObbAction {
@@ -1783,56 +1930,90 @@
mKey = key;
}
- public void handleExecute() throws RemoteException, IOException {
- final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
- if (obbInfo == null) {
- throw new IOException("Couldn't read OBB file: " + mObbState.filename);
+ public void handleExecute() throws IOException, RemoteException {
+ final ObbInfo obbInfo = getObbInfo();
+
+ /*
+ * If someone tried to trick us with some weird characters, rectify
+ * it here.
+ */
+ if (!mObbState.filename.equals(obbInfo.filename)) {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB filename " + mObbState.filename + " is actually "
+ + obbInfo.filename);
+
+ synchronized (mObbMounts) {
+ /*
+ * If the real filename is already mounted, discard this
+ * state and notify the caller that the OBB is already
+ * mounted.
+ */
+ if (isObbMounted(obbInfo.filename)) {
+ if (DEBUG_OBB)
+ Slog.i(TAG, "OBB already mounted as " + obbInfo.filename);
+
+ removeObbState(mObbState);
+ sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_MOUNTED);
+ return;
+ }
+
+ /*
+ * It's not already mounted, so we have to replace the state
+ * with the state containing the actual filename.
+ */
+ ObbState newObbState = new ObbState(obbInfo.filename, mObbState.token,
+ mObbState.callerUid);
+ replaceObbState(mObbState, newObbState);
+ mObbState = newObbState;
+ }
}
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
- if (mKey == null) {
- mKey = "none";
- }
-
- int rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
- mObbState.callerUid);
- try {
- mConnector.doCommand(cmd);
- } catch (NativeDaemonConnectorException e) {
- int code = e.getCode();
- if (code != VoldResponseCode.OpFailedStorageBusy) {
- rc = StorageResultCode.OperationFailedInternalError;
+ boolean mounted = false;
+ int rc;
+ synchronized (mObbState) {
+ if (mObbState.mounted) {
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
+ return;
}
- }
- if (rc == StorageResultCode.OperationSucceeded) {
+ rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("obb mount %s %s %d", mObbState.filename,
+ mKey != null ? mKey : "none",
+ mObbState.callerUid);
try {
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_MOUNTED);
- } catch (RemoteException e) {
- Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code != VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
}
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ mObbState.mounted = mounted = true;
+ }
+ }
+
+ if (mounted) {
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
} else {
Slog.e(TAG, "Couldn't mount OBB file: " + rc);
// We didn't succeed, so remove this from the mount-set.
removeObbState(mObbState);
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
}
}
public void handleError() {
removeObbState(mObbState);
- try {
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
- } catch (RemoteException e) {
- Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename);
- }
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
}
@Override
@@ -1858,51 +2039,69 @@
mForceUnmount = force;
}
- public void handleExecute() throws RemoteException, IOException {
- final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
- if (obbInfo == null) {
- throw new IOException("Couldn't read OBB file: " + mObbState.filename);
- }
+ public void handleExecute() throws IOException {
+ final ObbInfo obbInfo = getObbInfo();
- int rc = StorageResultCode.OperationSucceeded;
- String cmd = String.format("obb unmount %s%s", mObbState.filename,
- (mForceUnmount ? " force" : ""));
- try {
- mConnector.doCommand(cmd);
- } catch (NativeDaemonConnectorException e) {
- int code = e.getCode();
- if (code == VoldResponseCode.OpFailedStorageBusy) {
- rc = StorageResultCode.OperationFailedStorageBusy;
- } else {
- rc = StorageResultCode.OperationFailedInternalError;
+ /*
+ * If someone tried to trick us with some weird characters, rectify
+ * it here.
+ */
+ synchronized (mObbMounts) {
+ if (!isObbMounted(obbInfo.filename)) {
+ removeObbState(mObbState);
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
+ return;
+ }
+
+ if (!mObbState.filename.equals(obbInfo.filename)) {
+ removeObbState(mObbState);
+ mObbState = mObbPathToStateMap.get(obbInfo.filename);
}
}
- if (rc == StorageResultCode.OperationSucceeded) {
+ boolean unmounted = false;
+ synchronized (mObbState) {
+ if (!mObbState.mounted) {
+ sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_UNMOUNTED);
+ return;
+ }
+
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("obb unmount %s%s", mObbState.filename,
+ (mForceUnmount ? " force" : ""));
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
+ // If it's not mounted then we've already won.
+ rc = StorageResultCode.OperationSucceeded;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
+ }
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ mObbState.mounted = false;
+ unmounted = true;
+ }
+ }
+
+ if (unmounted) {
removeObbState(mObbState);
- try {
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_UNMOUNTED);
- } catch (RemoteException e) {
- Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
- }
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
} else {
- try {
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
- } catch (RemoteException e) {
- Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
- }
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
}
}
public void handleError() {
removeObbState(mObbState);
- try {
- mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
- } catch (RemoteException e) {
- Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename);
- }
+ sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
}
@Override
@@ -1917,9 +2116,33 @@
sb.append(mObbState.callerUid);
sb.append(",token=");
sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
+ sb.append(",binder=");
+ sb.append(mObbState.getBinder().toString());
sb.append('}');
return sb.toString();
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump ActivityManager from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " without permission " + android.Manifest.permission.DUMP);
+ return;
+ }
+
+ pw.println(" mObbMounts:");
+
+ synchronized (mObbMounts) {
+ final Collection<List<ObbState>> obbStateLists = mObbMounts.values();
+
+ for (final List<ObbState> obbStates : obbStateLists) {
+ for (final ObbState obbState : obbStates) {
+ pw.print(" "); pw.println(obbState.toString());
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 05abd99..8dbd3e7 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -55,7 +55,7 @@
class NetworkManagementService extends INetworkManagementService.Stub {
private static final String TAG = "NetworkManagmentService";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String NETD_TAG = "NetdConnector";
class NetdResponseCode {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 8f90756..1f97bee 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1102,27 +1102,6 @@
final File permFile = new File(Environment.getRootDirectory(),
"etc/permissions/platform.xml");
readPermissionsFromXml(permFile);
-
- StringBuilder sb = new StringBuilder(128);
- sb.append("Libs:");
- Iterator<String> it = mSharedLibraries.keySet().iterator();
- while (it.hasNext()) {
- sb.append(' ');
- String name = it.next();
- sb.append(name);
- sb.append(':');
- sb.append(mSharedLibraries.get(name));
- }
- Log.i(TAG, sb.toString());
-
- sb.setLength(0);
- sb.append("Features:");
- it = mAvailableFeatures.keySet().iterator();
- while (it.hasNext()) {
- sb.append(' ');
- sb.append(it.next());
- }
- Log.i(TAG, sb.toString());
}
private void readPermissionsFromXml(File permFile) {
@@ -2632,7 +2611,7 @@
// The system package has been updated and the code path does not match
// Ignore entry. Skip it.
Log.i(TAG, "Package " + ps.name + " at " + scanFile
- + "ignored: updated version " + ps.versionCode
+ + " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
return null;
@@ -6866,7 +6845,18 @@
return;
}
+ boolean dumpStar = true;
+ boolean dumpLibs = false;
+ boolean dumpFeatures = false;
+ boolean dumpResolvers = false;
+ boolean dumpPermissions = false;
+ boolean dumpPackages = false;
+ boolean dumpSharedUsers = false;
+ boolean dumpMessages = false;
+ boolean dumpProviders = false;
+
String packageName = null;
+ boolean showFilters = false;
int opti = 0;
while (opti < args.length) {
@@ -6879,10 +6869,22 @@
// Right now we only know how to print all.
} else if ("-h".equals(opt)) {
pw.println("Package manager dump options:");
- pw.println(" [-h] [cmd] ...");
+ pw.println(" [-h] [-f] [cmd] ...");
+ pw.println(" -f: print details of intent filters");
+ pw.println(" -h: print this help");
pw.println(" cmd may be one of:");
- pw.println(" [package.name]: info about given package");
+ pw.println(" l[ibraries]: list known shared libraries");
+ pw.println(" f[ibraries]: list device features");
+ pw.println(" r[esolvers]: dump intent resolvers");
+ pw.println(" perm[issions]: dump permissions");
+ pw.println(" prov[iders]: dump content providers");
+ pw.println(" p[ackages]: dump installed packages");
+ pw.println(" s[hared-users]: dump shared user IDs");
+ pw.println(" m[essages]: print collected runtime messages");
+ pw.println(" <package.name>: info about given package");
return;
+ } else if ("-f".equals(opt)) {
+ showFilters = true;
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
@@ -6895,32 +6897,87 @@
// Is this a package name?
if ("android".equals(cmd) || cmd.contains(".")) {
packageName = cmd;
+ } else if ("l".equals(cmd) || "libraries".equals(cmd)) {
+ dumpStar = false;
+ dumpLibs = true;
+ } else if ("f".equals(cmd) || "features".equals(cmd)) {
+ dumpStar = false;
+ dumpFeatures = true;
+ } else if ("r".equals(cmd) || "resolvers".equals(cmd)) {
+ dumpStar = false;
+ dumpResolvers = true;
+ } else if ("perm".equals(cmd) || "permissions".equals(cmd)) {
+ dumpStar = false;
+ dumpPermissions = true;
+ } else if ("p".equals(cmd) || "packages".equals(cmd)) {
+ dumpStar = false;
+ dumpPackages = true;
+ } else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
+ dumpStar = false;
+ dumpSharedUsers = true;
+ } else if ("prov".equals(cmd) || "providers".equals(cmd)) {
+ dumpStar = false;
+ dumpProviders = true;
+ } else if ("m".equals(cmd) || "messages".equals(cmd)) {
+ dumpStar = false;
+ dumpMessages = true;
}
}
boolean printedTitle = false;
synchronized (mPackages) {
- if (mActivities.dump(pw, "Activity Resolver Table:", " ", packageName)) {
+ if ((dumpStar || dumpLibs) && packageName == null) {
+ if (printedTitle) pw.println(" ");
printedTitle = true;
+ pw.println("Libraries:");
+ Iterator<String> it = mSharedLibraries.keySet().iterator();
+ while (it.hasNext()) {
+ String name = it.next();
+ pw.print(" ");
+ pw.print(name);
+ pw.print(" -> ");
+ pw.println(mSharedLibraries.get(name));
+ }
}
- if (mReceivers.dump(pw, printedTitle
- ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:",
- " ", packageName)) {
+
+ if ((dumpStar || dumpFeatures) && packageName == null) {
+ if (printedTitle) pw.println(" ");
printedTitle = true;
+ pw.println("Features:");
+ Iterator<String> it = mAvailableFeatures.keySet().iterator();
+ while (it.hasNext()) {
+ String name = it.next();
+ pw.print(" ");
+ pw.println(name);
+ }
}
- if (mServices.dump(pw, printedTitle
- ? "\nService Resolver Table:" : "Service Resolver Table:",
- " ", packageName)) {
- printedTitle = true;
+
+ if (dumpStar || dumpResolvers) {
+ if (mActivities.dump(pw, printedTitle
+ ? "\nActivity Resolver Table:" : "Activity Resolver Table:",
+ " ", packageName, showFilters)) {
+ printedTitle = true;
+ }
+ if (mReceivers.dump(pw, printedTitle
+ ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:",
+ " ", packageName, showFilters)) {
+ printedTitle = true;
+ }
+ if (mServices.dump(pw, printedTitle
+ ? "\nService Resolver Table:" : "Service Resolver Table:",
+ " ", packageName, showFilters)) {
+ printedTitle = true;
+ }
+ if (mSettings.mPreferredActivities.dump(pw, printedTitle
+ ? "\nPreferred Activities:" : "Preferred Activities:",
+ " ", packageName, showFilters)) {
+ printedTitle = true;
+ }
}
- if (mSettings.mPreferredActivities.dump(pw, printedTitle
- ? "\nPreferred Activities:" : "Preferred Activities:",
- " ", packageName)) {
- printedTitle = true;
- }
+
boolean printedSomething = false;
- {
+ if (dumpStar || dumpPermissions) {
for (BasePermission p : mSettings.mPermissions.values()) {
if (packageName != null && !packageName.equals(p.sourcePackage)) {
continue;
@@ -6947,9 +7004,27 @@
}
}
}
+
+ if (dumpStar || dumpProviders) {
+ printedSomething = false;
+ for (PackageParser.Provider p : mProviders.values()) {
+ if (packageName != null && !packageName.equals(p.info.packageName)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Registered ContentProviders:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
+ pw.println(p.toString());
+ }
+ }
+
printedSomething = false;
SharedUserSetting packageSharedUser = null;
- {
+ if (dumpStar || dumpPackages) {
for (PackageSetting ps : mSettings.mPackages.values()) {
if (packageName != null && !packageName.equals(ps.realName)
&& !packageName.equals(ps.name)) {
@@ -7052,52 +7127,54 @@
}
}
printedSomething = false;
- if (mSettings.mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e
- : mSettings.mRenamedPackages.entrySet()) {
- if (packageName != null && !packageName.equals(e.getKey())
- && !packageName.equals(e.getValue())) {
- continue;
+ if (dumpStar || dumpPackages) {
+ if (mSettings.mRenamedPackages.size() > 0) {
+ for (HashMap.Entry<String, String> e
+ : mSettings.mRenamedPackages.entrySet()) {
+ if (packageName != null && !packageName.equals(e.getKey())
+ && !packageName.equals(e.getValue())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ pw.print(" "); pw.print(e.getKey()); pw.print(" -> ");
+ pw.println(e.getValue());
}
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Renamed packages:");
- printedSomething = true;
- printedTitle = true;
+ }
+ printedSomething = false;
+ if (mSettings.mDisabledSysPackages.size() > 0) {
+ for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Hidden system packages:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+ if (ps.realName != null) {
+ pw.print(" compat name="); pw.println(ps.name);
+ }
+ pw.print(" userId="); pw.println(ps.userId);
+ pw.print(" sharedUser="); pw.println(ps.sharedUser);
+ pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(" resourcePath="); pw.println(ps.resourcePathString);
}
- pw.print(" "); pw.print(e.getKey()); pw.print(" -> ");
- pw.println(e.getValue());
}
}
printedSomething = false;
- if (mSettings.mDisabledSysPackages.size() > 0) {
- for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) {
- if (packageName != null && !packageName.equals(ps.realName)
- && !packageName.equals(ps.name)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Hidden system packages:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" Package [");
- pw.print(ps.realName != null ? ps.realName : ps.name);
- pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(ps)));
- pw.println("):");
- if (ps.realName != null) {
- pw.print(" compat name="); pw.println(ps.name);
- }
- pw.print(" userId="); pw.println(ps.userId);
- pw.print(" sharedUser="); pw.println(ps.sharedUser);
- pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- }
- }
- printedSomething = false;
- {
+ if (dumpStar || dumpSharedUsers) {
for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
if (packageName != null && su != packageSharedUser) {
continue;
@@ -7120,11 +7197,11 @@
}
}
- if (packageName == null) {
+ if ((dumpStar || dumpMessages) && packageName == null) {
if (printedTitle) pw.println(" ");
printedTitle = true;
pw.println("Settings parse messages:");
- pw.println(mSettings.mReadMessages.toString());
+ pw.print(mSettings.mReadMessages.toString());
pw.println(" ");
pw.println("Package warning messages:");
@@ -7135,29 +7212,12 @@
int avail = in.available();
byte[] data = new byte[avail];
in.read(data);
- pw.println(new String(data));
+ pw.print(new String(data));
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
-
- synchronized (mProviders) {
- boolean printedSomething = false;
- for (PackageParser.Provider p : mProviders.values()) {
- if (packageName != null && !packageName.equals(p.info.packageName)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Registered ContentProviders:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
- pw.println(p.toString());
- }
- }
}
static final class BasePermission {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 4532c1c..29a9a7e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -871,7 +871,7 @@
mWakeLockState = mLocks.gatherState();
// goes in the middle to reduce flicker
if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
- userActivity(SystemClock.uptimeMillis(), false);
+ userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false);
}
setPowerState(mWakeLockState | mUserState);
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7100cc5..0727a79 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -40,6 +40,7 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
import com.android.internal.policy.impl.PhoneWindowManager;
+import com.android.internal.view.BaseInputHandler;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
@@ -51,6 +52,8 @@
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -93,6 +96,7 @@
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.view.Display;
+import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -104,6 +108,8 @@
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
+import android.view.InputHandler;
+import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
@@ -159,6 +165,7 @@
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
+ static final boolean DEBUG_DRAG = true;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
@@ -486,6 +493,311 @@
boolean mTurnOnScreen;
/**
+ * Drag/drop state
+ */
+ class DragState {
+ IBinder mToken;
+ Surface mSurface;
+ boolean mLocalOnly;
+ ClipData mData;
+ ClipDescription mDataDescription;
+ float mThumbOffsetX, mThumbOffsetY;
+ InputChannel mServerChannel, mClientChannel;
+ WindowState mTargetWindow;
+ ArrayList<WindowState> mNotifiedWindows;
+ boolean mDragEnded;
+
+ private final Rect tmpRect = new Rect();
+
+ DragState(IBinder token, Surface surface, boolean localOnly) {
+ mToken = token;
+ mSurface = surface;
+ mLocalOnly = localOnly;
+ mNotifiedWindows = new ArrayList<WindowState>();
+ }
+
+ void reset() {
+ if (mSurface != null) {
+ mSurface.destroy();
+ }
+ mSurface = null;
+ mLocalOnly = false;
+ mToken = null;
+ mData = null;
+ mThumbOffsetX = mThumbOffsetY = 0;
+ mNotifiedWindows = null;
+ }
+
+ void register() {
+ if (DEBUG_DRAG) Slog.d(TAG, "registering drag input channel");
+ if (mClientChannel != null) {
+ Slog.e(TAG, "Duplicate register of drag input channel");
+ } else {
+ InputChannel[] channels = InputChannel.openInputChannelPair("drag");
+ mServerChannel = channels[0];
+ mClientChannel = channels[1];
+ mInputManager.registerInputChannel(mServerChannel);
+ InputQueue.registerInputChannel(mClientChannel, mDragInputHandler,
+ mH.getLooper().getQueue());
+ }
+ }
+
+ void unregister() {
+ if (DEBUG_DRAG) Slog.d(TAG, "unregistering drag input channel");
+ if (mClientChannel == null) {
+ Slog.e(TAG, "Unregister of nonexistent drag input channel");
+ } else {
+ mInputManager.unregisterInputChannel(mServerChannel);
+ InputQueue.unregisterInputChannel(mClientChannel);
+ mClientChannel.dispose();
+ mClientChannel = null;
+ mServerChannel = null;
+ }
+ }
+
+ /* call out to each visible window/session informing it about the drag
+ */
+ void broadcastDragStartedLw() {
+ // Cache a base-class instance of the clip metadata so that parceling
+ // works correctly in calling out to the apps.
+ mDataDescription = new ClipDescription(mData);
+ mNotifiedWindows.clear();
+
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "broadcasting DRAG_STARTED of " + mDataDescription);
+ }
+
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0,
+ mDataDescription, null);
+ for (WindowState ws : mWindows) {
+ sendDragStartedLw(ws, evt);
+ }
+ evt.recycle();
+ }
+
+ /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the
+ * designated window is potentially a drop recipient. There are race situations
+ * around DRAG_ENDED broadcast, so we make sure that once we've declared that
+ * the drag has ended, we never send out another DRAG_STARTED for this drag action.
+ */
+ private void sendDragStartedLw(WindowState newWin, final DragEvent event) {
+ if (!mDragEnded && newWin.isPotentialDragTarget()) {
+ try {
+ newWin.mClient.dispatchDragEvent(event);
+ // track each window that we've notified that the drag is starting
+ mNotifiedWindows.add(newWin);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to drag-start window " + newWin);
+ }
+ }
+ }
+
+ /* helper - construct and send a DRAG_STARTED event only if the window has not
+ * previously been notified, i.e. it became visible after the drag operation
+ * was begun. This is a rare case.
+ */
+ private void sendDragStartedIfNeededLw(WindowState newWin) {
+ // If we have sent the drag-started, we needn't do so again
+ for (WindowState ws : mNotifiedWindows) {
+ if (ws == newWin) {
+ return;
+ }
+ }
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "sending DRAG_STARTED to new window " + newWin);
+ }
+ DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0,
+ mDataDescription, null);
+ sendDragStartedLw(newWin, event);
+ event.recycle();
+ }
+
+ void broadcastDragEnded() {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "broadcasting DRAG_ENDED");
+ }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, 0, 0, null, null);
+ synchronized (mWindowMap) {
+ for (WindowState ws: mNotifiedWindows) {
+ try {
+ ws.mClient.dispatchDragEvent(evt);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to drag-end window " + ws);
+ }
+ }
+ mNotifiedWindows.clear();
+ mDragEnded = true;
+ }
+ evt.recycle();
+ }
+
+ void notifyMoveLw(float x, float y) {
+ WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ try {
+ // have we dragged over a new window?
+ if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "sending DRAG_EXITED to " + mTargetWindow);
+ }
+ // force DRAG_EXITED_EVENT if appropriate
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
+ 0, 0, null, null);
+ mTargetWindow.mClient.dispatchDragEvent(evt);
+ evt.recycle();
+ }
+ if (touchedWin != null) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "sending DRAG_LOCATION to " + touchedWin);
+ }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
+ x, y, null, null);
+ touchedWin.mClient.dispatchDragEvent(evt);
+ evt.recycle();
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "can't send drag notification to windows");
+ }
+ mTargetWindow = touchedWin;
+ }
+
+ // Tell the drop target about the data, and then broadcast the drag-ended notification
+ void notifyDropLw(float x, float y) {
+ WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ if (touchedWin != null) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "sending DROP to " + touchedWin);
+ }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP, x, y, null, mData);
+ try {
+ touchedWin.mClient.dispatchDragEvent(evt);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "can't send drop notification to win " + touchedWin);
+ }
+ evt.recycle();
+ }
+ }
+
+ // Find the visible, touch-deliverable window under the given point
+ private WindowState getTouchedWinAtPointLw(float xf, float yf) {
+ WindowState touchedWin = null;
+ final int x = (int) xf;
+ final int y = (int) yf;
+ final ArrayList<WindowState> windows = mWindows;
+ final int N = windows.size();
+ for (int i = N - 1; i >= 0; i--) {
+ WindowState child = windows.get(i);
+ final int flags = child.mAttrs.flags;
+ if (!child.isVisibleLw()) {
+ // not visible == don't tell about drags
+ continue;
+ }
+ if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ // not touchable == don't tell about drags
+ continue;
+ }
+ // account for the window's decor etc
+ tmpRect.set(child.mFrame);
+ if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
+ // The point is inside of the window if it is
+ // inside the frame, AND the content part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenContentInsets.left;
+ tmpRect.top += child.mGivenContentInsets.top;
+ tmpRect.right -= child.mGivenContentInsets.right;
+ tmpRect.bottom -= child.mGivenContentInsets.bottom;
+ } else if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
+ // The point is inside of the window if it is
+ // inside the frame, AND the visible part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenVisibleInsets.left;
+ tmpRect.top += child.mGivenVisibleInsets.top;
+ tmpRect.right -= child.mGivenVisibleInsets.right;
+ tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
+ }
+ final int touchFlags = flags &
+ (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ if (tmpRect.contains(x, y) || touchFlags == 0) {
+ // Found it
+ touchedWin = child;
+ break;
+ }
+ }
+
+ return touchedWin;
+ }
+ }
+
+ DragState mDragState = null;
+ private final InputHandler mDragInputHandler = new BaseInputHandler() {
+ @Override
+ public void handleMotion(MotionEvent event, Runnable finishedCallback) {
+ boolean endDrag = false;
+ final float newX = event.getRawX();
+ final float newY = event.getRawY();
+
+ try {
+ if (mDragState != null) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN: {
+ if (DEBUG_DRAG) {
+ Slog.w(TAG, "Unexpected ACTION_DOWN in drag layer");
+ }
+ } break;
+
+ case MotionEvent.ACTION_MOVE: {
+ synchronized (mWindowMap) {
+ // move the surface to the latest touch point
+ mDragState.mSurface.openTransaction();
+ mDragState.mSurface.setPosition((int)(newX - mDragState.mThumbOffsetX),
+ (int)(newY - mDragState.mThumbOffsetY));
+ mDragState.mSurface.closeTransaction();
+
+ // tell the involved window(s) where we are
+ mDragState.notifyMoveLw(newX, newY);
+ }
+ } break;
+
+ case MotionEvent.ACTION_UP: {
+ if (DEBUG_DRAG) Slog.d(TAG, "Got UP on move channel; dropping at "
+ + newX + "," + newY);
+ synchronized (mWindowMap) {
+ mDragState.notifyDropLw(newX, newY);
+ }
+ endDrag = true;
+ } break;
+
+ case MotionEvent.ACTION_CANCEL: {
+ if (DEBUG_DRAG) Slog.d(TAG, "Drag cancelled!");
+ endDrag = true;
+ } break;
+ }
+
+ if (endDrag) {
+ if (DEBUG_DRAG) Slog.d(TAG, "Drag ended; tearing down state");
+ // tell all the windows that the drag has ended
+ mDragState.broadcastDragEnded();
+
+ // stop intercepting input
+ mDragState.unregister();
+ mInputMonitor.updateInputWindowsLw();
+
+ // free our resources and drop all the object references
+ mDragState.reset();
+ mDragState = null;
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception caught by drag handleMotion", e);
+ } finally {
+ finishedCallback.run();
+ }
+ }
+ };
+
+ /**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
*/
@@ -5046,7 +5358,61 @@
mPolicy.adjustConfigurationLw(config);
return true;
}
-
+
+ // -------------------------------------------------------------
+ // Drag and drop
+ // -------------------------------------------------------------
+
+ IBinder prepareDragSurface(IWindow window, SurfaceSession session,
+ boolean localOnly, int width, int height, Surface outSurface) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
+ + " local=" + localOnly + " win=" + window
+ + " asbinder=" + window.asBinder());
+ }
+
+ final int callerPid = Binder.getCallingPid();
+ final long origId = Binder.clearCallingIdentity();
+ IBinder token = null;
+
+ try {
+ synchronized (mWindowMap) {
+ try {
+ // !!! TODO: fail if the given window does not currently have touch focus?
+
+ if (mDragState == null) {
+ Surface surface = new Surface(session, callerPid, "drag surface", 0,
+ width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
+ outSurface.copyFrom(surface);
+ token = new Binder();
+ mDragState = new DragState(token, surface, localOnly);
+ mDragState.mSurface = surface;
+ mDragState.mLocalOnly = localOnly;
+ token = mDragState.mToken = new Binder();
+
+ // 5 second timeout for this window to actually begin the drag
+ mH.removeMessages(H.DRAG_START_TIMEOUT, window);
+ Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, window.asBinder());
+ mH.sendMessageDelayed(msg, 5000);
+ } else {
+ Slog.w(TAG, "Drag already in progress");
+ }
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
+ if (mDragState != null) {
+ mDragState.reset();
+ mDragState = null;
+ }
+
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ return token;
+ }
+
// -------------------------------------------------------------
// Input Events and Focus Management
// -------------------------------------------------------------
@@ -5145,7 +5511,42 @@
return null;
}
-
+
+ private void addDragInputWindow(InputWindowList windowList) {
+ final InputWindow inputWindow = windowList.add();
+ inputWindow.inputChannel = mDragState.mServerChannel;
+ inputWindow.name = "drag";
+ inputWindow.layoutParamsFlags = 0;
+ inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+ inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ inputWindow.visible = true;
+ inputWindow.canReceiveKeys = false;
+ inputWindow.hasFocus = true;
+ inputWindow.hasWallpaper = false;
+ inputWindow.paused = false;
+ inputWindow.layer = mPolicy.windowTypeToLayerLw(inputWindow.layoutParamsType)
+ * TYPE_LAYER_MULTIPLIER
+ + TYPE_LAYER_OFFSET;
+ inputWindow.ownerPid = Process.myPid();
+ inputWindow.ownerUid = Process.myUid();
+
+ // The drag window covers the entire display
+ inputWindow.frameLeft = 0;
+ inputWindow.frameTop = 0;
+ inputWindow.frameRight = mDisplay.getWidth();
+ inputWindow.frameBottom = mDisplay.getHeight();
+
+ inputWindow.visibleFrameLeft = inputWindow.frameLeft;
+ inputWindow.visibleFrameTop = inputWindow.frameTop;
+ inputWindow.visibleFrameRight = inputWindow.frameRight;
+ inputWindow.visibleFrameBottom = inputWindow.frameBottom;
+
+ inputWindow.touchableAreaLeft = inputWindow.frameLeft;
+ inputWindow.touchableAreaTop = inputWindow.frameTop;
+ inputWindow.touchableAreaRight = inputWindow.frameRight;
+ inputWindow.touchableAreaBottom = inputWindow.frameBottom;
+ }
+
/* Updates the cached window information provided to the input dispatcher. */
public void updateInputWindowsLw() {
// Populate the input window list with information about all of the windows that
@@ -5154,6 +5555,16 @@
// out to be difficult because only the native code knows for sure which window
// currently has touch focus.
final ArrayList<WindowState> windows = mWindows;
+
+ // If there's a drag in flight, provide a pseudowindow to catch drag input
+ final boolean inDrag = (mDragState != null);
+ if (inDrag) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG, "Inserting drag window");
+ }
+ addDragInputWindow(mTempInputWindows);
+ }
+
final int N = windows.size();
for (int i = N - 1; i >= 0; i--) {
final WindowState child = windows.get(i);
@@ -5169,7 +5580,13 @@
final boolean isVisible = child.isVisibleLw();
final boolean hasWallpaper = (child == mWallpaperTarget)
&& (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
-
+
+ // If there's a drag in progress and 'child' is a potential drop target,
+ // make sure it's been told about the drag
+ if (inDrag && isVisible) {
+ mDragState.sendDragStartedIfNeededLw(child);
+ }
+
// Add a window to our list of input windows.
final InputWindow inputWindow = mTempInputWindows.add();
inputWindow.inputChannel = child.mInputChannel;
@@ -5741,6 +6158,87 @@
}
}
+ /* Drag/drop */
+ public IBinder prepareDrag(IWindow window, boolean localOnly,
+ int width, int height, Surface outSurface) {
+ return prepareDragSurface(window, mSurfaceSession, localOnly,
+ width, height, outSurface);
+ }
+
+ public boolean performDrag(IWindow window, IBinder dragToken,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "perform drag: win=" + window + " data=" + data);
+ }
+
+ synchronized (mWindowMap) {
+ if (mDragState == null) {
+ Slog.w(TAG, "No drag prepared");
+ throw new IllegalStateException("performDrag() without prepareDrag()");
+ }
+
+ if (dragToken != mDragState.mToken) {
+ Slog.w(TAG, "Performing mismatched drag");
+ throw new IllegalStateException("performDrag() does not match prepareDrag()");
+ }
+
+ WindowState callingWin = windowForClientLocked(null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG, "Bad requesting window " + window);
+ return false; // !!! TODO: throw here?
+ }
+
+ // !!! TODO: if input is not still focused on the initiating window, fail
+ // the drag initiation (e.g. an alarm window popped up just as the application
+ // called performDrag()
+
+ mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder());
+
+ // !!! TODO: call into the input monitor to sever the current touch event flow
+ // and redirect to the drag "window"; also extract the current touch (x, y)
+ // in screen coordinates
+
+ mDragState.register();
+ mInputMonitor.updateInputWindowsLw();
+ mInputManager.transferTouchFocus(callingWin.mInputChannel,
+ mDragState.mServerChannel);
+
+ mDragState.mData = data;
+ mDragState.broadcastDragStartedLw();
+
+ // remember the thumb offsets for later
+ mDragState.mThumbOffsetX = thumbCenterX;
+ mDragState.mThumbOffsetY = thumbCenterY;
+
+ // Make the surface visible at the proper location
+ final Surface surface = mDragState.mSurface;
+ surface.openTransaction();
+ try {
+ surface.setPosition((int)(touchX - thumbCenterX),
+ (int)(touchY - thumbCenterY));
+ surface.setAlpha(.5f);
+ surface.show();
+ } finally {
+ surface.closeTransaction();
+ }
+ }
+
+ return true; // success!
+ }
+
+ public void dragRecipientEntered(IWindow window) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "Drag into new candidate view @ " + window);
+ }
+ }
+
+ public void dragRecipientExited(IWindow window) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "Drag from old candidate view @ " + window);
+ }
+ }
+
public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
@@ -6882,6 +7380,15 @@
}
/**
+ * Can this window possibly be a drag/drop target? The test here is
+ * a combination of the above "visible now" with the check that the
+ * Input Manager uses when discarding windows from input consideration.
+ */
+ boolean isPotentialDragTarget() {
+ return isVisibleNow() && (mInputChannel != null) && !mRemoved;
+ }
+
+ /**
* Same as isVisible(), but we also count it as visible between the
* call to IWindowSession.add() and the first relayout().
*/
@@ -6968,34 +7475,6 @@
&& !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 {
- if ((mAttrs.flags & FLAG_FULLSCREEN) != 0) {
- return true;
- }
- 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.
@@ -7810,6 +8289,7 @@
public static final int APP_FREEZE_TIMEOUT = 17;
public static final int SEND_NEW_CONFIGURATION = 18;
public static final int REPORT_WINDOWS_CHANGE = 19;
+ public static final int DRAG_START_TIMEOUT = 20;
private Session mLastReportedHold;
@@ -8152,6 +8632,20 @@
break;
}
+ case DRAG_START_TIMEOUT: {
+ IBinder win = (IBinder)msg.obj;
+ if (DEBUG_DRAG) {
+ Slog.w(TAG, "Timeout starting drag by win " + win);
+ }
+ synchronized (mWindowMap) {
+ // !!! TODO: ANR the app that has failed to start the drag in time
+ if (mDragState != null) {
+ mDragState.reset();
+ mDragState = null;
+ }
+ }
+ }
+
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5c4b919..1eab7fc7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -113,9 +113,15 @@
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
@@ -6123,6 +6129,76 @@
return mSystemReady;
}
+ private static File getCalledPreBootReceiversFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "called_pre_boots.dat");
+ return fname;
+ }
+
+ private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
+ ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
+ File file = getCalledPreBootReceiversFile();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(file);
+ DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
+ int vers = dis.readInt();
+ String codename = dis.readUTF();
+ if (vers == android.os.Build.VERSION.SDK_INT
+ && codename.equals(android.os.Build.VERSION.CODENAME)) {
+ int num = dis.readInt();
+ while (num > 0) {
+ num--;
+ String pkg = dis.readUTF();
+ String cls = dis.readUTF();
+ lastDoneReceivers.add(new ComponentName(pkg, cls));
+ }
+ }
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure reading last done pre-boot receivers", e);
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return lastDoneReceivers;
+ }
+
+ private static void writeLastDonePreBootReceivers(ArrayList<ComponentName> list) {
+ File file = getCalledPreBootReceiversFile();
+ FileOutputStream fos = null;
+ DataOutputStream dos = null;
+ try {
+ Slog.i(TAG, "Writing new set of last done pre-boot receivers...");
+ fos = new FileOutputStream(file);
+ dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
+ dos.writeInt(android.os.Build.VERSION.SDK_INT);
+ dos.writeUTF(android.os.Build.VERSION.CODENAME);
+ dos.writeInt(list.size());
+ for (int i=0; i<list.size(); i++) {
+ dos.writeUTF(list.get(i).getPackageName());
+ dos.writeUTF(list.get(i).getClassName());
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure writing last done pre-boot receivers", e);
+ file.delete();
+ } finally {
+ if (dos != null) {
+ try {
+ dos.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
public void systemReady(final Runnable goingCallback) {
// In the simulator, startRunning will never have been called, which
// normally sets a few crucial variables. Do it here instead.
@@ -6157,9 +6233,24 @@
}
}
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+
+ ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+
+ final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
- intent.setComponent(new ComponentName(ai.packageName, ai.name));
+ ComponentName comp = new ComponentName(ai.packageName, ai.name);
+ if (lastDoneReceivers.contains(comp)) {
+ ris.remove(i);
+ i--;
+ }
+ }
+
+ for (int i=0; i<ris.size(); i++) {
+ ActivityInfo ai = ris.get(i).activityInfo;
+ ComponentName comp = new ComponentName(ai.packageName, ai.name);
+ doneReceivers.add(comp);
+ intent.setComponent(comp);
IIntentReceiver finisher = null;
if (i == ris.size()-1) {
finisher = new IIntentReceiver.Stub() {
@@ -6174,6 +6265,7 @@
synchronized (ActivityManagerService.this) {
mDidUpdate = true;
}
+ writeLastDonePreBootReceivers(doneReceivers);
systemReady(goingCallback);
}
});
@@ -6213,19 +6305,19 @@
}
}
- if (procsToKill != null) {
- synchronized(this) {
+ synchronized(this) {
+ if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
removeProcessLocked(proc, true);
}
-
- // Now that we have cleaned up any update processes, we
- // are ready to start launching real processes and know that
- // we won't trample on them any more.
- mProcessesReady = true;
}
+
+ // Now that we have cleaned up any update processes, we
+ // are ready to start launching real processes and know that
+ // we won't trample on them any more.
+ mProcessesReady = true;
}
Slog.i(TAG, "System now ready");
@@ -7741,7 +7833,7 @@
pw.println(" ");
pw.println("Receiver Resolver Table:");
- mReceiverResolver.dump(pw, null, " ", null);
+ mReceiverResolver.dump(pw, null, " ", null, false);
needSep = true;
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index bf4db80..6bd89cc 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -444,10 +444,11 @@
sb.append(shortComponentName);
sb.append(": ");
TimeUtils.formatDuration(thisTime, sb);
- sb.append(" (total ");
- TimeUtils.formatDuration(totalTime, sb);
- sb.append(totalTime);
- sb.append(")");
+ if (thisTime != totalTime) {
+ sb.append(" (total ");
+ TimeUtils.formatDuration(totalTime, sb);
+ sb.append(")");
+ }
Log.i(ActivityManagerService.TAG, sb.toString());
}
stack.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a4497d6..30395c0 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1881,7 +1881,7 @@
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified) {
- Slog.i(TAG, "Starting activity: " + intent);
+ Slog.i(TAG, "Starting: " + intent);
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 3f15d0a..8463b5a 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -57,6 +57,7 @@
public final class UsageStatsService extends IUsageStats.Stub {
public static final String SERVICE_NAME = "usagestats";
private static final boolean localLOGV = false;
+ private static final boolean REPORT_UNEXPECTED = false;
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
@@ -404,11 +405,11 @@
new Thread("UsageStatsService_DiskWriter") {
public void run() {
try {
- Slog.d(TAG, "Disk writer thread starting.");
+ if (localLOGV) Slog.d(TAG, "Disk writer thread starting.");
writeStatsToFile(true);
} finally {
mUnforcedDiskWriteRunning.set(false);
- Slog.d(TAG, "Disk writer thread ending.");
+ if (localLOGV) Slog.d(TAG, "Disk writer thread ending.");
}
}
}.start();
@@ -458,7 +459,7 @@
}
}
}
- Slog.d(TAG, "Dumped usage stats.");
+ if (localLOGV) Slog.d(TAG, "Dumped usage stats.");
}
private void writeStatsFLOCK(File file) throws IOException {
@@ -493,7 +494,7 @@
}
public void shutdown() {
- Slog.w(TAG, "Writing usage stats before shutdown...");
+ Slog.i(TAG, "Writing usage stats before shutdown...");
writeStatsToFile(true);
}
@@ -520,7 +521,7 @@
if (mLastResumedPkg != null) {
// We last resumed some other package... just pause it now
// to recover.
- Slog.i(TAG, "Unexpected resume of " + pkgName
+ if (REPORT_UNEXPECTED) Slog.i(TAG, "Unexpected resume of " + pkgName
+ " while already resumed in " + mLastResumedPkg);
PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
if (pus != null) {
@@ -559,7 +560,7 @@
return;
}
if (!mIsResumed) {
- Slog.i(TAG, "Something wrong here, didn't expect "
+ if (REPORT_UNEXPECTED) Slog.i(TAG, "Something wrong here, didn't expect "
+ pkgName + " to be paused");
return;
}
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e1e54fc..3d67e8d 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;
@@ -1289,6 +1283,7 @@
static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env,
jclass clazz, jobject fromChannelObj, jobject toChannelObj) {
if (checkInputManagerUnitialized(env)) {
+ LOGD("input manager uninitialized; bailing");
return false;
}
@@ -1298,6 +1293,7 @@
android_view_InputChannel_getInputChannel(env, toChannelObj);
if (fromChannel == NULL || toChannel == NULL) {
+ LOGD("bailing because from=%p to=%p", fromChannel, toChannel);
return false;
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b21a8d..fb76720 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -271,6 +271,17 @@
}
}
+void Layer::drawForSreenShot() const
+{
+ bool currentFixedSize = mFixedSize;
+ bool currentBlending = mNeedsBlending;
+ const_cast<Layer*>(this)->mFixedSize = false;
+ const_cast<Layer*>(this)->mFixedSize = true;
+ LayerBase::drawForSreenShot();
+ const_cast<Layer*>(this)->mFixedSize = currentFixedSize;
+ const_cast<Layer*>(this)->mNeedsBlending = currentBlending;
+}
+
void Layer::onDraw(const Region& clip) const
{
Texture tex(mBufferManager.getActiveTexture());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 188da6a..caa6d17 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -70,6 +70,7 @@
// LayerBase interface
virtual void setGeometry(hwc_layer_t* hwcl);
virtual void setPerFrameData(hwc_layer_t* hwcl);
+ virtual void drawForSreenShot() const;
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 3d049a7..14191cb 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -326,6 +326,12 @@
onDraw(clip);
}
+void LayerBase::drawForSreenShot() const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ onDraw( Region(hw.bounds()) );
+}
+
void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
GLclampf green, GLclampf blue,
GLclampf alpha) const
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c66dc34..bdee05b 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -121,6 +121,7 @@
* to perform the actual drawing.
*/
virtual void draw(const Region& clip) const;
+ virtual void drawForSreenShot() const;
/**
* onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index fdf9abc..c060895 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -132,6 +132,12 @@
LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
}
+void LayerBuffer::drawForSreenShot() const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ clearWithOpenGL( Region(hw.bounds()) );
+}
+
void LayerBuffer::onDraw(const Region& clip) const
{
sp<Source> source(getSource());
diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
index 1c0bf83..fece858 100644
--- a/services/surfaceflinger/LayerBuffer.h
+++ b/services/surfaceflinger/LayerBuffer.h
@@ -64,6 +64,7 @@
virtual sp<LayerBaseClient::Surface> createSurface() const;
virtual status_t ditch();
virtual void onDraw(const Region& clip) const;
+ virtual void drawForSreenShot() const;
virtual uint32_t doTransaction(uint32_t flags);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 17b98a6..e6bdfd1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1653,9 +1653,117 @@
// ---------------------------------------------------------------------------
+status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
+{
+ status_t result = PERMISSION_DENIED;
+
+ // only one display supported for now
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+
+ if ((sw > hw_w) || (sh > hw_h))
+ return BAD_VALUE;
+
+ sw = (!sw) ? hw_w : sw;
+ sh = (!sh) ? hw_h : sh;
+ const size_t size = sw * sh * 4;
+
+ // make sure to clear all GL error flags
+ while ( glGetError() != GL_NO_ERROR ) ;
+
+ // create a FBO
+ GLuint name, tname;
+ glGenRenderbuffersOES(1, &tname);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
+
+ GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+ if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
+
+ // invert everything, b/c glReadPixel() below will invert the FB
+ glViewport(0, 0, sw, sh);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+
+ // redraw the screen entirely...
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot();
+ }
+
+ // XXX: this is needed on tegra
+ glScissor(0, 0, sw, sh);
+
+ // check for errors and return screen capture
+ if (glGetError() != GL_NO_ERROR) {
+ // error while rendering
+ result = INVALID_OPERATION;
+ } else {
+ // allocate shared memory large enough to hold the
+ // screen capture
+ sp<MemoryHeapBase> base(
+ new MemoryHeapBase(size, 0, "screen-capture") );
+ void* const ptr = base->getBase();
+ if (ptr) {
+ // capture the screen with glReadPixels()
+ glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
+ if (glGetError() == GL_NO_ERROR) {
+ *heap = base;
+ *w = sw;
+ *h = sh;
+ *f = PIXEL_FORMAT_RGBA_8888;
+ result = NO_ERROR;
+ }
+ } else {
+ result = NO_MEMORY;
+ }
+ }
+
+ glEnable(GL_SCISSOR_TEST);
+ glViewport(0, 0, hw_w, hw_h);
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+
+ } else {
+ result = BAD_VALUE;
+ }
+
+ // release FBO resources
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDeleteRenderbuffersOES(1, &tname);
+ glDeleteFramebuffersOES(1, &name);
+ return result;
+}
+
+
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format)
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t sw, uint32_t sh)
{
// only one display supported for now
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -1671,12 +1779,15 @@
uint32_t* w;
uint32_t* h;
PixelFormat* f;
+ uint32_t sw;
+ uint32_t sh;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
- sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f)
+ sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
: flinger(flinger), dpy(dpy),
- heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED)
+ heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED)
{
}
status_t getResult() const {
@@ -1689,94 +1800,15 @@
if (flinger->mSecureFrameBuffer)
return true;
- // make sure to clear all GL error flags
- while ( glGetError() != GL_NO_ERROR ) ;
+ result = flinger->captureScreenImplLocked(dpy,
+ heap, w, h, f, sw, sh);
- // get screen geometry
- const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware());
- const uint32_t sw = hw.getWidth();
- const uint32_t sh = hw.getHeight();
- const Region screenBounds(hw.bounds());
- const size_t size = sw * sh * 4;
-
- // create a FBO
- GLuint name, tname;
- glGenRenderbuffersOES(1, &tname);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
-
- GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
- if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
-
- // invert everything, b/c glReadPixel() below will invert the FB
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrthof(0, sw, 0, sh, 0, 1);
- glMatrixMode(GL_MODELVIEW);
-
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
- const Vector< sp<LayerBase> >& layers(
- flinger->mVisibleLayersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- if (!strcmp(layer->getTypeId(), "LayerBuffer")) {
- // we cannot render LayerBuffer because it doens't
- // use OpenGL, and won't show-up in the FBO.
- continue;
- }
- layer->draw(screenBounds);
- }
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-
- // check for errors and return screen capture
- if (glGetError() != GL_NO_ERROR) {
- // error while rendering
- result = INVALID_OPERATION;
- } else {
- // allocate shared memory large enough to hold the
- // screen capture
- sp<MemoryHeapBase> base(
- new MemoryHeapBase(size, 0, "screen-capture") );
- void* const ptr = base->getBase();
- if (ptr) {
- // capture the screen with glReadPixels()
- glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
- if (glGetError() == GL_NO_ERROR) {
- *heap = base;
- *w = sw;
- *h = sh;
- *f = PIXEL_FORMAT_RGBA_8888;
- result = NO_ERROR;
- }
- } else {
- result = NO_MEMORY;
- }
- }
- } else {
- result = BAD_VALUE;
- }
-
- // release FBO resources
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteRenderbuffersOES(1, &tname);
- glDeleteFramebuffersOES(1, &name);
return true;
}
};
sp<MessageBase> msg = new MessageCaptureScreen(this,
- dpy, heap, width, height, format);
+ dpy, heap, width, height, format, sw, sh);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6e9ecbd..732e57e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -197,7 +197,9 @@
sp<IMemoryHeap>* heap,
uint32_t* width,
uint32_t* height,
- PixelFormat* format);
+ PixelFormat* format,
+ uint32_t reqWidth,
+ uint32_t reqHeight);
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
@@ -319,6 +321,11 @@
void commitTransaction();
+ status_t captureScreenImplLocked(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;
inline void incFreezeCount() {
diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp
index 9e893f4..6cf1504 100644
--- a/services/surfaceflinger/tests/screencap/screencap.cpp
+++ b/services/surfaceflinger/tests/screencap/screencap.cpp
@@ -42,7 +42,7 @@
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
- status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
+ status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0);
if (err != NO_ERROR) {
fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
exit(0);
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/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index d753973..52839be 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -35,7 +35,7 @@
*
*/
public abstract class DataConnectionTracker extends Handler {
- protected static final boolean DBG = true;
+ protected static final boolean DBG = false;
protected final String LOG_TAG = "DataConnectionTracker";
/**
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index ec6c0232..2957c7e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1187,6 +1187,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 5412768..74e8c1b 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 9e0c087..02fdf28 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -578,6 +578,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/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
old mode 100644
new mode 100755
index b71cf13..7d2013b
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -551,32 +551,53 @@
}
@Override
- protected void powerOffRadioSafely(){
- // clean data connection
+ protected void powerOffRadioSafely() {
DataConnectionTracker dcTracker = phone.mDataConnection;
Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
- dcTracker.sendMessage(msg);
- synchronized(this) {
- if (!mPendingRadioPowerOffAfterDataOff) {
- DataConnectionTracker.State currentState = dcTracker.getState();
- if (currentState != DataConnectionTracker.State.CONNECTED
- && currentState != DataConnectionTracker.State.DISCONNECTING
- && currentState != DataConnectionTracker.State.INITING) {
- if (DBG) log("Data disconnected, turn off radio right away.");
- hangupAndPowerOff();
- }
- else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
- if (DBG) {
- log("Wait up to 30 sec for data to disconnect, then turn off radio.");
+ synchronized (this) {
+ if (networkType == ServiceState.RADIO_TECHNOLOGY_1xRTT) {
+ /*
+ * In 1x CDMA , during radio power off modem will disconnect the
+ * data call and sends the power down registration message along
+ * with the data call release message to the network
+ */
+
+ msg.arg1 = 0; // tearDown is false since modem does it anyway for 1X
+ dcTracker.sendMessage(msg);
+
+ Log.w(LOG_TAG, "Turn off the radio right away");
+ hangupAndPowerOff();
+ } else {
+ if (!mPendingRadioPowerOffAfterDataOff) {
+ DataConnectionTracker.State currentState = dcTracker.getState();
+ if (currentState != DataConnectionTracker.State.CONNECTED
+ && currentState != DataConnectionTracker.State.DISCONNECTING
+ && currentState != DataConnectionTracker.State.INITING) {
+
+ msg.arg1 = 0; // tearDown is false as it is not needed.
+ dcTracker.sendMessage(msg);
+
+ if (DBG)
+ log("Data disconnected, turn off radio right away.");
+ hangupAndPowerOff();
+ } else {
+ // clean data connection
+ msg.arg1 = 1; // tearDown is true
+ dcTracker.sendMessage(msg);
+
+ if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
+ if (DBG) {
+ log("Wait upto 30s for data to disconnect, then turn off radio.");
+ }
+ mPendingRadioPowerOffAfterDataOff = true;
+ } else {
+ Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
+ hangupAndPowerOff();
+ }
}
- mPendingRadioPowerOffAfterDataOff = true;
- } else {
- Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
- hangupAndPowerOff();
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index d93852c..189d97d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -56,7 +56,7 @@
* 0, with the resulting code of 0x20.
*
* Note this mapping is also equivalent to that used by both the
- * IS5 and the IS-91 encodings. For the former this is defined
+ * IA5 and the IS-91 encodings. For the former this is defined
* using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B,
* Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits,
* and hence only maps entries up to the '_' character.
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 37dd971..38700cd 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -330,6 +330,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/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index af71a0f..df3c3ed 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -40,6 +40,15 @@
</activity>
<activity
+ android:name="LabelsActivity"
+ android:label="_Labels">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="ResizeActivity"
android:label="_Resize"
android:windowSoftInputMode="adjustResize">
@@ -164,6 +173,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="GradientsActivity"
+ android:label="_Gradients">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name="ShadersActivity"
diff --git a/tests/HwAccelerationTest/res/layout/labels.xml b/tests/HwAccelerationTest/res/layout/labels.xml
new file mode 100644
index 0000000..695a2cc
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/labels.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="200dip"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:text="This is a long text view for ellipsizing" />
+
+ <TextView
+ android:layout_width="200dip"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:gravity="center_horizontal"
+ android:text="This is a very long text view for ellipsizing" />
+
+ <TextView
+ android:layout_width="200dip"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:gravity="right"
+ android:text="This is a very long text view for ellipsizing" />
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
new file mode 100644
index 0000000..b70f3a9
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
@@ -0,0 +1,108 @@
+/*
+ * 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 com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GradientsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(new ShadersView(this));
+ }
+
+ static class ShadersView extends View {
+ private final Paint mPaint;
+ private final float mDrawWidth;
+ private final float mDrawHeight;
+ private final LinearGradient mGradient;
+ private final Matrix mMatrix;
+
+ ShadersView(Context c) {
+ super(c);
+
+ mDrawWidth = 200;
+ mDrawHeight = 200;
+
+ mGradient = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+ mMatrix = new Matrix();
+
+ mPaint = new Paint();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRGB(255, 255, 255);
+
+ // Gradients
+ canvas.save();
+ float top = 40.0f;
+ float right = 40.0f + mDrawWidth;
+ float left = 40.0f;
+ float bottom = 40.0f + mDrawHeight;
+
+ mPaint.setShader(mGradient);
+
+ mMatrix.setScale(1, mDrawWidth);
+ mMatrix.postRotate(90);
+ mMatrix.postTranslate(right, top);
+ mGradient.setLocalMatrix(mMatrix);
+ canvas.drawRect(right - mDrawWidth, top, right, top + mDrawHeight, mPaint);
+
+ top += 40.0f + mDrawHeight;
+ bottom += 40.0f + mDrawHeight;
+
+ mMatrix.setScale(1, mDrawHeight);
+ mMatrix.postTranslate(left, top);
+ mGradient.setLocalMatrix(mMatrix);
+ canvas.drawRect(left, top, right, top + mDrawHeight, mPaint);
+
+ left += 40.0f + mDrawWidth;
+ right += 40.0f + mDrawWidth;
+ top -= 40.0f + mDrawHeight;
+ bottom -= 40.0f + mDrawHeight;
+
+ mMatrix.setScale(1, mDrawHeight);
+ mMatrix.postRotate(180);
+ mMatrix.postTranslate(left, bottom);
+ mGradient.setLocalMatrix(mMatrix);
+ canvas.drawRect(left, bottom - mDrawHeight, right, bottom, mPaint);
+
+ top += 40.0f + mDrawHeight;
+ bottom += 40.0f + mDrawHeight;
+
+ mMatrix.setScale(1, mDrawWidth);
+ mMatrix.postRotate(-90);
+ mMatrix.postTranslate(left, top);
+ mGradient.setLocalMatrix(mMatrix);
+ canvas.drawRect(left, top, left + mDrawWidth, bottom, mPaint);
+
+ canvas.restore();
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java
new file mode 100644
index 0000000..bae0500
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class LabelsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.labels);
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
index 9c8e7ec..2db1071 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
@@ -77,8 +77,13 @@
m2.setScale(0.5f, 0.5f);
mScaledShader.setLocalMatrix(m2);
- mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
+ mHorGradient = new LinearGradient(0.0f, 0.0f, 1.0f, 0.0f,
Color.RED, Color.GREEN, Shader.TileMode.CLAMP);
+ Matrix m3 = new Matrix();
+ m3.setScale(mDrawHeight, 1.0f);
+ m3.postRotate(-90.0f);
+ m3.postTranslate(0.0f, mDrawHeight);
+ mHorGradient.setLocalMatrix(m3);
mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight,
Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
index f47b00f..763169a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
@@ -87,6 +87,7 @@
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
list.setCacheColorHint(0);
+ list.setVerticalFadingEdgeEnabled(true);
registerForContextMenu(list);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index f91f601..0553f5e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -30,6 +30,8 @@
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -46,6 +48,7 @@
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.BridgeInflater;
+import android.view.DragEvent;
import android.view.InputChannel;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -1073,6 +1076,33 @@
}
@SuppressWarnings("unused")
+ public IBinder prepareDrag(IWindow window, boolean localOnly,
+ int thumbnailWidth, int thumbnailHeight, Surface outSurface)
+ throws RemoteException {
+ // pass for now
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ public boolean performDrag(IWindow window, IBinder dragToken,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data)
+ throws RemoteException {
+ // pass for now
+ return false;
+ }
+
+ @SuppressWarnings("unused")
+ public void dragRecipientEntered(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
+ @SuppressWarnings("unused")
+ public void dragRecipientExited(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
+ @SuppressWarnings("unused")
public void setWallpaperPosition(IBinder window, float x, float y,
float xStep, float yStep) {
// pass for now.
@@ -1170,6 +1200,11 @@
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void dispatchDragEvent(DragEvent event) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/obbtool/mkobb.sh b/tools/obbtool/mkobb.sh
index f4cae9a1..ba5256f 100755
--- a/tools/obbtool/mkobb.sh
+++ b/tools/obbtool/mkobb.sh
@@ -21,7 +21,7 @@
MOUNTDIR=/tmp
# Presets. Changing these will probably break your OBB on the device
-CRYPTO=blowfish
+CRYPTO=twofish
FS=vfat
MKFS=mkfs.vfat
LOSETUP=losetup
@@ -122,7 +122,12 @@
rmdir ${temp_mount}
fi
if [ "x${loop_dev}" != "x" ]; then \
- ${LOSETUPBIN} -d ${loop_dev}
+ if [ ${use_crypto} -eq 1 ]; then \
+ dmsetup remove -f ${loop_dev}
+ ${LOSETUPBIN} -d ${old_loop_dev}
+ else \
+ ${LOSETUPBIN} -d ${loop_dev}
+ fi
fi
if [ "x${tempfile}" != "x" -a -f "${tempfile}" ]; then \
rm -f ${tempfile}
@@ -156,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;;
@@ -202,7 +206,7 @@
tempfile=$(tempfile -d ${outdir}) || ( echo "ERROR: couldn't create temporary file in ${outdir}"; exit 1 )
-block_count=`du --apparent-size --block-size=512 ${directory} | awk '{ print $1; }'`
+block_count=`du -s --apparent-size --block-size=512 ${directory} | awk '{ print $1; }'`
if [ $? -ne 0 ]; then \
echo "ERROR: Couldn't read size of input directory ${directory}"
exit 1
@@ -216,12 +220,14 @@
loop_dev=$(${LOSETUPBIN} -f) || ( echo "ERROR: losetup wouldn't tell us the next unused device"; exit 1 )
+${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 )
+
if [ ${use_crypto} -eq 1 ]; then \
- keyfile=$(tempfile -d ${outdir}) || ( echo "ERROR: could not create temporary key file"; exit 1 )
- ${LOSETUPBIN} -p 5 -e ${CRYPTO} ${loop_dev} ${tempfile} 5< ${keyfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 )
- rm -f ${keyfile}
-else \
- ${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 )
+ hashed_key=`echo -n "${key}" | md5sum | awk '{ print $1 }'`
+ unique_dm_name=`basename ${tempfile}`
+ echo "0 `blockdev --getsize ${loop_dev}` crypt ${CRYPTO} ${hashed_key} 0 ${loop_dev} 0" | dmsetup create ${unique_dm_name}
+ old_loop_dev=${loop_dev}
+ loop_dev=/dev/mapper/${unique_dm_name}
fi
#
@@ -252,7 +258,12 @@
#
umount ${temp_mount}
rmdir ${temp_mount}
-${LOSETUPBIN} -d ${loop_dev}
+if [ ${use_crypto} -eq 1 ]; then \
+ dmsetup remove -f ${loop_dev}
+ ${LOSETUPBIN} -d ${old_loop_dev}
+else \
+ ${LOSETUPBIN} -d ${loop_dev}
+fi
mv ${tempfile} ${filename}
trap - ERR
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index aff1439..405dff8 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -66,6 +66,7 @@
*/
public final class SipService extends ISipService.Stub {
private static final String TAG = "SipService";
+ private static final boolean DEBUGV = false;
private static final boolean DEBUG = true;
private static final boolean DEBUG_TIMER = DEBUG && false;
private static final int EXPIRY_TIME = 3600;
@@ -597,7 +598,7 @@
if (notCurrentSession(session)) return;
session = session.duplicate();
- if (DEBUG) Log.d(TAG, "~~~ keepalive");
+ if (DEBUGV) Log.v(TAG, "~~~ keepalive");
mTimer.cancel(this);
session.sendKeepAlive();
if (session.isReRegisterRequired()) {
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index a953d38..5214518 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -776,11 +776,14 @@
char c;
while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
- // Start your engine!
- track.start();
+ // Start AudioRecord before AudioTrack. This prevents AudioTrack from being
+ // disabled due to buffer underrun while waiting for AudioRecord.
if (mode != MUTED) {
record.start();
+ int16_t one;
+ record.read(&one, sizeof(one));
}
+ track.start();
while (!exitPending()) {
int16_t output[sampleCount];
@@ -806,34 +809,30 @@
track.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot write to AudioTrack");
- break;
+ return true;
}
}
if (toRead > 0) {
AudioRecord::Buffer buffer;
- buffer.frameCount = record.frameCount();
+ buffer.frameCount = toRead;
status_t status = record.obtainBuffer(&buffer, 1);
if (status == NO_ERROR) {
- int count = ((int)buffer.frameCount < toRead) ?
- buffer.frameCount : toRead;
- memcpy(&input[sampleCount - toRead], buffer.i8, count * 2);
- toRead -= count;
- if (buffer.frameCount < record.frameCount()) {
- buffer.frameCount = count;
- }
+ int offset = sampleCount - toRead;
+ memcpy(&input[offset], buffer.i8, buffer.size);
+ toRead -= buffer.frameCount;
record.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot read from AudioRecord");
- break;
+ return true;
}
}
}
if (chances <= 0) {
- LOGE("device loop timeout");
- break;
+ LOGW("device loop timeout");
+ while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
}
if (mode != MUTED) {