Merge commit 'goog/master' into merge_master
Conflicts:
opengl/libagl/Android.mk
opengl/libs/Android.mk
opengl/libs/egl_impl.h
diff --git a/api/1.xml b/api/1.xml
index b196ac7..02e8eac 100644
--- a/api/1.xml
+++ b/api/1.xml
@@ -88531,7 +88531,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="predicates" type="com.android.internal.util.Predicate...">
+<parameter name="predicates" type="com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...">
</parameter>
</method>
<method name="build"
@@ -169208,7 +169208,7 @@
>
<parameter name="loader" type="java.lang.ClassLoader">
</parameter>
-<parameter name="interfaces" type="java.lang.Class...">
+<parameter name="interfaces" type="java.lang.Class<?>...">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
diff --git a/api/2.xml b/api/2.xml
index b9736fe..65e7cec 100644
--- a/api/2.xml
+++ b/api/2.xml
@@ -88575,7 +88575,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="predicates" type="com.android.internal.util.Predicate...">
+<parameter name="predicates" type="com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...">
</parameter>
</method>
<method name="build"
@@ -169353,7 +169353,7 @@
>
<parameter name="loader" type="java.lang.ClassLoader">
</parameter>
-<parameter name="interfaces" type="java.lang.Class...">
+<parameter name="interfaces" type="java.lang.Class<?>...">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
diff --git a/api/4.xml b/api/4.xml
index ab93a47c..893301e 100644
--- a/api/4.xml
+++ b/api/4.xml
@@ -31801,97 +31801,6 @@
>
</field>
</class>
-<interface name="IPackageInstallObserver"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="packageInstalled"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="returnCode" type="int">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
-<class name="IPackageInstallObserver.Stub"
- extends="android.os.Binder"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.content.pm.IPackageInstallObserver">
-</implements>
-<constructor name="IPackageInstallObserver.Stub"
- type="android.content.pm.IPackageInstallObserver.Stub"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="asBinder"
- return="android.os.IBinder"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="asInterface"
- return="android.content.pm.IPackageInstallObserver"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="obj" type="android.os.IBinder">
-</parameter>
-</method>
-<method name="onTransact"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="code" type="int">
-</parameter>
-<parameter name="data" type="android.os.Parcel">
-</parameter>
-<parameter name="reply" type="android.os.Parcel">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</class>
<class name="InstrumentationInfo"
extends="android.content.pm.PackageItemInfo"
abstract="false"
@@ -33041,36 +32950,6 @@
<parameter name="appInfo" type="android.content.pm.ApplicationInfo">
</parameter>
</method>
-<method name="installPackage"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-<parameter name="observer" type="android.content.pm.IPackageInstallObserver">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="installPackage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-</method>
<method name="isSafeMode"
return="boolean"
abstract="true"
@@ -33344,17 +33223,6 @@
visibility="public"
>
</field>
-<field name="FORWARD_LOCK_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="GET_ACTIVITIES"
type="int"
transient="false"
@@ -33531,270 +33399,6 @@
visibility="public"
>
</field>
-<field name="INSTALL_FAILED_ALREADY_EXISTS"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_CONFLICTING_PROVIDER"
- type="int"
- transient="false"
- volatile="false"
- value="-13"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_DEXOPT"
- type="int"
- transient="false"
- volatile="false"
- value="-11"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_DUPLICATE_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="-5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INSUFFICIENT_STORAGE"
- type="int"
- transient="false"
- volatile="false"
- value="-4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INVALID_APK"
- type="int"
- transient="false"
- volatile="false"
- value="-2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INVALID_URI"
- type="int"
- transient="false"
- volatile="false"
- value="-3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_MISSING_SHARED_LIBRARY"
- type="int"
- transient="false"
- volatile="false"
- value="-9"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_NO_SHARED_USER"
- type="int"
- transient="false"
- volatile="false"
- value="-6"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_OLDER_SDK"
- type="int"
- transient="false"
- volatile="false"
- value="-12"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_REPLACE_COULDNT_DELETE"
- type="int"
- transient="false"
- volatile="false"
- value="-10"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"
- type="int"
- transient="false"
- volatile="false"
- value="-8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_UPDATE_INCOMPATIBLE"
- type="int"
- transient="false"
- volatile="false"
- value="-7"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_MANIFEST"
- type="int"
- transient="false"
- volatile="false"
- value="-101"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"
- type="int"
- transient="false"
- volatile="false"
- value="-106"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"
- type="int"
- transient="false"
- volatile="false"
- value="-107"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"
- type="int"
- transient="false"
- volatile="false"
- value="-105"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"
- type="int"
- transient="false"
- volatile="false"
- value="-104"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_MANIFEST_EMPTY"
- type="int"
- transient="false"
- volatile="false"
- value="-109"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"
- type="int"
- transient="false"
- volatile="false"
- value="-108"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_NOT_APK"
- type="int"
- transient="false"
- volatile="false"
- value="-100"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_NO_CERTIFICATES"
- type="int"
- transient="false"
- volatile="false"
- value="-103"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"
- type="int"
- transient="false"
- volatile="false"
- value="-102"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_SUCCEEDED"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="MATCH_DEFAULT_ONLY"
type="int"
transient="false"
@@ -33850,17 +33454,6 @@
visibility="public"
>
</field>
-<field name="REPLACE_EXISTING_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SIGNATURE_FIRST_NOT_SIGNED"
type="int"
transient="false"
@@ -101178,23 +100771,6 @@
<parameter name="appInfo" type="android.content.pm.ApplicationInfo">
</parameter>
</method>
-<method name="installPackage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-<parameter name="observer" type="android.content.pm.IPackageInstallObserver">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="isSafeMode"
return="boolean"
abstract="false"
diff --git a/api/current.xml b/api/current.xml
index 5325bf6..de3dbe8 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1013,6 +1013,17 @@
visibility="public"
>
</field>
+<field name="SHUTDOWN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.SHUTDOWN""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SIGNAL_PERSISTENT_PROCESSES"
type="java.lang.String"
transient="false"
@@ -1597,7 +1608,7 @@
type="int"
transient="false"
volatile="false"
- value="16843376"
+ value="16843378"
static="true"
final="true"
deprecated="not deprecated"
@@ -2554,7 +2565,7 @@
type="int"
transient="false"
volatile="false"
- value="16843377"
+ value="16843379"
static="true"
final="true"
deprecated="not deprecated"
@@ -5124,6 +5135,17 @@
visibility="public"
>
</field>
+<field name="maxSdkVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843377"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="maxWidth"
type="int"
transient="false"
@@ -7203,6 +7225,17 @@
visibility="public"
>
</field>
+<field name="targetSdkVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843376"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="taskAffinity"
type="int"
transient="false"
@@ -7313,6 +7346,17 @@
visibility="public"
>
</field>
+<field name="testOnly"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843380"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="text"
type="int"
transient="false"
@@ -23815,26 +23859,28 @@
</field>
</class>
</package>
-<package name="android.backup"
+<package name="android.content"
>
-<class name="BackupDataOutput"
+<class name="AbstractCursorEntityIterator"
extends="java.lang.Object"
- abstract="false"
+ abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<constructor name="BackupDataOutput"
- type="android.backup.BackupDataOutput"
+<implements name="android.content.EntityIterator">
+</implements>
+<constructor name="AbstractCursorEntityIterator"
+ type="android.content.AbstractCursorEntityIterator"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="context" type="android.content.Context">
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
</parameter>
-<parameter name="fd" type="java.io.FileDescriptor">
+<parameter name="entityCursor" type="android.database.Cursor">
</parameter>
</constructor>
<method name="close"
@@ -23848,188 +23894,42 @@
visibility="public"
>
</method>
-<method name="flush"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="write"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="buffer" type="byte[]">
-</parameter>
-</method>
-<method name="write"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="oneByte" type="int">
-</parameter>
-</method>
-<method name="write"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="buffer" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-<parameter name="count" type="int">
-</parameter>
-</method>
-<method name="writeKey"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="key" type="java.lang.String">
-</parameter>
-</method>
-<method name="writeOperation"
- return="void"
- abstract="false"
- native="true"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="op" type="int">
-</parameter>
-</method>
-<field name="OP_DELETE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OP_UPDATE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="FileBackupHelper"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="FileBackupHelper"
- type="android.backup.FileBackupHelper"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="performBackup"
- return="void"
+<method name="hasNext"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
- static="true"
+ static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="oldSnapshot" type="android.os.ParcelFileDescriptor">
-</parameter>
-<parameter name="newSnapshot" type="android.os.ParcelFileDescriptor">
-</parameter>
-<parameter name="data" type="android.backup.BackupDataOutput">
-</parameter>
-<parameter name="files" type="java.lang.String[]">
+</method>
+<method name="newEntityFromCursorLocked"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
</parameter>
</method>
-</class>
-<class name="SharedPreferencesBackupHelper"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="SharedPreferencesBackupHelper"
- type="android.backup.SharedPreferencesBackupHelper"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="performBackup"
- return="void"
+<method name="next"
+ return="android.content.Entity"
abstract="false"
native="false"
synchronized="false"
- static="true"
+ static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="oldSnapshot" type="android.os.ParcelFileDescriptor">
-</parameter>
-<parameter name="newSnapshot" type="android.os.ParcelFileDescriptor">
-</parameter>
-<parameter name="data" type="android.backup.BackupDataOutput">
-</parameter>
-<parameter name="prefGroups" type="java.lang.String[]">
-</parameter>
</method>
</class>
-</package>
-<package name="android.content"
->
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -24634,6 +24534,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Comparable">
+</implements>
<implements name="android.os.Parcelable">
</implements>
<constructor name="ComponentName"
@@ -24682,6 +24584,19 @@
<parameter name="in" type="android.os.Parcel">
</parameter>
</constructor>
+<method name="compareTo"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="that" type="android.content.ComponentName">
+</parameter>
+</method>
<method name="describeContents"
return="int"
abstract="false"
@@ -24874,6 +24789,36 @@
<parameter name="values" type="android.content.ContentValues[]">
</parameter>
</method>
+<method name="bulkInsertEntities"
+ return="android.net.Uri[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+</method>
+<method name="bulkUpdateEntities"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+</method>
<method name="delete"
return="int"
abstract="true"
@@ -24952,6 +24897,21 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
<method name="isTemporary"
return="boolean"
abstract="false"
@@ -25070,6 +25030,25 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+</method>
<method name="setReadPermission"
return="void"
abstract="false"
@@ -25115,6 +25094,21 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
</class>
<class name="ContentProviderClient"
extends="java.lang.Object"
@@ -25141,6 +25135,40 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="bulkInsertEntities"
+ return="android.net.Uri[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="bulkUpdateEntities"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="delete"
return="int"
abstract="false"
@@ -25203,6 +25231,23 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="openAssetFile"
return="android.content.res.AssetFileDescriptor"
abstract="false"
@@ -25264,6 +25309,27 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="release"
return="boolean"
abstract="false"
@@ -25296,6 +25362,23 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
</class>
<class name="ContentQueryMap"
extends="java.util.Observable"
@@ -25440,6 +25523,40 @@
<parameter name="values" type="android.content.ContentValues[]">
</parameter>
</method>
+<method name="bulkInsertEntities"
+ return="android.net.Uri[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="bulkUpdateEntities"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entities" type="android.content.Entity[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="cancelSync"
return="void"
abstract="false"
@@ -25498,6 +25615,23 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="notifyChange"
return="void"
abstract="false"
@@ -25632,6 +25766,27 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntity"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="registerContentObserver"
return="void"
abstract="false"
@@ -25696,6 +25851,23 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="validateSyncExtrasBundle"
return="void"
abstract="false"
@@ -28847,6 +29019,183 @@
</parameter>
</method>
</interface>
+<class name="Entity"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Entity"
+ type="android.content.Entity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="EntityIterator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="close"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<interface name="IEntityIterator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="close"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IEntityIterator.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.IEntityIterator">
+</implements>
+<constructor name="IEntityIterator.Stub"
+ type="android.content.IEntityIterator.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.content.IEntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -30940,6 +31289,17 @@
visibility="public"
>
</field>
+<field name="ACTION_REMOTE_INTENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.action.REMOTE_INTENT""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_RUN"
type="java.lang.String"
transient="false"
@@ -31028,6 +31388,17 @@
visibility="public"
>
</field>
+<field name="ACTION_SHUTDOWN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.action.ACTION_SHUTDOWN""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_SYNC"
type="java.lang.String"
transient="false"
@@ -31467,6 +31838,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_REMOTE_INTENT_TOKEN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.extra.remote_intent_token""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_REPLACING"
type="java.lang.String"
transient="false"
@@ -34109,6 +34491,39 @@
visibility="public"
>
</field>
+<field name="FLAG_TARGETS_SDK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_TEST_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_UPDATED_SYSTEM_APP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="className"
type="java.lang.String"
transient="false"
@@ -34513,97 +34928,6 @@
>
</field>
</class>
-<interface name="IPackageInstallObserver"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.os.IInterface">
-</implements>
-<method name="packageInstalled"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-<parameter name="returnCode" type="int">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</interface>
-<class name="IPackageInstallObserver.Stub"
- extends="android.os.Binder"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.content.pm.IPackageInstallObserver">
-</implements>
-<constructor name="IPackageInstallObserver.Stub"
- type="android.content.pm.IPackageInstallObserver.Stub"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="asBinder"
- return="android.os.IBinder"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="asInterface"
- return="android.content.pm.IPackageInstallObserver"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="obj" type="android.os.IBinder">
-</parameter>
-</method>
-<method name="onTransact"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="code" type="int">
-</parameter>
-<parameter name="data" type="android.os.Parcel">
-</parameter>
-<parameter name="reply" type="android.os.Parcel">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-</class>
<class name="InstrumentationInfo"
extends="android.content.pm.PackageItemInfo"
abstract="false"
@@ -35460,6 +35784,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="true"
@@ -35753,36 +36090,6 @@
<parameter name="appInfo" type="android.content.pm.ApplicationInfo">
</parameter>
</method>
-<method name="installPackage"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-<parameter name="observer" type="android.content.pm.IPackageInstallObserver">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
-<method name="installPackage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-</method>
<method name="isSafeMode"
return="boolean"
abstract="true"
@@ -36056,17 +36363,6 @@
visibility="public"
>
</field>
-<field name="FORWARD_LOCK_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="GET_ACTIVITIES"
type="int"
transient="false"
@@ -36254,270 +36550,6 @@
visibility="public"
>
</field>
-<field name="INSTALL_FAILED_ALREADY_EXISTS"
- type="int"
- transient="false"
- volatile="false"
- value="-1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_CONFLICTING_PROVIDER"
- type="int"
- transient="false"
- volatile="false"
- value="-13"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_DEXOPT"
- type="int"
- transient="false"
- volatile="false"
- value="-11"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_DUPLICATE_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="-5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INSUFFICIENT_STORAGE"
- type="int"
- transient="false"
- volatile="false"
- value="-4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INVALID_APK"
- type="int"
- transient="false"
- volatile="false"
- value="-2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_INVALID_URI"
- type="int"
- transient="false"
- volatile="false"
- value="-3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_MISSING_SHARED_LIBRARY"
- type="int"
- transient="false"
- volatile="false"
- value="-9"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_NO_SHARED_USER"
- type="int"
- transient="false"
- volatile="false"
- value="-6"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_OLDER_SDK"
- type="int"
- transient="false"
- volatile="false"
- value="-12"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_REPLACE_COULDNT_DELETE"
- type="int"
- transient="false"
- volatile="false"
- value="-10"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"
- type="int"
- transient="false"
- volatile="false"
- value="-8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_FAILED_UPDATE_INCOMPATIBLE"
- type="int"
- transient="false"
- volatile="false"
- value="-7"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_MANIFEST"
- type="int"
- transient="false"
- volatile="false"
- value="-101"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"
- type="int"
- transient="false"
- volatile="false"
- value="-106"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"
- type="int"
- transient="false"
- volatile="false"
- value="-107"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"
- type="int"
- transient="false"
- volatile="false"
- value="-105"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"
- type="int"
- transient="false"
- volatile="false"
- value="-104"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_MANIFEST_EMPTY"
- type="int"
- transient="false"
- volatile="false"
- value="-109"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"
- type="int"
- transient="false"
- volatile="false"
- value="-108"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_NOT_APK"
- type="int"
- transient="false"
- volatile="false"
- value="-100"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_NO_CERTIFICATES"
- type="int"
- transient="false"
- volatile="false"
- value="-103"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"
- type="int"
- transient="false"
- volatile="false"
- value="-102"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="INSTALL_SUCCEEDED"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="MATCH_DEFAULT_ONLY"
type="int"
transient="false"
@@ -36573,17 +36605,6 @@
visibility="public"
>
</field>
-<field name="REPLACE_EXISTING_PACKAGE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SIGNATURE_FIRST_NOT_SIGNED"
type="int"
transient="false"
@@ -55520,6 +55541,32 @@
<parameter name="path" type="java.lang.String">
</parameter>
</method>
+<method name="createFromFile"
+ return="android.graphics.Typeface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.io.File">
+</parameter>
+</method>
+<method name="createFromFile"
+ return="android.graphics.Typeface"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
<method name="defaultFromStyle"
return="android.graphics.Typeface"
abstract="false"
@@ -88345,6 +88392,16 @@
visibility="public"
>
</constructor>
+<field name="CODENAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="INCREMENTAL"
type="java.lang.String"
transient="false"
@@ -88371,6 +88428,66 @@
volatile="false"
static="true"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="SDK_INT"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Build.VERSION_CODES"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Build.VERSION_CODES"
+ type="android.os.Build.VERSION_CODES"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="BASE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BASE_1_1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CUPCAKE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -114196,6 +114313,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="false"
@@ -114472,23 +114602,6 @@
<parameter name="appInfo" type="android.content.pm.ApplicationInfo">
</parameter>
</method>
-<method name="installPackage"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="packageURI" type="android.net.Uri">
-</parameter>
-<parameter name="observer" type="android.content.pm.IPackageInstallObserver">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-</method>
<method name="isSafeMode"
return="boolean"
abstract="false"
@@ -141892,6 +142005,17 @@
<implements name="java.lang.annotation.Annotation">
</implements>
</class>
+<class name="ViewDebug.FlagToString"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.annotation.Annotation">
+</implements>
+</class>
<class name="ViewDebug.HierarchyTraceType"
extends="java.lang.Enum"
abstract="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 96ee502..f85ea9f8 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -915,24 +915,24 @@
void CameraService::Client::postAutoFocus(bool focused)
{
LOGV("postAutoFocus");
- mCameraClient->autoFocusCallback(focused);
+ mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0);
}
void CameraService::Client::postShutter()
{
- mCameraClient->shutterCallback();
+ mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
}
void CameraService::Client::postRaw(const sp<IMemory>& mem)
{
LOGD("postRaw");
- mCameraClient->rawCallback(mem);
+ mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
}
void CameraService::Client::postJpeg(const sp<IMemory>& mem)
{
LOGD("postJpeg");
- mCameraClient->jpegCallback(mem);
+ mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
}
void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
@@ -960,7 +960,7 @@
LOGE("failed to allocate space for frame callback");
return;
}
- mCameraClient->previewCallback(frame);
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
}
void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame)
@@ -970,7 +970,7 @@
LOGW("frame is a null pointer");
return;
}
- mCameraClient->recordingCallback(frame);
+ mCameraClient->dataCallback(CAMERA_MSG_VIDEO_FRAME, frame);
}
void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
@@ -1004,7 +1004,7 @@
copyFrameAndPostCopiedFrame(heap, offset, size);
} else {
LOGV("frame is directly sent out without copying");
- mCameraClient->previewCallback(mem);
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
}
// Is this is one-shot only?
@@ -1018,7 +1018,7 @@
void CameraService::Client::postError(status_t error)
{
- mCameraClient->errorCallback(error);
+ mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0);
}
status_t CameraService::dump(int fd, const Vector<String16>& args)
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 161bb46..8212b92 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -537,6 +537,12 @@
case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER:
s = "INSTALL_FAILED_CONFLICTING_PROVIDER";
break;
+ case PackageManager.INSTALL_FAILED_NEWER_SDK:
+ s = "INSTALL_FAILED_NEWER_SDK";
+ break;
+ case PackageManager.INSTALL_FAILED_TEST_ONLY:
+ s = "INSTALL_FAILED_TEST_ONLY";
+ break;
case PackageManager.INSTALL_PARSE_FAILED_NOT_APK:
s = "INSTALL_PARSE_FAILED_NOT_APK";
break;
@@ -576,13 +582,23 @@
private void runInstall() {
int installFlags = 0;
+ String installerPackageName = null;
String opt;
while ((opt=nextOption()) != null) {
if (opt.equals("-l")) {
- installFlags |= PackageManager.FORWARD_LOCK_PACKAGE;
+ installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
} else if (opt.equals("-r")) {
- installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
+ installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ } else if (opt.equals("-i")) {
+ installerPackageName = nextOptionData();
+ if (installerPackageName == null) {
+ System.err.println("Error: no value specified for -i");
+ showUsage();
+ return;
+ }
+ } else if (opt.equals("-t")) {
+ installFlags |= PackageManager.INSTALL_ALLOW_TEST;
} else {
System.err.println("Error: Unknown option: " + opt);
showUsage();
@@ -600,7 +616,8 @@
PackageInstallObserver obs = new PackageInstallObserver();
try {
- mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags);
+ mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
+ installerPackageName);
synchronized (obs) {
while (!obs.finished) {
@@ -809,37 +826,39 @@
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
System.err.println(" pm path PACKAGE");
- System.err.println(" pm install [-l] [-r] PATH");
+ System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
System.err.println("");
- System.err.println("The list packages command prints all packages. Use");
- System.err.println("the -f option to see their associated file.");
+ System.err.println("The list packages command prints all packages. Options:");
+ System.err.println(" -f: see their associated file.");
System.err.println("");
System.err.println("The list permission-groups command prints all known");
System.err.println("permission groups.");
System.err.println("");
System.err.println("The list permissions command prints all known");
- System.err.println("permissions, optionally only those in GROUP. Use");
- System.err.println("the -g option to organize by group. Use");
- System.err.println("the -f option to print all information. Use");
- System.err.println("the -s option for a short summary. Use");
- System.err.println("the -d option to only list dangerous permissions. Use");
- System.err.println("the -u option to list only the permissions users will see.");
+ System.err.println("permissions, optionally only those in GROUP. Options:");
+ System.err.println(" -g: organize by group.");
+ System.err.println(" -f: print all information.");
+ System.err.println(" -s: short summary.");
+ System.err.println(" -d: only list dangerous permissions.");
+ System.err.println(" -u: list only the permissions users will see.");
System.err.println("");
System.err.println("The list instrumentation command prints all instrumentations,");
- System.err.println("or only those that target a specified package. Use the -f option");
- System.err.println("to see their associated file.");
+ System.err.println("or only those that target a specified package. Options:");
+ System.err.println(" -f: see their associated file.");
System.err.println("");
System.err.println("The path command prints the path to the .apk of a package.");
System.err.println("");
- System.err.println("The install command installs a package to the system. Use");
- System.err.println("the -l option to install the package with FORWARD_LOCK. Use");
- System.err.println("the -r option to reinstall an exisiting app, keeping its data.");
+ System.err.println("The install command installs a package to the system. Options:");
+ System.err.println(" -l: install the package with FORWARD_LOCK.");
+ System.err.println(" -r: reinstall an exisiting app, keeping its data.");
+ System.err.println(" -t: allow test .apks to be installed.");
+ System.err.println(" -i: specify the installer package name.");
System.err.println("");
- System.err.println("The uninstall command removes a package from the system. Use");
- System.err.println("the -k option to keep the data and cache directories around");
+ System.err.println("The uninstall command removes a package from the system. Options:");
+ System.err.println(" -k: keep the data and cache directories around.");
System.err.println("after the package removal.");
System.err.println("");
System.err.println("The enable and disable commands change the enabled state of");
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 53e6f34..541f413 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -990,6 +990,14 @@
return true;
}
+ case SHUTDOWN_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean res = shutdown(data.readInt());
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
case PEEK_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Intent service = Intent.CREATOR.createFromParcel(data);
@@ -2160,5 +2168,19 @@
return res;
}
+ public boolean shutdown(int timeout) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(timeout);
+ mRemote.transact(SHUTDOWN_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2fc476e..1e15d14 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -191,16 +191,11 @@
usePreloaded = false;
DisplayMetrics newMetrics = new DisplayMetrics();
newMetrics.setTo(metrics);
- float invertedScale = 1.0f / applicationScale;
- newMetrics.density *= invertedScale;
- newMetrics.xdpi *= invertedScale;
- newMetrics.ydpi *= invertedScale;
- newMetrics.widthPixels *= invertedScale;
- newMetrics.heightPixels *= invertedScale;
+ float newDensity = metrics.density / applicationScale;
+ newMetrics.updateDensity(newDensity);
metrics = newMetrics;
}
- //Log.i(TAG, "Resource:" + appDir + ", density " + newMetrics.density + ", orig density:" +
- // metrics.density);
+ //Log.i(TAG, "Resource:" + appDir + ", display metrics=" + metrics);
r = new Resources(assets, metrics, getConfiguration(), usePreloaded);
//Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
// XXX need to remove entries when weak references go away
@@ -3502,8 +3497,10 @@
Resources r = v.get();
if (r != null) {
// keep the original density based on application cale.
- appDm.density = r.getDisplayMetrics().density;
+ appDm.updateDensity(r.getDisplayMetrics().density);
r.updateConfiguration(config, appDm);
+ // reset
+ appDm.setTo(dm);
//Log.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 72d9e3d..d235832 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -2326,15 +2326,26 @@
}
@Override
- public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags) {
+ public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
+ String installerPackageName) {
try {
- mPM.installPackage(packageURI, observer, flags);
+ mPM.installPackage(packageURI, observer, flags, installerPackageName);
} catch (RemoteException e) {
// Should never happen!
}
}
@Override
+ public String getInstallerPackageName(String packageName) {
+ try {
+ return mPM.getInstallerPackageName(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
+ @Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
try {
mPM.deletePackage(packageName, observer, flags);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2ac6160..56b29c1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -16,7 +16,6 @@
package android.app;
-import android.app.ActivityManager.MemoryInfo;
import android.content.ComponentName;
import android.content.ContentProviderNative;
import android.content.IContentProvider;
@@ -34,7 +33,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
import android.os.Bundle;
import java.util.List;
@@ -225,6 +223,8 @@
public boolean profileControl(String process, boolean start,
String path) throws RemoteException;
+ public boolean shutdown(int timeout) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -370,4 +370,5 @@
int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83;
int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85;
+ int SHUTDOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+86;
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 8fc2447..343380c 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -171,7 +171,7 @@
// having windows anchored by their parent but not clipped by them.
ViewGroup.LayoutParams.FILL_PARENT);
WindowManager.LayoutParams lp = theWindow.getAttributes();
- lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
+ lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
theWindow.setAttributes(lp);
// get the view elements for local access
@@ -309,11 +309,23 @@
+ appSearchData + ", " + globalSearch + ")");
}
+ // Try to get the searchable info for the provided component (or for global search,
+ // if globalSearch == true).
mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch);
- if (mSearchable == null) {
- // unfortunately, we can't log here. it would be logspam every time the user
- // clicks the "search" key on a non-search app
- return false;
+
+ // If we got back nothing, and it wasn't a request for global search, then try again
+ // for global search, as we'll try to launch that in lieu of any component-specific search.
+ if (!globalSearch && mSearchable == null) {
+ globalSearch = true;
+ mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch);
+
+ // If we still get back null (i.e., there's not even a searchable info available
+ // for global search), then really give up.
+ if (mSearchable == null) {
+ // Unfortunately, we can't log here. it would be logspam every time the user
+ // clicks the "search" key on a non-search app.
+ return false;
+ }
}
mLaunchComponent = componentName;
@@ -325,6 +337,14 @@
// show the dialog. this will call onStart().
if (!isShowing()) {
+ // First make sure the keyboard is showing (if needed), so that we get the right height
+ // for the dropdown to respect the IME.
+ if (getContext().getResources().getConfiguration().hardKeyboardHidden ==
+ Configuration.HARDKEYBOARDHIDDEN_YES) {
+ InputMethodManager inputManager = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputManager.showSoftInputUnchecked(0, null);
+ }
show();
}
@@ -531,9 +551,13 @@
if (mGlobalSearchMode) {
mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in
mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
+ mSearchAutoComplete.setDropDownBackgroundResource(
+ com.android.internal.R.drawable.search_dropdown_background);
} else {
mSearchAutoComplete.setDropDownAlwaysVisible(false);
mSearchAutoComplete.setDropDownDismissedOnCompletion(true);
+ mSearchAutoComplete.setDropDownBackgroundResource(
+ com.android.internal.R.drawable.search_dropdown_background_apps);
}
// attach the suggestions adapter, if suggestions are available
@@ -1329,7 +1353,7 @@
private SearchDialog mSearchDialog;
public SearchAutoComplete(Context context) {
- super(null);
+ super(context);
mThreshold = getThreshold();
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 90de40d..3bf37c3 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1184,23 +1184,32 @@
public final static String SUGGEST_URI_PATH_QUERY = "search_suggest_query";
/**
+ * MIME type for suggestions data. You'll use this in your suggestions content provider
+ * in the getType() function.
+ */
+ public final static String SUGGEST_MIME_TYPE =
+ "vnd.android.cursor.dir/vnd.android.search.suggest";
+
+ /**
* Uri path for shortcut validation. This is the path that the search manager will use when
* querying your content provider to refresh a shortcutted suggestion result and to check if it
* is still valid. When asked, a source may return an up to date result, or no result. No
* result indicates the shortcut refers to a no longer valid sugggestion.
*
* @see #SUGGEST_COLUMN_SHORTCUT_ID
- * @hide
+ *
+ * @hide pending API council approval
*/
public final static String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut";
/**
- * MIME type for suggestions data. You'll use this in your suggestions content provider
+ * MIME type for shortcut validation. You'll use this in your suggestions content provider
* in the getType() function.
+ *
+ * @hide pending API council approval
*/
- public final static String SUGGEST_MIME_TYPE =
- "vnd.android.cursor.dir/vnd.android.search.suggest";
-
+ public final static String SHORTCUT_MIME_TYPE =
+ "vnd.android.cursor.item/vnd.android.search.suggest";
/**
* Column name for suggestions cursor. <i>Unused - can be null or column can be omitted.</i>
*/
diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java
index 7871fb6..26712a1 100755
--- a/core/java/android/appwidget/AppWidgetProvider.java
+++ b/core/java/android/appwidget/AppWidgetProvider.java
@@ -22,7 +22,7 @@
import android.os.Bundle;
/**
- * A conveience class to aid in implementing an AppWidget provider.
+ * A convenience class to aid in implementing an AppWidget provider.
* Everything you can do with AppWidgetProvider, you can do with a regular {@link BroadcastReceiver}.
* AppWidgetProvider merely parses the relevant fields out of the Intent that is received in
* {@link #onReceive(Context,Intent) onReceive(Context,Intent)}, and calls hook methods
diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java
index 6c47f7e..555494e 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -20,6 +20,7 @@
import java.io.FileDescriptor;
+/** @hide */
public class BackupDataOutput {
/* package */ FileDescriptor fd;
diff --git a/core/java/android/backup/BackupService.java b/core/java/android/backup/BackupService.java
index 6ac703a..50a5921 100644
--- a/core/java/android/backup/BackupService.java
+++ b/core/java/android/backup/BackupService.java
@@ -75,9 +75,8 @@
* file. The application should record the final backup state
* here after writing the requested data to dataFd.
*/
- public abstract void onBackup(ParcelFileDescriptor oldState,
- ParcelFileDescriptor data,
- ParcelFileDescriptor newState);
+ public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState);
/**
* The application is being restored from backup, and should replace any
@@ -92,7 +91,7 @@
* file. The application should record the final backup state
* here after restoring its data from dataFd.
*/
- public abstract void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState);
+ public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data, ParcelFileDescriptor newState);
// ----- Core implementation -----
@@ -117,7 +116,15 @@
ParcelFileDescriptor newState) throws RemoteException {
// !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v("BackupServiceBinder", "doBackup() invoked");
- BackupService.this.onBackup(oldState, data, newState);
+ BackupDataOutput output = new BackupDataOutput(BackupService.this,
+ data.getFileDescriptor());
+ try {
+ BackupService.this.onBackup(oldState, output, newState);
+ } catch (RuntimeException ex) {
+ Log.d("BackupService", "onBackup ("
+ + BackupService.this.getClass().getName() + ") threw", ex);
+ throw ex;
+ }
}
public void doRestore(ParcelFileDescriptor data,
diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java
index 3b2122c..05159dc 100644
--- a/core/java/android/backup/FileBackupHelper.java
+++ b/core/java/android/backup/FileBackupHelper.java
@@ -18,20 +18,24 @@
import android.content.Context;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
import java.io.FileDescriptor;
+/** @hide */
public class FileBackupHelper {
+ private static final String TAG = "FileBackupHelper";
+
/**
- * Based on oldSnapshot, determine which of the files from the application's data directory
- * need to be backed up, write them to the data stream, and fill in newSnapshot with the
+ * Based on oldState, determine which of the files from the application's data directory
+ * need to be backed up, write them to the data stream, and fill in newState with the
* state as it exists now.
*/
public static void performBackup(Context context,
- ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
- BackupDataOutput data, String[] files) {
+ ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState, String[] files) {
String basePath = context.getFilesDir().getAbsolutePath();
- performBackup_checked(basePath, oldSnapshot, newSnapshot, data, files);
+ performBackup_checked(basePath, oldState, data, newState, files);
}
/**
@@ -39,30 +43,31 @@
* since it's easier to do that from java.
*/
static void performBackup_checked(String basePath,
- ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
- BackupDataOutput data, String[] files) {
- if (newSnapshot == null) {
- throw new NullPointerException("newSnapshot==null");
+ ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState, String[] files) {
+ if (files.length == 0) {
+ return;
}
- if (data == null) {
- throw new NullPointerException("data==null");
+ if (basePath == null) {
+ throw new NullPointerException();
}
+ // oldStateFd can be null
+ FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null;
if (data.fd == null) {
- throw new NullPointerException("data.fd==null");
+ throw new NullPointerException();
}
- if (files == null) {
- throw new NullPointerException("files==null");
+ FileDescriptor newStateFd = newState.getFileDescriptor();
+ if (newStateFd == null) {
+ throw new NullPointerException();
}
- int err = performBackup_native(basePath, oldSnapshot.getFileDescriptor(),
- newSnapshot.getFileDescriptor(), data.fd, files);
+ int err = performBackup_native(basePath, oldStateFd, data.fd, newStateFd, files);
if (err != 0) {
throw new RuntimeException("Backup failed"); // TODO: more here
}
}
- native private static int performBackup_native(String basePath,
- FileDescriptor oldSnapshot, FileDescriptor newSnapshot,
- FileDescriptor data, String[] files);
+ native private static int performBackup_native(String basePath, FileDescriptor oldState,
+ FileDescriptor data, FileDescriptor newState, String[] files);
}
diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index e839bb4..8627f08 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -21,6 +21,7 @@
import java.io.FileDescriptor;
+/** @hide */
public class SharedPreferencesBackupHelper {
public static void performBackup(Context context,
ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
@@ -34,7 +35,7 @@
files[i] = prefGroups[i] + ".xml";
}
- FileBackupHelper.performBackup_checked(basePath, oldSnapshot, newSnapshot, data, files);
+ FileBackupHelper.performBackup_checked(basePath, oldSnapshot, data, newSnapshot, files);
}
}
diff --git a/core/java/android/content/AbstractCursorEntityIterator.java b/core/java/android/content/AbstractCursorEntityIterator.java
new file mode 100644
index 0000000..bf3c4de
--- /dev/null
+++ b/core/java/android/content/AbstractCursorEntityIterator.java
@@ -0,0 +1,112 @@
+package android.content;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.RemoteException;
+
+/**
+ * An abstract class that makes it easy to implement an EntityIterator over a cursor.
+ * The user must implement {@link #newEntityFromCursorLocked}, which runs inside of a
+ * database transaction.
+ */
+public abstract class AbstractCursorEntityIterator implements EntityIterator {
+ private final Cursor mEntityCursor;
+ private final SQLiteDatabase mDb;
+ private volatile Entity mNextEntity;
+ private volatile boolean mIsClosed;
+
+ public AbstractCursorEntityIterator(SQLiteDatabase db, Cursor entityCursor) {
+ mEntityCursor = entityCursor;
+ mDb = db;
+ mNextEntity = null;
+ mIsClosed = false;
+ }
+
+ /**
+ * If there are entries left in the cursor then advance the cursor and use the new row to
+ * populate mNextEntity. If the cursor is at the end or if advancing it causes the cursor
+ * to become at the end then set mEntityCursor to null. If newEntityFromCursor returns null
+ * then continue advancing until it either returns a non-null Entity or the cursor reaches
+ * the end.
+ */
+ private void fillEntityIfAvailable() {
+ while (mNextEntity == null) {
+ if (!mEntityCursor.moveToNext()) {
+ // the cursor is at then end, bail out
+ return;
+ }
+ // This may return null if newEntityFromCursor is not able to create an entity
+ // from the current cursor position. In that case this method will loop and try
+ // the next cursor position
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ }
+ mDb.beginTransaction();
+ try {
+ int position = mEntityCursor.getPosition();
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ int newPosition = mEntityCursor.getPosition();
+ if (newPosition != position) {
+ throw new IllegalStateException("the cursor position changed during the call to"
+ + "newEntityFromCursorLocked, from " + position + " to " + newPosition);
+ }
+ } finally {
+ mDb.endTransaction();
+ }
+ }
+
+ /**
+ * Checks if there are more Entities accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return true if the call to next() will return an Entity.
+ */
+ public boolean hasNext() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling hasNext() when the iterator is closed");
+ }
+ fillEntityIfAvailable();
+ return mNextEntity != null;
+ }
+
+ /**
+ * Returns the next Entity that is accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return the next Entity that is accessible via this iterator
+ */
+ public Entity next() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling next() when the iterator is closed");
+ }
+ if (!hasNext()) {
+ throw new IllegalStateException("you may only call next() if hasNext() is true");
+ }
+
+ try {
+ return mNextEntity;
+ } finally {
+ mNextEntity = null;
+ }
+ }
+
+ /**
+ * Closes this iterator making it invalid. If is invalid for the user to call any public
+ * method on the iterator once it has been closed.
+ */
+ public void close() {
+ if (mIsClosed) {
+ throw new IllegalStateException("closing when already closed");
+ }
+ mIsClosed = true;
+ mEntityCursor.close();
+ }
+
+ /**
+ * Returns a new Entity from the current cursor position. This is called from within a
+ * database transaction. If a new entity cannot be created from this cursor position (e.g.
+ * if the row that is referred to no longer exists) then this may return null. The cursor
+ * is guaranteed to be pointing to a valid row when this call is made. The implementation
+ * of newEntityFromCursorLocked is not allowed to change the position of the cursor.
+ * @param cursor from where to read the data for the Entity
+ * @return an Entity that corresponds to the current cursor position or null
+ */
+ public abstract Entity newEntityFromCursorLocked(Cursor cursor);
+}
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 32c6864..0455202 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.Comparable;
/**
* Identifier for a specific application component
@@ -29,7 +30,7 @@
* name inside of that package.
*
*/
-public final class ComponentName implements Parcelable {
+public final class ComponentName implements Parcelable, Comparable<ComponentName> {
private final String mPackage;
private final String mClass;
@@ -196,6 +197,15 @@
public int hashCode() {
return mPackage.hashCode() + mClass.hashCode();
}
+
+ public int compareTo(ComponentName that) {
+ int v;
+ v = this.mPackage.compareTo(that.mPackage);
+ if (v != 0) {
+ return v;
+ }
+ return this.mClass.compareTo(that.mClass);
+ }
public int describeContents() {
return 0;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 3a080a0..3a8de6e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -130,6 +130,12 @@
selectionArgs, sortOrder);
}
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ checkReadPermission(uri);
+ return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
@@ -145,6 +151,11 @@
return ContentProvider.this.bulkInsert(uri, initialValues);
}
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) {
+ checkWritePermission(uri);
+ return ContentProvider.this.bulkInsertEntities(uri, entities);
+ }
+
public int delete(Uri uri, String selection, String[] selectionArgs) {
checkWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -156,6 +167,11 @@
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) {
+ checkWritePermission(uri);
+ return ContentProvider.this.bulkUpdateEntities(uri, entities);
+ }
+
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
@@ -328,6 +344,11 @@
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Return the MIME type of the data at the given URI. This should start with
* <code>vnd.android.cursor.item</code> for a single record,
@@ -378,6 +399,18 @@
return numValues;
}
+ public Uri insertEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) {
+ Uri[] result = new Uri[entities.length];
+ for (int i = 0; i < entities.length; i++) {
+ result[i] = insertEntity(uri, entities[i]);
+ }
+ return result;
+ }
+
/**
* A request to delete one or more rows. The selection clause is applied when performing
* the deletion, allowing the operation to affect multiple rows in a
@@ -422,6 +455,18 @@
public abstract int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs);
+ public int updateEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) {
+ int[] result = new int[entities.length];
+ for (int i = 0; i < entities.length; i++) {
+ result[i] = updateEntity(uri, entities[i]);
+ }
+ return result;
+ }
+
/**
* Open a file blob associated with a content URI.
* This method can be called from multiple
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 9902807..ed3ed42 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.content;
import android.database.Cursor;
@@ -26,52 +42,78 @@
mContentResolver = contentResolver;
}
- /** {@see ContentProvider#query} */
+ /** see {@link ContentProvider#query} */
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException {
return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder);
}
- /** {@see ContentProvider#getType} */
+ /** see {@link ContentProvider#getType} */
public String getType(Uri url) throws RemoteException {
return mContentProvider.getType(url);
}
- /** {@see ContentProvider#insert} */
+ /** see {@link ContentProvider#insert} */
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException {
return mContentProvider.insert(url, initialValues);
}
- /** {@see ContentProvider#bulkInsert} */
+ /** see {@link ContentProvider#bulkInsert} */
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
return mContentProvider.bulkInsert(url, initialValues);
}
- /** {@see ContentProvider#delete} */
+ /** see {@link ContentProvider#delete} */
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
return mContentProvider.delete(url, selection, selectionArgs);
}
- /** {@see ContentProvider#update} */
+ /** see {@link ContentProvider#update} */
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
return mContentProvider.update(url, values, selection, selectionArgs);
}
- /** {@see ContentProvider#openFile} */
+ /** see {@link ContentProvider#openFile} */
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
return mContentProvider.openFile(url, mode);
}
- /** {@see ContentProvider#openAssetFile} */
+ /** see {@link ContentProvider#openAssetFile} */
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
return mContentProvider.openAssetFile(url, mode);
}
+ /** see {@link ContentProvider#queryEntities} */
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ return mContentProvider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
+ /** see {@link ContentProvider#insertEntity} */
+ public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.bulkInsertEntities(uri, new Entity[]{entity})[0];
+ }
+
+ /** see {@link ContentProvider#bulkInsertEntities} */
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException {
+ return mContentProvider.bulkInsertEntities(uri, entities);
+ }
+
+ /** see {@link ContentProvider#updateEntity} */
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.bulkUpdateEntities(uri, new Entity[]{entity})[0];
+ }
+
+ /** see {@link ContentProvider#bulkUpdateEntities} */
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException {
+ return mContentProvider.bulkUpdateEntities(uri, entities);
+ }
+
/**
* Call this to indicate to the system that the associated {@link ContentProvider} is no
* longer needed by this {@link ContentProviderClient}.
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index f9282e2..ac67076 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -105,6 +105,20 @@
return true;
}
+ case QUERY_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri url = Uri.CREATOR.createFromParcel(data);
+ String selection = data.readString();
+ String[] selectionArgs = data.readStringArray();
+ String sortOrder = data.readString();
+ EntityIterator entityIterator = queryEntities(url, selection, selectionArgs,
+ sortOrder);
+ reply.writeNoException();
+ reply.writeStrongBinder(new IEntityIteratorImpl(entityIterator).asBinder());
+ return true;
+ }
+
case GET_TYPE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -140,6 +154,40 @@
return true;
}
+ case BULK_INSERT_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ String className = data.readString();
+ Class entityClass = Class.forName(className);
+ int numEntities = data.readInt();
+ Entity[] entities = new Entity[numEntities];
+ for (int i = 0; i < numEntities; i++) {
+ entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader());
+ }
+ Uri[] uris = bulkInsertEntities(uri, entities);
+ reply.writeNoException();
+ reply.writeTypedArray(uris, 0);
+ return true;
+ }
+
+ case BULK_UPDATE_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ String className = data.readString();
+ Class entityClass = Class.forName(className);
+ int numEntities = data.readInt();
+ Entity[] entities = new Entity[numEntities];
+ for (int i = 0; i < numEntities; i++) {
+ entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader());
+ }
+ int[] counts = bulkUpdateEntities(uri, entities);
+ reply.writeNoException();
+ reply.writeIntArray(counts);
+ return true;
+ }
+
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -215,6 +263,25 @@
return super.onTransact(code, data, reply, flags);
}
+ private class IEntityIteratorImpl extends IEntityIterator.Stub {
+ private final EntityIterator mEntityIterator;
+
+ IEntityIteratorImpl(EntityIterator iterator) {
+ mEntityIterator = iterator;
+ }
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() throws RemoteException {
+ mEntityIterator.close();
+ }
+ }
+
public IBinder asBinder()
{
return this;
@@ -288,7 +355,7 @@
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
adaptor.getObserver(), window);
-
+
if (bulkCursor == null) {
return null;
}
@@ -296,6 +363,54 @@
return adaptor;
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ url.writeToParcel(data, 0);
+ data.writeString(selection);
+ data.writeStringArray(selectionArgs);
+ data.writeString(sortOrder);
+
+ mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+
+ IBinder entityIteratorBinder = reply.readStrongBinder();
+
+ data.recycle();
+ reply.recycle();
+
+ return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder));
+ }
+
+ static class RemoteEntityIterator implements EntityIterator {
+ private final IEntityIterator mEntityIterator;
+ RemoteEntityIterator(IEntityIterator entityIterator) {
+ mEntityIterator = entityIterator;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() {
+ try {
+ mEntityIterator.close();
+ } catch (RemoteException e) {
+ // doesn't matter
+ }
+ }
+ }
+
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -357,6 +472,54 @@
return count;
}
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeString(entities[0].getClass().getName());
+ data.writeInt(entities.length);
+ for (Entity entity : entities) {
+ data.writeParcelable(entity, 0);
+ }
+
+ mRemote.transact(IContentProvider.BULK_INSERT_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ Uri[] results = new Uri[entities.length];
+ reply.readTypedArray(results, Uri.CREATOR);
+
+ data.recycle();
+ reply.recycle();
+
+ return results;
+ }
+
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeString(entities[0].getClass().getName());
+ data.writeInt(entities.length);
+ for (Entity entity : entities) {
+ data.writeParcelable(entity, 0);
+ }
+
+ mRemote.transact(IContentProvider.BULK_UPDATE_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ int[] results = new int[entities.length];
+ reply.readIntArray(results);
+
+ data.recycle();
+ reply.recycle();
+
+ return results;
+ }
+
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6f3b1b6..f9bed59 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -166,6 +166,53 @@
}
}
+ class EntityIteratorWrapper implements EntityIterator {
+ private final EntityIterator mInner;
+ private final ContentProviderClient mClient;
+
+ EntityIteratorWrapper(EntityIterator inner, ContentProviderClient client) {
+ mInner = inner;
+ mClient = client;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ return mInner.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mInner.next();
+ }
+
+ public void close() {
+ mClient.release();
+ mInner.close();
+ }
+
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+ }
+
+ public final EntityIterator queryEntity(Uri uri,
+ String selection, String[] selectionArgs, String sortOrder) throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ EntityIterator entityIterator =
+ provider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ return new EntityIteratorWrapper(entityIterator, provider);
+ } catch(RuntimeException e) {
+ provider.release();
+ throw e;
+ } catch(RemoteException e) {
+ provider.release();
+ throw e;
+ }
+ }
+
/**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
@@ -485,6 +532,56 @@
}
}
+ public final Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ return provider.insertEntity(uri, entity);
+ } finally {
+ provider.release();
+ }
+ }
+
+ public final int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ return provider.updateEntity(uri, entity);
+ } finally {
+ provider.release();
+ }
+ }
+
+ public final Uri[] bulkInsertEntities(Uri uri, Entity[] entities)
+ throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ return provider.bulkInsertEntities(uri, entities);
+ } finally {
+ provider.release();
+ }
+ }
+
+ public final int[] bulkUpdateEntities(Uri uri, Entity[] entities)
+ throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ return provider.bulkUpdateEntities(uri, entities);
+ } finally {
+ provider.release();
+ }
+ }
+
/**
* Inserts multiple rows into a table at the given URL.
*
diff --git a/core/java/android/content/Entity.aidl b/core/java/android/content/Entity.aidl
new file mode 100644
index 0000000..fb201f3
--- /dev/null
+++ b/core/java/android/content/Entity.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Entity.aidl
+**
+** Copyright 2007, 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.content;
+
+parcelable Entity;
diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java
new file mode 100644
index 0000000..31ea2cd
--- /dev/null
+++ b/core/java/android/content/Entity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.Parcelable;
+
+/**
+ * Objects that pass through the ContentProvider and ContentResolver's methods that deal with
+ * Entities must implement this abstract base class and thus themselves be Parcelable.
+ */
+public abstract class Entity implements Parcelable {
+}
diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java
new file mode 100644
index 0000000..61914cf
--- /dev/null
+++ b/core/java/android/content/EntityIterator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.RemoteException;
+
+public interface EntityIterator {
+ /**
+ * Returns whether there are more elements to iterate, i.e. whether the
+ * iterator is positioned in front of an element.
+ *
+ * @return {@code true} if there are more elements, {@code false} otherwise.
+ * @see #next
+ * @since Android 1.0
+ */
+ public boolean hasNext() throws RemoteException;
+
+ /**
+ * Returns the next object in the iteration, i.e. returns the element in
+ * front of the iterator and advances the iterator by one position.
+ *
+ * @return the next object.
+ * @throws java.util.NoSuchElementException
+ * if there are no more elements.
+ * @see #hasNext
+ * @since Android 1.0
+ */
+ public Entity next() throws RemoteException;
+
+ /**
+ * Indicates that this iterator is no longer needed and that any associated resources
+ * may be released (such as a SQLite cursor).
+ */
+ public void close();
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 0b81245..b4d1865 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -43,14 +43,19 @@
CursorWindow window) throws RemoteException;
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException;
+ public EntityIterator queryEntities(Uri url, String selection,
+ String[] selectionArgs, String sortOrder)
+ throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException;
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException;
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException;
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException;
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException;
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException;
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
public AssetFileDescriptor openAssetFile(Uri url, String mode)
@@ -67,4 +72,7 @@
static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12;
static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13;
static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14;
+ static final int BULK_INSERT_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 16;
+ static final int BULK_UPDATE_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 17;
+ static final int QUERY_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 18;
}
diff --git a/core/java/android/content/IEntityIterator.java b/core/java/android/content/IEntityIterator.java
new file mode 100644
index 0000000..eb800f7
--- /dev/null
+++ b/core/java/android/content/IEntityIterator.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * ICPC interface methods for an iterator over Entity objects.
+ */
+public interface IEntityIterator extends IInterface {
+ /** Local-side IPC implementation stub class. */
+ public static abstract class Stub extends Binder implements IEntityIterator {
+ private static final String TAG = "IEntityIterator";
+ private static final java.lang.String DESCRIPTOR = "android.content.IEntityIterator";
+
+ /** Construct the stub at attach it to the interface. */
+ public Stub() {
+ this.attachInterface(this, DESCRIPTOR);
+ }
+ /**
+ * Cast an IBinder object into an IEntityIterator interface,
+ * generating a proxy if needed.
+ */
+ public static IEntityIterator asInterface(IBinder obj) {
+ if ((obj==null)) {
+ return null;
+ }
+ IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+ if (((iin!=null)&&(iin instanceof IEntityIterator))) {
+ return ((IEntityIterator)iin);
+ }
+ return new IEntityIterator.Stub.Proxy(obj);
+ }
+
+ public IBinder asBinder() {
+ return this;
+ }
+
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ {
+ reply.writeString(DESCRIPTOR);
+ return true;
+ }
+
+ case TRANSACTION_hasNext:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ boolean _result;
+ try {
+ _result = this.hasNext();
+ } catch (Exception e) {
+ Log.e(TAG, "caught exception in hasNext()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ reply.writeInt(((_result)?(1):(0)));
+ return true;
+ }
+
+ case TRANSACTION_next:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ Entity entity;
+ try {
+ entity = this.next();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in next()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ reply.writeString(entity.getClass().getName());
+ reply.writeParcelable(entity, 0);
+ return true;
+ }
+
+ case TRANSACTION_close:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ try {
+ this.close();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in close()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ return true;
+ }
+ }
+ return super.onTransact(code, data, reply, flags);
+ }
+
+ private static class Proxy implements IEntityIterator {
+ private IBinder mRemote;
+ Proxy(IBinder remote) {
+ mRemote = remote;
+ }
+ public IBinder asBinder() {
+ return mRemote;
+ }
+ public java.lang.String getInterfaceDescriptor() {
+ return DESCRIPTOR;
+ }
+ public boolean hasNext() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ boolean _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_hasNext, _data, _reply, 0);
+ _reply.readException();
+ _result = (0!=_reply.readInt());
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public Entity next() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ Entity _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0);
+ _reply.readException();
+ final String className = _reply.readString();
+ final Class entityClass = Class.forName(className);
+ ClassLoader classLoader = entityClass.getClassLoader();
+ _result = (Entity) _reply.readParcelable(classLoader);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public void close() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_close, _data, _reply, 0);
+ _reply.readException();
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+ }
+ static final int TRANSACTION_hasNext = (IBinder.FIRST_CALL_TRANSACTION + 0);
+ static final int TRANSACTION_next = (IBinder.FIRST_CALL_TRANSACTION + 1);
+ static final int TRANSACTION_close = (IBinder.FIRST_CALL_TRANSACTION + 2);
+ }
+ public boolean hasNext() throws RemoteException;
+ public Entity next() throws RemoteException;
+ public void close() throws RemoteException;
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ebdd588..0e6be0a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -510,6 +510,7 @@
* <li> {@link #ACTION_BATTERY_CHANGED}
* <li> {@link #ACTION_POWER_CONNECTED}
* <li> {@link #ACTION_POWER_DISCONNECTED}
+ * <li> {@link #ACTION_SHUTDOWN}
* </ul>
*
* <h3>Standard Categories</h3>
@@ -1047,6 +1048,17 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
+ /**
+ * Activity Action: The user pressed the "Report" button in the crash/ANR dialog.
+ * This intent is delivered to the package which installed the application, usually
+ * the Market.
+ * <p>Input: No data is specified. The bug report is passed in using
+ * an {@link #EXTRA_BUG_REPORT} field.
+ * <p>Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
@@ -1271,6 +1283,15 @@
public static final String ACTION_POWER_DISCONNECTED =
"android.intent.action.POWER_DISCONNECTED";
/**
+ * Broadcast Action: Device is shutting down.
+ * This is broadcast when the device is being shut down (completely turned
+ * off, not sleeping). Once the broadcast is complete, the final shutdown
+ * will proceed and all unsaved data lost. Apps will not normally need
+ * to handle this, since the forground activity will be paused as well.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
+ /**
* Broadcast Action: Indicates low memory condition on the device
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -1532,6 +1553,21 @@
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
+ /**
+ * Broadcast Action: a remote intent is to be broadcasted.
+ *
+ * A remote intent is used for remote RPC between devices. The remote intent
+ * is serialized and sent from one device to another device. The receiving
+ * device parses the remote intent and broadcasts it. Note that anyone can
+ * broadcast a remote intent. However, if the intent receiver of the remote intent
+ * does not trust intent broadcasts from arbitrary intent senders, it should require
+ * the sender to hold certain permissions so only trusted sender's broadcast will be
+ * let through.
+ */
+ public static final String ACTION_REMOTE_INTENT =
+ "android.intent.action.REMOTE_INTENT";
+
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -1771,6 +1807,31 @@
* delivered.
*/
public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
+
+ /**
+ * Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
+ * the bug report.
+ *
+ * @hide
+ */
+ public static final String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
+
+ /**
+ * Used as a string extra field when sending an intent to PackageInstaller to install a
+ * package. Specifies the installer package name; this package will receive the
+ * {@link #ACTION_APP_ERROR} intent.
+ *
+ * @hide
+ */
+ public static final String EXTRA_INSTALLER_PACKAGE_NAME
+ = "android.intent.extra.INSTALLER_PACKAGE_NAME";
+
+ /**
+ * Used in the extra field in the remote intent. It's astring token passed with the
+ * remote intent.
+ */
+ public static final String EXTRA_REMOTE_INTENT_TOKEN =
+ "android.intent.extra.remote_intent_token";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
@@ -1931,7 +1992,7 @@
/**
* If set, this marks a point in the task's activity stack that should
* be cleared when the task is reset. That is, the next time the task
- * is broad to the foreground with
+ * is brought to the foreground with
* {@link #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} (typically as a result of
* the user re-launching it from home), this activity and all on top of
* it will be finished so that the user does not return to them, but
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 019abb8..03cfbea 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -255,6 +255,14 @@
}
};
+ private BroadcastReceiver mShutdownIntentReceiver =
+ new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ Log.w(TAG, "Writing sync state before shutdown...");
+ getSyncStorageEngine().writeAllState();
+ }
+ };
+
private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM";
private static final String SYNC_POLL_ALARM = "android.content.syncmanager.SYNC_POLL_ALARM";
private final SyncHandler mSyncHandler;
@@ -301,6 +309,10 @@
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
context.registerReceiver(mStorageIntentReceiver, intentFilter);
+ intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
+ intentFilter.setPriority(100);
+ context.registerReceiver(mShutdownIntentReceiver, intentFilter);
+
if (!factoryTest) {
mNotificationMgr = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index e20e70f..aaa763d 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -391,8 +391,7 @@
while (i > 0) {
i--;
AuthorityInfo authority = mAuthorities.get(i);
- if (authority.account.equals(account)
- && authority.authority.equals(providerName)) {
+ if (authority.authority.equals(providerName)) {
authority.enabled = sync;
}
}
@@ -740,7 +739,7 @@
}
boolean writeStatisticsNow = false;
- int day = getCurrentDay();
+ int day = getCurrentDayLocked();
if (mDayStats[0] == null) {
mDayStats[0] = new DayStats(day);
} else if (day != mDayStats[0].day) {
@@ -929,7 +928,7 @@
}
}
- private int getCurrentDay() {
+ private int getCurrentDayLocked() {
mCal.setTimeInMillis(System.currentTimeMillis());
final int dayOfYear = mCal.get(Calendar.DAY_OF_YEAR);
if (mYear != mCal.get(Calendar.YEAR)) {
@@ -1009,6 +1008,21 @@
return status;
}
+ public void writeAllState() {
+ synchronized (mAuthorities) {
+ // Account info is always written so no need to do it here.
+
+ if (mNumPendingFinished > 0) {
+ // Only write these if they are out of date.
+ writePendingOperationsLocked();
+ }
+
+ // Just always write these... they are likely out of date.
+ writeStatusLocked();
+ writeStatisticsLocked();
+ }
+ }
+
/**
* Read all account information back in to the initial engine state.
*/
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 173057c..88ac04c 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -113,19 +113,31 @@
*/
public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
-
/**
- * Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
- * {@hide}
+ * Value for {@link #flags}: this is set if this application has been
+ * install as an update to a built-in system application.
*/
public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
+
+ /**
+ * Value for {@link #flags}: this is set of the application has set
+ * its android:targetSdkVersion to something >= the current SDK version.
+ */
+ public static final int FLAG_TARGETS_SDK = 1<<8;
+
+ /**
+ * Value for {@link #flags}: this is set of the application has set
+ * its android:targetSdkVersion to something >= the current SDK version.
+ */
+ public static final int FLAG_TEST_ONLY = 1<<9;
/**
* Flags associated with the application. Any combination of
* {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
* {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
* {@link #FLAG_ALLOW_TASK_REPARENTING}
- * {@link #FLAG_ALLOW_CLEAR_USER_DATA}.
+ * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
+ * {@link #FLAG_TARGETS_SDK}.
*/
public int flags = 0;
diff --git a/core/java/android/content/pm/IPackageInstallObserver.aidl b/core/java/android/content/pm/IPackageInstallObserver.aidl
index e83bbc6..6133365 100644
--- a/core/java/android/content/pm/IPackageInstallObserver.aidl
+++ b/core/java/android/content/pm/IPackageInstallObserver.aidl
@@ -19,7 +19,7 @@
/**
* API for installation callbacks from the Package Manager.
- *
+ * @hide
*/
oneway interface IPackageInstallObserver {
void packageInstalled(in String packageName, int returnCode);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bf963ff..57b84b2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -140,8 +140,11 @@
* @param observer a callback to use to notify when the package installation in finished.
* @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
* {@link #REPLACE_EXISITING_PACKAGE}
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
*/
- void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags);
+ void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
+ in String installerPackageName);
/**
* Delete a package.
@@ -152,6 +155,8 @@
*/
void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags);
+ String getInstallerPackageName(in String packageName);
+
void addPackageToPreferred(String packageName);
void removePackageFromPreferred(String packageName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9e06666..8095990 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -172,6 +172,14 @@
public static final int GET_SUPPORTS_DENSITIES = 0x00008000;
/**
+ * Resolution and querying flag: if set, only filters that support the
+ * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for
+ * matching. This is a synonym for including the CATEGORY_DEFAULT in your
+ * supplied Intent.
+ */
+ public static final int MATCH_DEFAULT_ONLY = 0x00010000;
+
+ /**
* Permission check result: this is returned by {@link #checkPermission}
* if the permission has been granted to the given package.
*/
@@ -219,14 +227,6 @@
*/
public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
- /**
- * Resolution and querying flag: if set, only filters that support the
- * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for
- * matching. This is a synonym for including the CATEGORY_DEFAULT in your
- * supplied Intent.
- */
- public static final int MATCH_DEFAULT_ONLY = 0x00010000;
-
public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0;
public static final int COMPONENT_ENABLED_STATE_ENABLED = 1;
public static final int COMPONENT_ENABLED_STATE_DISABLED = 2;
@@ -235,14 +235,24 @@
* Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
* indicate that this package should be installed as forward locked, i.e. only the app itself
* should have access to it's code and non-resource assets.
+ * @hide
*/
- public static final int FORWARD_LOCK_PACKAGE = 0x00000001;
+ public static final int INSTALL_FORWARD_LOCK = 0x00000001;
/**
* Flag parameter for {@link #installPackage} to indicate that you want to replace an already
- * installed package, if one exists
+ * installed package, if one exists.
+ * @hide
*/
- public static final int REPLACE_EXISTING_PACKAGE = 0x00000002;
+ public static final int INSTALL_REPLACE_EXISTING = 0x00000002;
+
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that you want to
+ * allow test packages (those that have set android:testOnly in their
+ * manifest) to be installed.
+ * @hide
+ */
+ public static final int INSTALL_ALLOW_TEST = 0x00000004;
/**
* Flag parameter for
@@ -255,6 +265,7 @@
/**
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
+ * @hide
*/
public static final int INSTALL_SUCCEEDED = 1;
@@ -262,6 +273,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package is
* already installed.
+ * @hide
*/
public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
@@ -269,6 +281,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package archive
* file is invalid.
+ * @hide
*/
public static final int INSTALL_FAILED_INVALID_APK = -2;
@@ -276,13 +289,15 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the URI passed in
* is invalid.
+ * @hide
*/
public static final int INSTALL_FAILED_INVALID_URI = -3;
/**
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package manager
- * service found that the device didn't have enough storage space to install the app
+ * service found that the device didn't have enough storage space to install the app.
+ * @hide
*/
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
@@ -290,6 +305,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if a
* package is already installed with the same name.
+ * @hide
*/
public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
@@ -297,6 +313,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the requested shared user does not exist.
+ * @hide
*/
public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
@@ -305,6 +322,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* a previously installed package of the same name has a different signature
* than the new package (and the old package's data was not removed).
+ * @hide
*/
public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
@@ -313,6 +331,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package is requested a shared user which is already installed on the
* device and does not have matching signature.
+ * @hide
*/
public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
@@ -320,6 +339,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package uses a shared library that is not available.
+ * @hide
*/
public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
@@ -327,6 +347,7 @@
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package uses a shared library that is not available.
+ * @hide
*/
public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
@@ -335,6 +356,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package failed while optimizing and validating its dex files,
* either because there was not enough storage or the validation failed.
+ * @hide
*/
public static final int INSTALL_FAILED_DEXOPT = -11;
@@ -343,6 +365,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package failed because the current SDK version is older than
* that required by the package.
+ * @hide
*/
public static final int INSTALL_FAILED_OLDER_SDK = -12;
@@ -351,14 +374,35 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the new package failed because it contains a content provider with the
* same authority as a provider already installed in the system.
+ * @hide
*/
public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package failed because the current SDK version is newer than
+ * that required by the package.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_NEWER_SDK = -14;
+
+ /**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package failed because it has specified that it is a test-only
+ * package and the caller has not supplied the {@link #INSTALL_ALLOW_TEST}
+ * flag.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_TEST_ONLY = -15;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
* '.apk' extension.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
@@ -366,6 +410,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was unable to retrieve the AndroidManifest.xml file.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
@@ -373,6 +418,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser encountered an unexpected exception.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
@@ -380,6 +426,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser did not find any certificates in the .apk.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
@@ -387,6 +434,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser found inconsistent certificates on the files in the .apk.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
@@ -395,6 +443,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser encountered a CertificateEncodingException in one of the
* files in the .apk.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
@@ -402,6 +451,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser encountered a bad or missing package name in the manifest.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
@@ -409,6 +459,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser encountered a bad shared user id name in the manifest.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
@@ -416,6 +467,7 @@
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser encountered some structural problem in the manifest.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
@@ -424,6 +476,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser did not find any actionable tags (instrumentation or application)
* in the manifest.
+ * @hide
*/
public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
@@ -1330,6 +1383,8 @@
}
/**
+ * @hide
+ *
* Install a package. Since this may take a little while, the result will
* be posted back to the given observer. An installation will fail if the calling context
* lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
@@ -1341,13 +1396,14 @@
* @param observer An observer callback to get notified when the package installation is
* complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
- * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
- * {@link #REPLACE_EXISTING_PACKAGE}
- *
- * @see #installPackage(android.net.Uri)
+ * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
*/
public abstract void installPackage(
- Uri packageURI, IPackageInstallObserver observer, int flags);
+ Uri packageURI, IPackageInstallObserver observer, int flags,
+ String installerPackageName);
/**
* Attempts to delete a package. Since this may take a little while, the result will
@@ -1366,6 +1422,15 @@
*/
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
+
+ /**
+ * Retrieve the package name of the application that installed a package. This identifies
+ * which market the package came from.
+ *
+ * @param packageName The name of the package to query
+ */
+ public abstract String getInstallerPackageName(String packageName);
+
/**
* Attempts to clear the user data directory of an application.
* Since this may take a little while, the result will
@@ -1471,17 +1536,6 @@
IPackageStatsObserver observer);
/**
- * Install a package.
- *
- * @param packageURI The location of the package file to install
- *
- * @see #installPackage(android.net.Uri, IPackageInstallObserver, int)
- */
- public void installPackage(Uri packageURI) {
- installPackage(packageURI, null, 0);
- }
-
- /**
* Add a new package to the list of preferred packages. This new package
* will be added to the front of the list (removed from its current location
* if already listed), meaning it will now be preferred over all other
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f9c4984..88907c1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -59,6 +59,7 @@
private String mArchiveSourcePath;
private String[] mSeparateProcesses;
private int mSdkVersion;
+ private String mSdkCodename;
private int mParseError = PackageManager.INSTALL_SUCCEEDED;
@@ -123,8 +124,9 @@
mSeparateProcesses = procs;
}
- public void setSdkVersion(int sdkVersion) {
+ public void setSdkVersion(int sdkVersion, String codename) {
mSdkVersion = sdkVersion;
+ mSdkCodename = codename;
}
private static final boolean isPackageFilename(String name) {
@@ -613,9 +615,9 @@
int type;
final Package pkg = new Package(pkgName);
- pkg.mSystem = (flags&PARSE_IS_SYSTEM) != 0;
boolean foundApp = false;
-
+ boolean targetsSdk = false;
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = sa.getInteger(
@@ -721,19 +723,74 @@
XmlUtils.skipCurrentTag(parser);
- } else if (tagName.equals("uses-sdk")) {
+ } else if (tagName.equals("uses-sdk")) {
if (mSdkVersion > 0) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestUsesSdk);
- int vers = sa.getInt(
- com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion, 0);
+ int minVers = 0;
+ String minCode = null;
+ int targetVers = 0;
+ String targetCode = null;
+
+ TypedValue val = sa.peekValue(
+ com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+ if (val != null) {
+ if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+ targetCode = minCode = val.string.toString();
+ } else {
+ // If it's not a string, it's an integer.
+ minVers = val.data;
+ }
+ }
+
+ val = sa.peekValue(
+ com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+ if (val != null) {
+ if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+ targetCode = minCode = val.string.toString();
+ } else {
+ // If it's not a string, it's an integer.
+ targetVers = val.data;
+ }
+ }
+
+ int maxVers = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesSdk_maxSdkVersion,
+ mSdkVersion);
sa.recycle();
- if (vers > mSdkVersion) {
- outError[0] = "Requires newer sdk version #" + vers
- + " (current version is #" + mSdkVersion + ")";
+ if (targetCode != null) {
+ if (!targetCode.equals(mSdkCodename)) {
+ if (mSdkCodename != null) {
+ outError[0] = "Requires development platform " + targetCode
+ + " (current platform is " + mSdkCodename + ")";
+ } else {
+ outError[0] = "Requires development platform " + targetCode
+ + " but this is a release platform.";
+ }
+ mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+ return null;
+ }
+ // If the code matches, it definitely targets this SDK.
+ targetsSdk = true;
+ } else if (targetVers >= mSdkVersion) {
+ // If they have explicitly targeted our current version
+ // or something after it, then note this.
+ targetsSdk = true;
+ }
+
+ if (minVers > mSdkVersion) {
+ outError[0] = "Requires newer sdk version #" + minVers
+ + " (current version is #" + mSdkVersion + ")";
+ mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+ return null;
+ }
+
+ if (maxVers < mSdkVersion) {
+ outError[0] = "Requires older sdk version #" + maxVers
+ + " (current version is #" + mSdkVersion + ")";
mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
return null;
}
@@ -767,6 +824,10 @@
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
}
+ if (targetsSdk) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK;
+ }
+
if (pkg.usesLibraries.size() > 0) {
pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
@@ -1126,6 +1187,12 @@
ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
+ false)) {
+ ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
+ }
+
String str;
str = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestApplication_permission);
@@ -2133,9 +2200,6 @@
// If this is a 3rd party app, this is the path of the zip file.
public String mPath;
- // True if this package is part of the system image.
- public boolean mSystem;
-
// The version code declared for this package.
public int mVersionCode;
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index 6a560ce..fea63be 100755
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -27,8 +27,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.util.Xml;
-import android.view.Display;
-import android.view.WindowManager;
+import android.util.DisplayMetrics;
import java.io.IOException;
import java.util.ArrayList;
@@ -510,10 +509,11 @@
* @param modeId keyboard mode identifier
*/
public Keyboard(Context context, int xmlLayoutResId, int modeId) {
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- final Display display = wm.getDefaultDisplay();
- mDisplayWidth = display.getWidth();
- mDisplayHeight = display.getHeight();
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ mDisplayWidth = dm.widthPixels;
+ mDisplayHeight = dm.heightPixels;
+ //Log.v(TAG, "keyboard's display metrics:" + dm);
+
mDefaultHorizontalGap = 0;
mDefaultWidth = mDisplayWidth / 10;
mDefaultVerticalGap = 0;
diff --git a/core/java/android/net/http/CertificateValidatorCache.java b/core/java/android/net/http/CertificateValidatorCache.java
index 54a1dbe..47661d5 100644
--- a/core/java/android/net/http/CertificateValidatorCache.java
+++ b/core/java/android/net/http/CertificateValidatorCache.java
@@ -236,15 +236,17 @@
}
}
- int hashLength = secureHash.length;
- if (secureHash != null && 0 < hashLength) {
- if (hashLength == mHash.length) {
- for (int i = 0; i < hashLength; ++i) {
- if (secureHash[i] != mHash[i]) {
- return false;
+ if (secureHash != null) {
+ int hashLength = secureHash.length;
+ if (0 < hashLength) {
+ if (hashLength == mHash.length) {
+ for (int i = 0; i < hashLength; ++i) {
+ if (secureHash[i] != mHash[i]) {
+ return false;
+ }
}
+ return true;
}
- return true;
}
}
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index df4fff0..aeb85a2 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -116,12 +116,17 @@
mBodyProvider = bodyProvider;
mBodyLength = bodyLength;
- if (bodyProvider == null) {
+ if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
mHttpRequest = new BasicHttpRequest(method, getUri());
} else {
mHttpRequest = new BasicHttpEntityEnclosingRequest(
method, getUri());
- setBodyProvider(bodyProvider, bodyLength);
+ // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
+ // By using BasicHttpEntityEnclosingRequest, it will set up the
+ // correct content-length, content-type and content-encoding.
+ if (bodyProvider != null) {
+ setBodyProvider(bodyProvider, bodyLength);
+ }
}
addHeader(HOST_HEADER, getHostPort());
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 333ba73..8a0fd58 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -61,6 +61,13 @@
*/
public static final int SCAN_WIFI_LOCK = 6;
+ /**
+ * A constant indicating a wifi multicast timer
+ *
+ * {@hide}
+ */
+ public static final int WIFI_MULTICAST_ENABLED = 7;
+
/**
* Include all of the data in the stats, including previously saved data.
*/
@@ -225,9 +232,13 @@
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteScanWifiLockAcquiredLocked();
public abstract void noteScanWifiLockReleasedLocked();
+ public abstract void noteWifiMulticastEnabledLocked();
+ public abstract void noteWifiMulticastDisabledLocked();
public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getScanWifiLockTime(long batteryRealtime, int which);
+ public abstract long getWifiMulticastTime(long batteryRealtime,
+ int which);
/**
* Note that these must match the constants in android.os.LocalPowerManager.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 467c17f..5487c54 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -59,11 +59,47 @@
public static final String RELEASE = getString("ro.build.version.release");
/**
- * The user-visible SDK version of the framework. It is an integer starting at 1.
+ * The user-visible SDK version of the framework in its raw String
+ * representation; use {@link #SDK_INT} instead.
+ *
+ * @deprecated Use {@link #SDK_INT} to easily get this as an integer.
*/
public static final String SDK = getString("ro.build.version.sdk");
+
+ /**
+ * The user-visible SDK version of the framework; its possible
+ * values are defined in {@link Build.VERSION_CODES}.
+ */
+ public static final int SDK_INT = SystemProperties.getInt(
+ "ro.build.version.sdk", 0);
+
+ /**
+ * The current development codename, or the string "REL" if this is
+ * a release build.
+ */
+ public static final String CODENAME = getString("ro.build.version.codename");
}
+ /**
+ * Enumeration of the currently known SDK version codes. These are the
+ * values that can be found in {@link VERSION#SDK}. Version numbers
+ * increment monotonically with each official platform release.
+ */
+ public static class VERSION_CODES {
+ /**
+ * October 2008: The original, first, version of Android. Yay!
+ */
+ public static final int BASE = 1;
+ /**
+ * February 2009: First Android update, officially called 1.1.
+ */
+ public static final int BASE_1_1 = 2;
+ /**
+ * May 2009: Android 1.5.
+ */
+ public static final int CUPCAKE = 3;
+ }
+
/** The type of build, like "user" or "eng". */
public static final String TYPE = getString("ro.build.type");
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a7de895..d9612af 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -30,6 +30,10 @@
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
@@ -876,6 +880,17 @@
/**
+ * Equivalent to <code>setFieldsOn(cl, false)</code>.
+ *
+ * @see #setFieldsOn(Class, boolean)
+ *
+ * @hide
+ */
+ public static void setFieldsOn(Class<?> cl) {
+ setFieldsOn(cl, false);
+ }
+
+ /**
* Reflectively sets static fields of a class based on internal debugging
* properties. This method is a no-op if android.util.Config.DEBUG is
* false.
@@ -887,7 +902,7 @@
* Class setup: define a class whose only fields are non-final, static
* primitive types (except for "char") or Strings. In a static block
* after the field definitions/initializations, pass the class to
- * this method, Debug.setFieldsOn(). Example:
+ * this method, Debug.setFieldsOn(). Example:
* <pre>
* package com.example;
*
@@ -899,12 +914,18 @@
* public static String ns = null;
* public static boolean b = false;
* public static int i = 5;
+ * @Debug.DebugProperty
* public static float f = 0.1f;
+ * @@Debug.DebugProperty
* public static double d = 0.5d;
*
* // This MUST appear AFTER all fields are defined and initialized!
* static {
+ * // Sets all the fields
* Debug.setFieldsOn(MyDebugVars.class);
+ *
+ * // Sets only the fields annotated with @Debug.DebugProperty
+ * // Debug.setFieldsOn(MyDebugVars.class, true);
* }
* }
* </pre>
@@ -917,25 +938,31 @@
* {@hide}
*
* @param cl The class to (possibly) modify
+ * @param partial If false, sets all static fields, otherwise, only set
+ * fields with the {@link android.os.Debug.DebugProperty}
+ * annotation
* @throws IllegalArgumentException if any fields are final or non-static,
* or if the type of the field does not match the type of
* the internal debugging property value.
*/
- public static void setFieldsOn(Class<?> cl) {
+ public static void setFieldsOn(Class<?> cl, boolean partial) {
if (Config.DEBUG) {
if (debugProperties != null) {
/* Only look for fields declared directly by the class,
* so we don't mysteriously change static fields in superclasses.
*/
for (Field field : cl.getDeclaredFields()) {
- final String propertyName = cl.getName() + "." + field.getName();
- boolean isStatic = Modifier.isStatic(field.getModifiers());
- boolean isFinal = Modifier.isFinal(field.getModifiers());
- if (!isStatic || isFinal) {
- throw new IllegalArgumentException(propertyName +
- " must be static and non-final");
+ if (!partial || field.getAnnotation(DebugProperty.class) != null) {
+ final String propertyName = cl.getName() + "." + field.getName();
+ boolean isStatic = Modifier.isStatic(field.getModifiers());
+ boolean isFinal = Modifier.isFinal(field.getModifiers());
+
+ if (!isStatic || isFinal) {
+ throw new IllegalArgumentException(propertyName +
+ " must be static and non-final");
+ }
+ modifyFieldIfSet(field, debugProperties, propertyName);
}
- modifyFieldIfSet(field, debugProperties, propertyName);
}
}
} else {
@@ -944,4 +971,15 @@
") called in non-DEBUG build");
}
}
+
+ /**
+ * Annotation to put on fields you want to set with
+ * {@link Debug#setFieldsOn(Class, boolean)}.
+ *
+ * @hide
+ */
+ @Target({ ElementType.FIELD })
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface DebugProperty {
+ }
}
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
index 47497e5..3679e47 100644
--- a/core/java/android/os/Power.java
+++ b/core/java/android/os/Power.java
@@ -80,10 +80,9 @@
public static native int setLastUserActivityTimeout(long ms);
/**
- * Turn the device off.
- *
- * This method is considered deprecated in favor of
- * {@link android.policy.ShutdownThread.shutdownAfterDisablingRadio()}.
+ * Low-level function turn the device off immediately, without trying
+ * to be clean. Most people should use
+ * {@link android.internal.app.ShutdownThread} for a clean shutdown.
*
* @deprecated
* @hide
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index daa99c2..8f12355 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -438,6 +438,7 @@
*
* @param s the string to parse
* @return true if the resulting time value is in UTC time
+ * @throws android.util.TimeFormatException if s cannot be parsed.
*/
public boolean parse3339(String s) {
if (nativeParse3339(s)) {
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 095f4f4..e4dd020 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -99,4 +99,24 @@
xdpi = DEVICE_DENSITY;
ydpi = DEVICE_DENSITY;
}
+
+ /**
+ * Set the display metrics' density and update parameters depend on it.
+ * @hide
+ */
+ public void updateDensity(float newDensity) {
+ float ratio = newDensity / density;
+ density = newDensity;
+ scaledDensity = density;
+ widthPixels *= ratio;
+ heightPixels *= ratio;
+ xdpi *= ratio;
+ ydpi *= ratio;
+ }
+
+ public String toString() {
+ return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
+ ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
+ ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
+ }
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 71da9cf..49e4e4c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -257,6 +257,23 @@
}
@Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ // SurfaceView uses pre-scaled size unless fixed size is requested. This hook
+ // scales the event back to the pre-scaled coordinates for such surface.
+ if (mRequestedWidth < 0 && mAppScale != 1.0f) {
+ MotionEvent scaledBack = MotionEvent.obtain(event);
+ scaledBack.scale(mAppScale);
+ try {
+ return super.dispatchTouchEvent(scaledBack);
+ } finally {
+ scaledBack.recycle();
+ }
+ } else {
+ return super.dispatchTouchEvent(event);
+ }
+ }
+
+ @Override
protected void dispatchDraw(Canvas canvas) {
// if SKIP_DRAW is cleared, draw() has already punched a hole
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
@@ -278,7 +295,13 @@
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
-
+
+ // Use original size for surface unless fixed size is requested.
+ if (mRequestedWidth <= 0) {
+ myWidth *= mAppScale;
+ myHeight *= mAppScale;
+ }
+
getLocationInWindow(mLocation);
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
@@ -304,8 +327,9 @@
mFormat = mRequestedFormat;
mType = mRequestedType;
- mLayout.x = mLeft;
- mLayout.y = mTop;
+ // Scaling window's layout here beause mLayout is not used elsewhere.
+ mLayout.x = (int) (mLeft * mAppScale);
+ mLayout.y = (int) (mTop * mAppScale);
mLayout.width = (int) (getWidth() * mAppScale);
mLayout.height = (int) (getHeight() * mAppScale);
mLayout.format = mRequestedFormat;
@@ -334,7 +358,7 @@
mSurfaceLock.lock();
mDrawingStopped = !visible;
final int relayoutResult = mSession.relayout(
- mWindow, mLayout, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale),
+ mWindow, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
@@ -358,7 +382,7 @@
synchronized (mCallbacks) {
callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
mCallbacks.toArray(callbacks);
- }
+ }
if (visibleChanged) {
mIsCreating = true;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d042f28d..16b70ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -49,6 +49,7 @@
import android.util.Pool;
import android.util.Pools;
import android.util.PoolableManager;
+import android.util.Config;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Animation;
import android.view.inputmethod.InputConnection;
@@ -1405,6 +1406,28 @@
static final int SCROLL_CONTAINER_ADDED = 0x00100000;
/**
+ * View flag indicating whether this view was invalidated (fully or partially.)
+ *
+ * @hide
+ */
+ static final int DIRTY = 0x00200000;
+
+ /**
+ * View flag indicating whether this view was invalidated by an opaque
+ * invalidate request.
+ *
+ * @hide
+ */
+ static final int DIRTY_OPAQUE = 0x00400000;
+
+ /**
+ * Mask for {@link #DIRTY} and {@link #DIRTY_OPAQUE}.
+ *
+ * @hide
+ */
+ static final int DIRTY_MASK = 0x00600000;
+
+ /**
* The parent this view is attached to.
* {@hide}
*
@@ -1420,7 +1443,18 @@
/**
* {@hide}
*/
- @ViewDebug.ExportedProperty
+ @ViewDebug.ExportedProperty(flagMapping = {
+ @ViewDebug.FlagToString(mask = FORCE_LAYOUT, equals = FORCE_LAYOUT,
+ name = "FORCE_LAYOUT"),
+ @ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED,
+ name = "LAYOUT_REQUIRED"),
+ @ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID,
+ name = "DRAWING_CACHE_INVALID", outputIf = false),
+ @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true),
+ @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false),
+ @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
+ @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY, name = "DIRTY")
+ })
int mPrivateFlags;
/**
@@ -4522,6 +4556,24 @@
}
/**
+ * Indicates whether this View is opaque. An opaque View guarantees that it will
+ * draw all the pixels overlapping its bounds using a fully opaque color.
+ *
+ * Subclasses of View should override this method whenever possible to indicate
+ * whether an instance is opaque. Opaque Views are treated in a special way by
+ * the View hierarchy, possibly allowing it to perform optimizations during
+ * invalidate/draw passes.
+ *
+ * @return True if this View is guaranteed to be fully opaque, false otherwise.
+ *
+ * @hide Pending API council approval
+ */
+ @ViewDebug.ExportedProperty
+ public boolean isOpaque() {
+ return mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE;
+ }
+
+ /**
* @return A handler associated with the thread running the View. This
* handler can be used to pump events in the UI events queue.
*/
@@ -5601,7 +5653,7 @@
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
- if (ViewRoot.PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60002, hashCode());
}
@@ -5694,6 +5746,7 @@
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
+ mPrivateFlags &= ~DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
@@ -5740,7 +5793,7 @@
canvas = new Canvas(bitmap);
}
- if ((backgroundColor&0xff000000) != 0) {
+ if ((backgroundColor & 0xff000000) != 0) {
bitmap.eraseColor(backgroundColor);
}
@@ -5748,6 +5801,10 @@
final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY);
+ // Temporarily remove the dirty mask
+ int flags = mPrivateFlags;
+ mPrivateFlags &= ~DIRTY_MASK;
+
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
dispatchDraw(canvas);
@@ -5755,6 +5812,8 @@
draw(canvas);
}
+ mPrivateFlags = flags;
+
canvas.restoreToCount(restoreCount);
if (attachInfo != null) {
@@ -5875,7 +5934,10 @@
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
- mPrivateFlags |= DRAWN;
+ final int privateFlags = mPrivateFlags;
+ final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
+ (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
+ mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
@@ -5892,22 +5954,24 @@
// Step 1, draw the background, if needed
int saveCount;
- final Drawable background = mBGDrawable;
- if (background != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
+ if (!dirtyOpaque) {
+ final Drawable background = mBGDrawable;
+ if (background != null) {
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
- mBackgroundSizeChanged = false;
- }
+ if (mBackgroundSizeChanged) {
+ background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
+ mBackgroundSizeChanged = false;
+ }
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
+ if ((scrollX | scrollY) == 0) {
+ background.draw(canvas);
+ } else {
+ canvas.translate(scrollX, scrollY);
+ background.draw(canvas);
+ canvas.translate(-scrollX, -scrollY);
+ }
}
}
@@ -5917,7 +5981,7 @@
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
- onDraw(canvas);
+ if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
@@ -6020,7 +6084,7 @@
}
// Step 3, draw the content
- onDraw(canvas);
+ if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
@@ -7123,6 +7187,60 @@
}
/**
+ * @param consistency The type of consistency. See ViewDebug for more information.
+ *
+ * @hide
+ */
+ protected boolean dispatchConsistencyCheck(int consistency) {
+ return onConsistencyCheck(consistency);
+ }
+
+ /**
+ * Method that subclasses should implement to check their consistency. The type of
+ * consistency check is indicated by the bit field passed as a parameter.
+ *
+ * @param consistency The type of consistency. See ViewDebug for more information.
+ *
+ * @throws IllegalStateException if the view is in an inconsistent state.
+ *
+ * @hide
+ */
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = true;
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+ final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
+
+ if (checkLayout) {
+ if (getParent() == null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " does not have a parent.");
+ }
+
+ if (mAttachInfo == null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " is not attached to a window.");
+ }
+ }
+
+ if (checkDrawing) {
+ // Do not check the DIRTY/DRAWN flags because views can call invalidate()
+ // from their draw() method
+
+ if ((mPrivateFlags & DRAWN) != DRAWN &&
+ (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + this + " was invalidated but its drawing cache is valid.");
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Prints information about this view in the log output, with the tag
* {@link #VIEW_LOG_TAG}.
*
@@ -8049,7 +8167,6 @@
* window.
*/
static class AttachInfo {
-
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -8179,6 +8296,11 @@
long mDrawingTime;
/**
+ * Indicates whether or not ignoring the DIRTY_MASK flags.
+ */
+ boolean mIgnoreDirtyState;
+
+ /**
* Indicates whether the view's window is currently in touch mode.
*/
boolean mInTouchMode;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 367c9a2..aaaadef 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -54,6 +54,27 @@
*/
public class ViewDebug {
/**
+ * Log tag used to log errors related to the consistency of the view hierarchy.
+ *
+ * @hide
+ */
+ public static final String CONSISTENCY_LOG_TAG = "ViewConsistency";
+
+ /**
+ * Flag indicating the consistency check should check layout-related properties.
+ *
+ * @hide
+ */
+ public static final int CONSISTENCY_LAYOUT = 0x1;
+
+ /**
+ * Flag indicating the consistency check should check drawing-related properties.
+ *
+ * @hide
+ */
+ public static final int CONSISTENCY_DRAWING = 0x2;
+
+ /**
* Enables or disables view hierarchy tracing. Any invoker of
* {@link #trace(View, android.view.ViewDebug.HierarchyTraceType)} should first
* check that this value is set to true as not to affect performance.
@@ -80,6 +101,49 @@
static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent";
/**
+ * Profiles drawing times in the events log.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean profileDrawing = false;
+
+ /**
+ * Profiles layout times in the events log.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean profileLayout = false;
+
+ /**
+ * Profiles real fps (times between draws) and displays the result.
+ *
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean showFps = false;
+
+ /**
+ * <p>Enables or disables views consistency check. Even when this property is enabled,
+ * view consistency checks happen only if {@link android.util.Config#DEBUG} is set
+ * to true. The value of this property can be configured externally in one of the
+ * following files:</p>
+ * <ul>
+ * <li>/system/debug.prop</li>
+ * <li>/debug.prop</li>
+ * <li>/data/debug.prop</li>
+ * </ul>
+ * @hide
+ */
+ @Debug.DebugProperty
+ public static boolean consistencyCheckEnabled = false;
+
+ static {
+ Debug.setFieldsOn(ViewDebug.class, true);
+ }
+
+ /**
* This annotation can be used to mark fields and methods to be dumped by
* the view server. Only non-void methods with no arguments can be annotated
* by this annotation.
@@ -123,7 +187,7 @@
* of an array:
*
* <pre>
- * @ViewDebug.ExportedProperty(mapping = {
+ * @ViewDebug.ExportedProperty(indexMapping = {
* @ViewDebug.IntToString(from = 0, to = "INVALID"),
* @ViewDebug.IntToString(from = 1, to = "FIRST"),
* @ViewDebug.IntToString(from = 2, to = "SECOND")
@@ -139,6 +203,25 @@
IntToString[] indexMapping() default { };
/**
+ * A flags mapping can be defined to map flags encoded in an integer to
+ * specific strings. A mapping can be used to see human readable values
+ * for the flags of an integer:
+ *
+ * <pre>
+ * @ViewDebug.ExportedProperty(flagMapping = {
+ * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = ENABLED, name = "ENABLED"),
+ * @ViewDebug.FlagToString(mask = ENABLED_MASK, equals = DISABLED, name = "DISABLED"),
+ * })
+ * private int mFlags;
+ * <pre>
+ *
+ * A specified String is output when the following is true:
+ *
+ * @return An array of int to String mappings
+ */
+ FlagToString[] flagMapping() default { };
+
+ /**
* When deep export is turned on, this property is not dumped. Instead, the
* properties contained in this property are dumped. Each child property
* is prefixed with the name of this property.
@@ -182,7 +265,45 @@
*/
String to();
}
-
+
+ /**
+ * Defines a mapping from an flag to a String. Such a mapping can be used
+ * in a @ExportedProperty to provide more meaningful values to the end user.
+ *
+ * @see android.view.ViewDebug.ExportedProperty
+ */
+ @Target({ ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface FlagToString {
+ /**
+ * The mask to apply to the original value.
+ *
+ * @return An arbitrary int value.
+ */
+ int mask();
+
+ /**
+ * The value to compare to the result of:
+ * <code>original value & {@link #mask()}</code>.
+ *
+ * @return An arbitrary value.
+ */
+ int equals();
+
+ /**
+ * The String to use in place of the original int value.
+ *
+ * @return An arbitrary non-null String.
+ */
+ String name();
+
+ /**
+ * Indicates whether to output the flag when the test is true,
+ * or false. Defaults to true.
+ */
+ boolean outputIf() default true;
+ }
+
/**
* This annotation can be used to mark fields and methods to be dumped when
* the view is captured. Methods with this annotation must have no arguments
@@ -975,6 +1096,13 @@
final int id = (Integer) methodValue;
methodValue = resolveId(context, id);
} else {
+ final FlagToString[] flagsMapping = property.flagMapping();
+ if (flagsMapping.length > 0) {
+ final int intValue = (Integer) methodValue;
+ final String valuePrefix = prefix + method.getName() + '_';
+ exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
+ }
+
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
final int intValue = (Integer) methodValue;
@@ -1036,6 +1164,13 @@
final int id = field.getInt(view);
fieldValue = resolveId(context, id);
} else {
+ final FlagToString[] flagsMapping = property.flagMapping();
+ if (flagsMapping.length > 0) {
+ final int intValue = field.getInt(view);
+ final String valuePrefix = prefix + field.getName() + '_';
+ exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix);
+ }
+
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
final int intValue = field.getInt(view);
@@ -1093,6 +1228,23 @@
out.write(' ');
}
+ private static void exportUnrolledFlags(BufferedWriter out, FlagToString[] mapping,
+ int intValue, String prefix) throws IOException {
+
+ final int count = mapping.length;
+ for (int j = 0; j < count; j++) {
+ final FlagToString flagMapping = mapping[j];
+ final boolean ifTrue = flagMapping.outputIf();
+ final int maskResult = intValue & flagMapping.mask();
+ final boolean test = maskResult == flagMapping.equals();
+ if ((test && ifTrue) || (!test && !ifTrue)) {
+ final String name = flagMapping.name();
+ final String value = "0x" + Integer.toHexString(maskResult);
+ writeEntry(out, prefix, name, "", value);
+ }
+ }
+ }
+
private static void exportUnrolledArray(Context context, BufferedWriter out,
ExportedProperty property, int[] array, String prefix, String suffix)
throws IOException {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e686d1c..db5177f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,6 +32,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import android.util.Config;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
@@ -1402,7 +1403,7 @@
}
}
- // Clear the flag as early as possible to allow draw() implementations
+ // Sets the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations
child.mPrivateFlags |= DRAWN;
@@ -1481,6 +1482,7 @@
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
+ child.mPrivateFlags &= ~DIRTY_MASK;
child.dispatchDraw(canvas);
} else {
child.draw(canvas);
@@ -1494,7 +1496,7 @@
cachePaint.setAlpha(255);
mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
}
- if (ViewRoot.PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60003, hashCode());
}
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
@@ -1796,7 +1798,7 @@
boolean preventRequestLayout) {
child.mParent = null;
addViewInner(child, index, params, preventRequestLayout);
- child.mPrivateFlags |= DRAWN;
+ child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
return true;
}
@@ -2210,7 +2212,7 @@
addInArray(child, index);
child.mParent = this;
- child.mPrivateFlags |= DRAWN;
+ child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
@@ -2320,15 +2322,33 @@
// ourselves and the parent to make sure the invalidate request goes
// through
final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
-
+
+ // Check whether the child that requests the invalidate is fully opaque
+ final boolean isOpaque = child.isOpaque();
+ // Mark the child as dirty, using the appropriate flag
+ // Make sure we do not set both flags at the same time
+ final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
+
do {
+ View view = null;
+ if (parent instanceof View) {
+ view = (View) parent;
+ }
+
if (drawAnimation) {
- if (parent instanceof View) {
- ((View) parent).mPrivateFlags |= DRAW_ANIMATION;
+ if (view != null) {
+ view.mPrivateFlags |= DRAW_ANIMATION;
} else if (parent instanceof ViewRoot) {
((ViewRoot) parent).mIsAnimating = true;
}
}
+
+ // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
+ // flag coming from the child that initiated the invalidate
+ if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+ view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+ }
+
parent = parent.invalidateChildInParent(location, dirty);
} while (parent != null);
}
@@ -2732,6 +2752,61 @@
}
/**
+ * @hide
+ */
+ @Override
+ protected boolean dispatchConsistencyCheck(int consistency) {
+ boolean result = super.dispatchConsistencyCheck(consistency);
+
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = super.onConsistencyCheck(consistency);
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+ final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
+
+ if (checkLayout) {
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ if (children[i].getParent() != this) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "View " + children[i] + " has no parent/a parent that is not " + this);
+ }
+ }
+ }
+
+ if (checkDrawing) {
+ // If this group is dirty, check that the parent is dirty as well
+ if ((mPrivateFlags & DIRTY_MASK) != 0) {
+ final ViewParent parent = getParent();
+ if (parent != null && !(parent instanceof ViewRoot)) {
+ if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "ViewGroup " + this + " is dirty but its parent is not: " + this);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 0b03626..dbfb194 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -75,13 +75,6 @@
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean WATCH_POINTER = false;
- static final boolean PROFILE_DRAWING = false;
- private static final boolean PROFILE_LAYOUT = false;
- // profiles real fps (times between draws) and displays the result
- private static final boolean SHOW_FPS = false;
- // used by SHOW_FPS
- private static int sDrawTime;
-
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -97,6 +90,8 @@
static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+ private static int sDrawTime;
+
long mLastTrackballTime = 0;
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -128,9 +123,10 @@
int mHeight;
Rect mDirty; // will be a graphics.Region soon
boolean mIsAnimating;
- // TODO: change these to scaler class.
- float mAppScale;
- float mAppScaleInverted; // = 1.0f / mAppScale
+ // TODO: change these to scalar class.
+ private float mAppScale;
+ private float mAppScaleInverted; // = 1.0f / mAppScale
+ private int[] mWindowLayoutParamsBackup = null;
final View.AttachInfo mAttachInfo;
@@ -389,6 +385,9 @@
if (mView == null) {
mView = view;
mAppScale = mView.getContext().getApplicationScale();
+ if (mAppScale != 1.0f) {
+ mWindowLayoutParamsBackup = new int[4];
+ }
mAppScaleInverted = 1.0f / mAppScale;
mWindowAttributes.copyFrom(attrs);
mSoftInputMode = attrs.softInputMode;
@@ -478,7 +477,6 @@
synchronized (this) {
int oldSoftInputMode = mWindowAttributes.softInputMode;
mWindowAttributes.copyFrom(attrs);
- mWindowAttributes.scale(mAppScale);
if (newView) {
mSoftInputMode = attrs.softInputMode;
@@ -795,7 +793,7 @@
final Rect frame = mWinFrame;
boolean initialized = false;
boolean contentInsetsChanged = false;
- boolean visibleInsetsChanged = false;
+ boolean visibleInsetsChanged;
try {
boolean hadSurface = mSurface.isValid();
int fl = 0;
@@ -936,14 +934,22 @@
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
"ViewRoot", "Laying out " + host + " to (" +
host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
- long startTime;
- if (PROFILE_LAYOUT) {
+ long startTime = 0L;
+ if (Config.DEBUG && ViewDebug.profileLayout) {
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
- if (PROFILE_LAYOUT) {
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
+ throw new IllegalStateException("The view hierarchy is an inconsistent state,"
+ + "please refer to the logs with the tag "
+ + ViewDebug.CONSISTENCY_LOG_TAG + " for more infomation.");
+ }
+ }
+
+ if (Config.DEBUG && ViewDebug.profileLayout) {
EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
}
@@ -1135,8 +1141,7 @@
}
int yoff;
- final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
+ final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
if (scrolling) {
yoff = mScroller.getCurrY();
} else {
@@ -1151,13 +1156,14 @@
if (mUseGL) {
if (!dirty.isEmpty()) {
Canvas canvas = mGlCanvas;
- if (mGL!=null && canvas != null) {
+ if (mGL != null && canvas != null) {
mGL.glDisable(GL_SCISSOR_TEST);
mGL.glClearColor(0, 0, 0, 0);
mGL.glClear(GL_COLOR_BUFFER_BIT);
mGL.glEnable(GL_SCISSOR_TEST);
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+ mAttachInfo.mIgnoreDirtyState = true;
mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale;
@@ -1168,14 +1174,19 @@
canvas.scale(scale, scale);
}
mView.draw(canvas);
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
+ }
} finally {
canvas.restoreToCount(saveCount);
}
+ mAttachInfo.mIgnoreDirtyState = false;
+
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglErrors();
- if (SHOW_FPS) {
+ if (Config.DEBUG && ViewDebug.showFps) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1191,8 +1202,10 @@
return;
}
- if (fullRedrawNeeded)
+ if (fullRedrawNeeded) {
+ mAttachInfo.mIgnoreDirtyState = true;
dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
+ }
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Draw " + mView + "/"
@@ -1204,7 +1217,18 @@
Canvas canvas;
try {
+ int left = dirty.left;
+ int top = dirty.top;
+ int right = dirty.right;
+ int bottom = dirty.bottom;
+
canvas = surface.lockCanvas(dirty);
+
+ if (left != dirty.left || top != dirty.top || right != dirty.right ||
+ bottom != dirty.bottom) {
+ mAttachInfo.mIgnoreDirtyState = true;
+ }
+
// TODO: Do this in native
canvas.setDensityScale(mDensity);
} catch (Surface.OutOfResourcesException e) {
@@ -1216,7 +1240,7 @@
try {
if (!dirty.isEmpty() || mIsAnimating) {
- long startTime;
+ long startTime = 0L;
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
@@ -1224,7 +1248,7 @@
//canvas.drawARGB(255, 255, 0, 0);
}
- if (PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
startTime = SystemClock.elapsedRealtime();
}
@@ -1232,12 +1256,11 @@
// need to clear it before drawing so that the child will
// properly re-composite its drawing on a transparent
// background. This automatically respects the clip/dirty region
- if (!canvas.isOpaque()) {
- canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
- } else if (yoff != 0) {
- // If we are applying an offset, we need to clear the area
- // where the offset doesn't appear to avoid having garbage
- // left in the blank areas.
+ // or
+ // If we are applying an offset, we need to clear the area
+ // where the offset doesn't appear to avoid having garbage
+ // left in the blank areas.
+ if (!canvas.isOpaque() || yoff != 0) {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
@@ -1247,9 +1270,10 @@
mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale;
- Context cxt = mView.getContext();
if (DEBUG_DRAW) {
- Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + ", appScale=" + mAppScale);
+ Context cxt = mView.getContext();
+ Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
+ ", appScale=" + mAppScale);
}
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
@@ -1260,10 +1284,15 @@
}
mView.draw(canvas);
} finally {
+ mAttachInfo.mIgnoreDirtyState = false;
canvas.restoreToCount(saveCount);
}
- if (SHOW_FPS) {
+ if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
+ mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
+ }
+
+ if (Config.DEBUG && ViewDebug.showFps) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1271,7 +1300,7 @@
sDrawTime = now;
}
- if (PROFILE_DRAWING) {
+ if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
}
}
@@ -2309,12 +2338,22 @@
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
+
+ boolean restore = false;
+ if (params != null && mAppScale != 1.0f) {
+ restore = true;
+ params.scale(mAppScale, mWindowLayoutParamsBackup);
+ }
int relayoutResult = sWindowSession.relayout(
mWindow, params,
(int) (mView.mMeasuredWidth * mAppScale),
(int) (mView.mMeasuredHeight * mAppScale),
viewVisibility, insetsPending, mWinFrame,
mPendingContentInsets, mPendingVisibleInsets, mSurface);
+ if (restore) {
+ params.restore(mWindowLayoutParamsBackup);
+ }
+
mPendingContentInsets.scale(mAppScaleInverted);
mPendingVisibleInsets.scale(mAppScaleInverted);
mWinFrame.scale(mAppScaleInverted);
@@ -2416,7 +2455,7 @@
msg.arg2 = handled ? 1 : 0;
sendMessage(msg);
}
-
+
public void dispatchResized(int w, int h, Rect coveredInsets,
Rect visibleInsets, boolean reportDraw) {
if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f6a171d..c69c281 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,6 +18,7 @@
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -954,19 +955,42 @@
return sb.toString();
}
- void scale(float scale) {
+ /**
+ * Scale the layout params' coordinates and size.
+ * Returns the original info as a backup so that the caller can
+ * restore the layout params;
+ */
+ void scale(float scale, int[] backup) {
if (scale != 1.0f) {
+ backup[0] = x;
+ backup[1] = y;
x *= scale;
y *= scale;
if (width > 0) {
+ backup[2] = width;
width *= scale;
}
if (height > 0) {
+ backup[3] = height;
height *= scale;
}
}
}
+ /**
+ * Restore the layout params' coordinates and size.
+ */
+ void restore(int[] backup) {
+ x = backup[0];
+ y = backup[1];
+ if (width > 0) {
+ width = backup[2];
+ }
+ if (height > 0) {
+ height = backup[3];
+ }
+ }
+
private CharSequence mTitle = "";
}
}
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index be15ef8..667cb2c 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -99,6 +99,7 @@
private static final int RECEIVED_CERTIFICATE = 124;
private static final int SWITCH_OUT_HISTORY = 125;
private static final int EXCEEDED_DATABASE_QUOTA = 126;
+ private static final int JS_TIMEOUT = 127;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -548,6 +549,18 @@
}
break;
+ case JS_TIMEOUT:
+ if(mWebChromeClient != null) {
+ final JsResult res = (JsResult) msg.obj;
+ if(mWebChromeClient.onJsTimeout()) {
+ res.confirm();
+ } else {
+ res.cancel();
+ }
+ res.setReady();
+ }
+ break;
+
case RECEIVED_CERTIFICATE:
mWebView.setCertificate((SslCertificate) msg.obj);
break;
@@ -1073,4 +1086,25 @@
sendMessage(exceededQuota);
}
+ /**
+ * @hide pending API council approval
+ */
+ public boolean onJsTimeout() {
+ //always interrupt timedout JS by default
+ if (mWebChromeClient == null) {
+ return true;
+ }
+ JsResult result = new JsResult(this, true);
+ Message timeout = obtainMessage(JS_TIMEOUT, result);
+ synchronized (this) {
+ sendMessage(timeout);
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.e(LOGTAG, "Caught exception while waiting for jsUnload");
+ Log.e(LOGTAG, Log.getStackTraceString(e));
+ }
+ }
+ return result.getResult();
+ }
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index c0c6775..e8c2279 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -647,8 +647,6 @@
// another file in the local web server directory. Still
// "localhost" is the best pseudo domain name.
ret[0] = "localhost";
- } else if (!ret[0].equals("localhost")) {
- return null;
}
} else if (index == ret[0].lastIndexOf(PERIOD)) {
// cookie host must have at least two periods
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 0b874fa..bd64f89 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -174,4 +174,19 @@
// WebCore will interpret this that new quota was declined.
quotaUpdater.updateQuota(currentQuota);
}
+
+ /**
+ * Tell the client that a JavaScript execution timeout has occured. And the
+ * client may decide whether or not to interrupt the execution. If the
+ * client returns true, the JavaScript will be interrupted. If the client
+ * returns false, the execution will continue. Note that in the case of
+ * continuing execution, the timeout counter will be reset, and the callback
+ * will continue to occur if the script does not finish at the next check
+ * point.
+ * @return boolean Whether the JavaScript execution should be interrupted.
+ * @hide pending API Council approval
+ */
+ public boolean onJsTimeout() {
+ return true;
+ }
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 5a2cd26..883aa28 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -141,6 +141,7 @@
private boolean mBlockNetworkLoads;
private boolean mJavaScriptEnabled = false;
private boolean mPluginsEnabled = false;
+ private long mWebStorageDefaultQuota = 0;
private boolean mJavaScriptCanOpenWindowsAutomatically = false;
private boolean mUseDoubleTree = false;
private boolean mUseWideViewport = false;
@@ -903,6 +904,18 @@
}
/**
+ * @hide
+ * Set the default quota for WebStorage DBs
+ * @param quota the default quota in bytes
+ */
+ public synchronized void setWebStorageDefaultQuota(long quota) {
+ if (mWebStorageDefaultQuota != quota) {
+ mWebStorageDefaultQuota = quota;
+ postSync();
+ }
+ }
+
+ /**
* Set the path to where database storage API databases should be saved.
* This will update WebCore when the Sync runs in the C++ side.
* @param databasePath String path to the directory where databases should
@@ -996,6 +1009,15 @@
}
/**
+ * @hide
+ * Return the default quota for WebStorage DBs
+ * @return the default quota in bytes
+ */
+ public synchronized long getWebStorageDefaultQuota() {
+ return mWebStorageDefaultQuota;
+ }
+
+ /**
* Tell javascript to open windows automatically. This applies to the
* javascript function window.open().
* @param flag True if javascript can open windows automatically.
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index a0faf76..f27360d 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -16,6 +16,16 @@
package android.webkit;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
+import java.util.Vector;
+
/**
* Functionality for manipulating the webstorage databases.
*/
@@ -32,4 +42,242 @@
public interface QuotaUpdater {
public void updateQuota(long newQuota);
};
+
+ // Log tag
+ private static final String TAG = "webstorage";
+
+ // Global instance of a WebStorage
+ private static WebStorage sWebStorage;
+
+ // We keep a copy of the origins, quotas and usages
+ // that we protect via a lock and update in syncValues()
+ private static Lock mLock = new ReentrantLock();
+ private static Condition mCacheUpdated = mLock.newCondition();
+
+ // Message ids
+ static final int UPDATE = 0;
+ static final int SET_QUOTA_ORIGIN = 1;
+ static final int DELETE_ORIGIN = 2;
+ static final int DELETE_ALL = 3;
+
+ private Vector <String> mOrigins;
+ private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
+ private HashMap <String, Long> mUsages = new HashMap<String, Long>();
+
+ private Handler mHandler = null;
+
+ private class Origin {
+ String mOrigin = null;
+ long mQuota = 0;
+
+ public Origin(String origin, long quota) {
+ mOrigin = origin;
+ mQuota = quota;
+ }
+
+ public Origin(String origin) {
+ mOrigin = origin;
+ }
+
+ public String getOrigin() {
+ return mOrigin;
+ }
+
+ public long getQuota() {
+ return mQuota;
+ }
+ }
+
+ /**
+ * @hide
+ * Message handler
+ */
+ public void createHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SET_QUOTA_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeSetQuotaForOrigin(website.getOrigin(),
+ website.getQuota());
+ syncValues();
+ } break;
+
+ case DELETE_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeDeleteOrigin(website.getOrigin());
+ syncValues();
+ } break;
+
+ case DELETE_ALL:
+ nativeDeleteAllDatabases();
+ syncValues();
+ break;
+
+ case UPDATE:
+ syncValues();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * @hide
+ * Returns a list of origins having a database
+ */
+ public Vector getOrigins() {
+ Vector ret = null;
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ ret = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the use for a given origin
+ */
+ public long getUsageForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ Long usage = mUsages.get(origin);
+ if (usage != null) {
+ ret = usage.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the quota for a given origin
+ */
+ public long getQuotaForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ Long quota = mQuotas.get(origin);
+ if (quota != null) {
+ ret = quota.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Set the quota for a given origin
+ */
+ public void setQuotaForOrigin(String origin, long quota) {
+ if (origin != null) {
+ postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+ new Origin(origin, quota)));
+ }
+ }
+
+ /**
+ * @hide
+ * Delete a given origin
+ */
+ public void deleteOrigin(String origin) {
+ if (origin != null) {
+ postMessage(Message.obtain(null, DELETE_ORIGIN,
+ new Origin(origin)));
+ }
+ }
+
+ /**
+ * @hide
+ * Delete all databases
+ */
+ public void deleteAllDatabases() {
+ postMessage(Message.obtain(null, DELETE_ALL));
+ }
+
+ /**
+ * Utility function to send a message to our handler
+ */
+ private void postMessage(Message msg) {
+ if (mHandler != null) {
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
+ * @hide
+ * Get the global instance of WebStorage.
+ * @return A single instance of WebStorage.
+ */
+ public static WebStorage getInstance() {
+ if (sWebStorage == null) {
+ sWebStorage = new WebStorage();
+ }
+ return sWebStorage;
+ }
+
+ /**
+ * @hide
+ * Post a Sync request
+ */
+ public void update() {
+ postMessage(Message.obtain(null, UPDATE));
+ }
+
+ /**
+ * Run on the webcore thread
+ * sync the local cached values with the real ones
+ */
+ private void syncValues() {
+ mLock.lock();
+ Vector tmp = nativeGetOrigins();
+ mOrigins = new Vector<String>();
+ mQuotas.clear();
+ mUsages.clear();
+ for (int i = 0; i < tmp.size(); i++) {
+ String origin = (String) tmp.get(i);
+ mOrigins.add(origin);
+ mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
+ mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+ }
+ mCacheUpdated.signal();
+ mLock.unlock();
+ }
+
+ // Native functions
+ private static native Vector nativeGetOrigins();
+ private static native long nativeGetUsageForOrigin(String origin);
+ private static native long nativeGetQuotaForOrigin(String origin);
+ private static native void nativeSetQuotaForOrigin(String origin, long quota);
+ private static native void nativeDeleteOrigin(String origin);
+ private static native void nativeDeleteAllDatabases();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 935e928..5b67b74 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -21,6 +21,7 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
+import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -60,6 +61,7 @@
import android.webkit.TextDialog.AutoCompleteAdapter;
import android.webkit.WebViewCore.EventHub;
import android.widget.AbsoluteLayout;
+import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
@@ -4402,7 +4404,7 @@
View v = mTextEntry;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- nativeMotionUp(x, y, mNavSlop, true);
+ nativeMotionUp(x, y, mNavSlop);
}
}
@@ -4414,7 +4416,7 @@
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (nativeMotionUp(contentX, contentY, mNavSlop, true)) {
+ if (nativeMotionUp(contentX, contentY, mNavSlop)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
@@ -4933,7 +4935,10 @@
@Override
public boolean hasStableIds() {
- return true;
+ // AdapterView's onChanged method uses this to determine whether
+ // to restore the old state. Return false so that the old (out
+ // of date) state does not replace the new, valid state.
+ return false;
}
private Container item(int position) {
@@ -4997,6 +5002,51 @@
}
}
+ /*
+ * Whenever the data set changes due to filtering, this class ensures
+ * that the checked item remains checked.
+ */
+ private class SingleDataSetObserver extends DataSetObserver {
+ private long mCheckedId;
+ private ListView mListView;
+ private Adapter mAdapter;
+
+ /*
+ * Create a new observer.
+ * @param id The ID of the item to keep checked.
+ * @param l ListView for getting and clearing the checked states
+ * @param a Adapter for getting the IDs
+ */
+ public SingleDataSetObserver(long id, ListView l, Adapter a) {
+ mCheckedId = id;
+ mListView = l;
+ mAdapter = a;
+ }
+
+ public void onChanged() {
+ // The filter may have changed which item is checked. Find the
+ // item that the ListView thinks is checked.
+ int position = mListView.getCheckedItemPosition();
+ long id = mAdapter.getItemId(position);
+ if (mCheckedId != id) {
+ // Clear the ListView's idea of the checked item, since
+ // it is incorrect
+ mListView.clearChoices();
+ // Search for mCheckedId. If it is in the filtered list,
+ // mark it as checked
+ int count = mAdapter.getCount();
+ for (int i = 0; i < count; i++) {
+ if (mAdapter.getItemId(i) == mCheckedId) {
+ mListView.setItemChecked(i, true);
+ break;
+ }
+ }
+ }
+ }
+
+ public void onInvalidate() {}
+ }
+
public void run() {
final ListView listView = (ListView) LayoutInflater.from(mContext)
.inflate(com.android.internal.R.layout.select_dialog, null);
@@ -5030,8 +5080,7 @@
// filtered. Do not allow filtering on multiple lists until
// that bug is fixed.
- // Disable filter altogether
- // listView.setTextFilterEnabled(!mMultiple);
+ listView.setTextFilterEnabled(!mMultiple);
if (mMultiple) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
int length = mSelectedArray.length;
@@ -5051,6 +5100,9 @@
listView.setSelection(mSelection);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setItemChecked(mSelection, true);
+ DataSetObserver observer = new SingleDataSetObserver(
+ adapter.getItemId(mSelection), listView, adapter);
+ adapter.registerDataSetObserver(observer);
}
}
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@@ -5120,13 +5172,12 @@
// called by JNI
private void sendMotionUp(int touchGeneration, int buildGeneration,
- int frame, int node, int x, int y, int size, boolean isClick,
+ int frame, int node, int x, int y, int size,
boolean retry) {
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
touchUpData.mMoveGeneration = touchGeneration;
touchUpData.mBuildGeneration = buildGeneration;
touchUpData.mSize = size;
- touchUpData.mIsClick = isClick;
touchUpData.mRetry = retry;
mFocusData.mFrame = touchUpData.mFrame = frame;
mFocusData.mNode = touchUpData.mNode = node;
@@ -5263,7 +5314,7 @@
private native void nativeInstrumentReport();
private native void nativeMarkNodeInvalid(int node);
// return true if the page has been scrolled
- private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
+ private native boolean nativeMotionUp(int x, int y, int slop);
// returns false if it handled the key
private native boolean nativeMoveFocus(int keyCode, int count,
boolean noScroll);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b364952..1c83264 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -143,6 +143,8 @@
// The WebIconDatabase needs to be initialized within the UI thread so
// just request the instance here.
WebIconDatabase.getInstance();
+ // Create the WebStorage singleton
+ WebStorage.getInstance();
// Send a message to initialize the WebViewCore.
Message init = sWebCoreHandler.obtainMessage(
WebCoreThread.INITIALIZE, this);
@@ -162,6 +164,8 @@
mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
// Create the handler and transfer messages for the IconDatabase
WebIconDatabase.getInstance().createHandler();
+ // Create the handler for WebStorage
+ WebStorage.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -284,6 +288,16 @@
return mCallbackProxy.onJsBeforeUnload(url, message);
}
+ /**
+ *
+ * Callback to notify that a JavaScript execution timeout has occured.
+ * @return True if the JavaScript execution should be interrupted. False
+ * will continue the execution.
+ */
+ protected boolean jsInterrupt() {
+ return mCallbackProxy.onJsTimeout();
+ }
+
//-------------------------------------------------------------------------
// JNI methods
//-------------------------------------------------------------------------
@@ -370,7 +384,7 @@
private native void nativeTouchUp(int touchGeneration,
int buildGeneration, int framePtr, int nodePtr, int x, int y,
- int size, boolean isClick, boolean retry);
+ int size, boolean retry);
private native boolean nativeHandleTouchEvent(int action, int x, int y);
@@ -526,7 +540,6 @@
int mX;
int mY;
int mSize;
- boolean mIsClick;
boolean mRetry;
}
@@ -892,7 +905,7 @@
touchUpData.mBuildGeneration,
touchUpData.mFrame, touchUpData.mNode,
touchUpData.mX, touchUpData.mY,
- touchUpData.mSize, touchUpData.mIsClick,
+ touchUpData.mSize,
touchUpData.mRetry);
break;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 767c7e7..1ca59b2 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -433,7 +433,9 @@
private InputConnection mDefInputConnection;
private InputConnectionWrapper mPublicInputConnection;
-
+
+ private Runnable mClearScrollingCache;
+
/**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
@@ -2299,6 +2301,7 @@
}
if (more) {
+ invalidate();
mLastFlingY = y;
post(this);
} else {
@@ -2322,16 +2325,23 @@
}
private void clearScrollingCache() {
- if (mCachingStarted) {
- setChildrenDrawnWithCacheEnabled(false);
- if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
- setChildrenDrawingCacheEnabled(false);
- }
- if (!isAlwaysDrawnWithCacheEnabled()) {
- invalidate();
- }
- mCachingStarted = false;
+ if (mClearScrollingCache == null) {
+ mClearScrollingCache = new Runnable() {
+ public void run() {
+ if (mCachingStarted) {
+ mCachingStarted = false;
+ setChildrenDrawnWithCacheEnabled(false);
+ if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
+ setChildrenDrawingCacheEnabled(false);
+ }
+ if (!isAlwaysDrawnWithCacheEnabled()) {
+ invalidate();
+ }
+ }
+ }
+ };
}
+ post(mClearScrollingCache);
}
/**
@@ -2788,7 +2798,7 @@
int screenHeight = getResources().getDisplayMetrics().heightPixels;
final int[] xy = new int[2];
getLocationOnScreen(xy);
- // TODO: The 20 below should come from the theme and be expressed in dip
+ // TODO: The 20 below should come from the theme
// TODO: And the gravity should be defined in the theme as well
final int bottomGap = screenHeight - xy[1] - getHeight() + (int) (mDensityScale * 20);
if (!mPopup.isShowing()) {
@@ -3180,7 +3190,7 @@
// Reclaim views on screen
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
- AbsListView.LayoutParams lp = (AbsListView.LayoutParams)child.getLayoutParams();
+ AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
// Don't reclaim header or footer views, or views that should be ignored
if (lp != null && mRecycler.shouldRecycleViewType(lp.viewType)) {
views.add(child);
@@ -3195,6 +3205,63 @@
}
/**
+ * @hide
+ */
+ @Override
+ protected boolean onConsistencyCheck(int consistency) {
+ boolean result = super.onConsistencyCheck(consistency);
+
+ final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
+
+ if (checkLayout) {
+ // The active recycler must be empty
+ final View[] activeViews = mRecycler.mActiveViews;
+ int count = activeViews.length;
+ for (int i = 0; i < count; i++) {
+ if (activeViews[i] != null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
+ "AbsListView " + this + " has a view in its active recycler: " +
+ activeViews[i]);
+ }
+ }
+
+ // All views in the recycler must NOT be on screen and must NOT have a parent
+ final ArrayList<View> scrap = mRecycler.mCurrentScrap;
+ if (!checkScrap(scrap)) result = false;
+ final ArrayList<View>[] scraps = mRecycler.mScrapViews;
+ count = scraps.length;
+ for (int i = 0; i < count; i++) {
+ if (!checkScrap(scraps[i])) result = false;
+ }
+ }
+
+ return result;
+ }
+
+ private boolean checkScrap(ArrayList<View> scrap) {
+ if (scrap == null) return true;
+ boolean result = true;
+
+ final int count = scrap.size();
+ for (int i = 0; i < count; i++) {
+ final View view = scrap.get(i);
+ if (view.getParent() != null) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ " has a view in its scrap heap still attached to a parent: " + view);
+ }
+ if (indexOfChild(view) >= 0) {
+ result = false;
+ android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, "AbsListView " + this +
+ " has a view in its scrap heap that is also a direct child: " + view);
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Sets the recycler listener to be notified whenever a View is set aside in
* the recycler for later reuse. This listener can be used to free resources
* associated to the View.
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 8da7c6b..bfc5f08 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -126,6 +126,8 @@
// Indicates whether this AutoCompleteTextView is attached to a window or not
// The widget is attached to a window when mAttachCount > 0
private int mAttachCount;
+
+ private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
public AutoCompleteTextView(Context context) {
this(context, null);
@@ -186,6 +188,28 @@
setFocusable(true);
addTextChangedListener(new MyWatcher());
+
+ mPassThroughClickListener = new PassThroughClickListener();
+ super.setOnClickListener(mPassThroughClickListener);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener listener) {
+ mPassThroughClickListener.mWrapped = listener;
+ }
+
+ /**
+ * Private hook into the on click event, dispatched from {@link PassThroughClickListener}
+ */
+ private void onClickImpl() {
+ // if drop down should always visible, bring it back in front of the soft
+ // keyboard when the user touches the text field
+ if (mDropDownAlwaysVisible
+ && mPopup.isShowing()
+ && mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED) {
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+ showDropDown();
+ }
}
/**
@@ -1130,9 +1154,14 @@
}
}
- // Max height available on the screen for a popup
- final int maxHeight =
- mPopup.getMaxAvailableHeight(getDropDownAnchorView(), mDropDownVerticalOffset);
+ // Max height available on the screen for a popup. If this AutoCompleteTextView has
+ // the dropDownAlwaysVisible attribute, and the input method is not currently required,
+ // we then we ask for the height ignoring any bottom decorations like the input method.
+ // Otherwise we respect the input method.
+ boolean ignoreBottomDecorations = mDropDownAlwaysVisible &&
+ mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ final int maxHeight = mPopup.getMaxAvailableHeight(
+ getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
final int measuredHeight = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights;
@@ -1214,7 +1243,7 @@
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- mPopup.update();
+ showDropDown();
}
return false;
}
@@ -1353,4 +1382,21 @@
*/
CharSequence fixText(CharSequence invalidText);
}
+
+ /**
+ * Allows us a private hook into the on click event without preventing users from setting
+ * their own click listener.
+ */
+ private class PassThroughClickListener implements OnClickListener {
+
+ private View.OnClickListener mWrapped;
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ onClickImpl();
+
+ if (mWrapped != null) mWrapped.onClick(v);
+ }
+ }
+
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 66c162e..5472d68 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Parcel;
@@ -113,7 +114,11 @@
Drawable mDivider;
int mDividerHeight;
+
+ private boolean mIsCacheColorOpaque;
+ private boolean mDividerIsOpaque;
private boolean mClipDivider;
+
private boolean mHeaderDividersEnabled;
private boolean mFooterDividersEnabled;
@@ -2776,6 +2781,20 @@
return mItemsCanFocus;
}
+ /**
+ * @hide Pending API council approval.
+ */
+ @Override
+ public boolean isOpaque() {
+ return (mCachingStarted && mIsCacheColorOpaque && mDividerIsOpaque) || super.isOpaque();
+ }
+
+ @Override
+ public void setCacheColorHint(int color) {
+ mIsCacheColorOpaque = (color >>> 24) == 0xFF;
+ super.setCacheColorHint(color);
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
// Draw the dividers
@@ -2897,6 +2916,7 @@
mClipDivider = false;
}
mDivider = divider;
+ mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE;
requestLayoutIfNecessary();
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 2c9714e..78c7bd8 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -25,6 +25,7 @@
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.WindowManagerImpl;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.View.OnTouchListener;
import android.graphics.PixelFormat;
@@ -72,8 +73,8 @@
*/
public static final int INPUT_METHOD_NOT_NEEDED = 2;
- private final Context mContext;
- private final WindowManager mWindowManager;
+ private Context mContext;
+ private WindowManager mWindowManager;
private boolean mIsShowing;
private boolean mIsDropdown;
@@ -158,8 +159,7 @@
*/
public PopupWindow(Context context, AttributeSet attrs, int defStyle) {
mContext = context;
- mWindowManager = (WindowManager)context.getSystemService(
- Context.WINDOW_SERVICE);
+ mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
TypedArray a =
context.obtainStyledAttributes(
@@ -272,11 +272,11 @@
* @param height the popup's height
* @param focusable true if the popup can be focused, false otherwise
*/
- public PopupWindow(View contentView, int width, int height,
- boolean focusable) {
- mContext = contentView.getContext();
- mWindowManager = (WindowManager)mContext.getSystemService(
- Context.WINDOW_SERVICE);
+ public PopupWindow(View contentView, int width, int height, boolean focusable) {
+ if (contentView != null) {
+ mContext = contentView.getContext();
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ }
setContentView(contentView);
setWidth(width);
setHeight(height);
@@ -373,6 +373,14 @@
}
mContentView = contentView;
+
+ if (mContext == null) {
+ mContext = mContentView.getContext();
+ }
+
+ if (mWindowManager == null) {
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ }
}
/**
@@ -747,6 +755,11 @@
* @param p the layout parameters of the popup's content view
*/
private void preparePopup(WindowManager.LayoutParams p) {
+ if (mContentView == null || mContext == null || mWindowManager == null) {
+ throw new IllegalStateException("You must specify a valid content view by "
+ + "calling setContentView() before attempting to show the popup.");
+ }
+
if (mBackground != null) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
int height = ViewGroup.LayoutParams.FILL_PARENT;
@@ -948,14 +961,38 @@
* shown.
*/
public int getMaxAvailableHeight(View anchor, int yOffset) {
+ return getMaxAvailableHeight(anchor, yOffset, false);
+ }
+
+ /**
+ * Returns the maximum height that is available for the popup to be
+ * completely shown, optionally ignoring any bottom decorations such as
+ * the input method. It is recommended that this height be the maximum for
+ * the popup's height, otherwise it is possible that the popup will be
+ * clipped.
+ *
+ * @param anchor The view on which the popup window must be anchored.
+ * @param yOffset y offset from the view's bottom edge
+ * @param ignoreBottomDecorations if true, the height returned will be
+ * all the way to the bottom of the display, ignoring any
+ * bottom decorations
+ * @return The maximum available height for the popup to be completely
+ * shown.
+ *
+ * @hide Pending API council approval.
+ */
+ public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
final int[] anchorPos = mDrawingLocation;
anchor.getLocationOnScreen(anchorPos);
- final int distanceToBottom = displayFrame.bottom -
- (anchorPos[1] + anchor.getHeight()) - yOffset;
+ int bottomEdge = displayFrame.bottom;
+ if (ignoreBottomDecorations) {
+ bottomEdge = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
+ }
+ final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
// anchorPos[1] is distance from anchor to top of screen
@@ -1116,7 +1153,7 @@
p.flags = newFlags;
update = true;
}
-
+
if (update) {
mWindowManager.updateViewLayout(mPopupView, p);
}
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index c4f0abd..edbb3db 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -823,7 +823,7 @@
@ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf")
}, mapping = {
@ViewDebug.IntToString(from = TRUE, to = "true"),
- @ViewDebug.IntToString(from = 0, to = "NO_ID")
+ @ViewDebug.IntToString(from = 0, to = "FALSE/NO_ID")
})
private int[] mRules = new int[VERB_COUNT];
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c6b01876..adfc74f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4434,29 +4434,31 @@
boolean reportExtractedText() {
final InputMethodState ims = mInputMethodState;
- final boolean contentChanged = ims.mContentChanged;
- if (ims != null && (contentChanged || ims.mSelectionModeChanged)) {
- ims.mContentChanged = false;
- ims.mSelectionModeChanged = false;
- final ExtractedTextRequest req = mInputMethodState.mExtracting;
- if (req != null) {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start="
- + ims.mChangedStart + " end=" + ims.mChangedEnd
- + " delta=" + ims.mChangedDelta);
- if (ims.mChangedStart < 0 && !contentChanged) {
- ims.mChangedStart = EXTRACT_NOTHING;
- }
- if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
- ims.mChangedDelta, ims.mTmpExtracted)) {
- if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start="
- + ims.mTmpExtracted.partialStartOffset
- + " end=" + ims.mTmpExtracted.partialEndOffset
- + ": " + ims.mTmpExtracted.text);
- imm.updateExtractedText(this, req.token,
- mInputMethodState.mTmpExtracted);
- return true;
+ if (ims != null) {
+ final boolean contentChanged = ims.mContentChanged;
+ if (contentChanged || ims.mSelectionModeChanged) {
+ ims.mContentChanged = false;
+ ims.mSelectionModeChanged = false;
+ final ExtractedTextRequest req = mInputMethodState.mExtracting;
+ if (req != null) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start="
+ + ims.mChangedStart + " end=" + ims.mChangedEnd
+ + " delta=" + ims.mChangedDelta);
+ if (ims.mChangedStart < 0 && !contentChanged) {
+ ims.mChangedStart = EXTRACT_NOTHING;
+ }
+ if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
+ ims.mChangedDelta, ims.mTmpExtracted)) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start="
+ + ims.mTmpExtracted.partialStartOffset
+ + " end=" + ims.mTmpExtracted.partialEndOffset
+ + ": " + ims.mTmpExtracted.text);
+ imm.updateExtractedText(this, req.token,
+ mInputMethodState.mTmpExtracted);
+ return true;
+ }
}
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 9ce532c..e1ff2a5 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -45,6 +45,8 @@
void noteFullWifiLockReleased(int uid);
void noteScanWifiLockAcquired(int uid);
void noteScanWifiLockReleased(int uid);
+ void noteWifiMulticastEnabled(int uid);
+ void noteWifiMulticastDisabled(int uid);
void setOnBattery(boolean onBattery, int level);
void recordCurrentLevel(int level);
long getAwakeTimeBattery();
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
new file mode 100644
index 0000000..77d6e20
--- /dev/null
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2008 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.internal.app;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.ProgressDialog;
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.IBluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.Power;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import com.android.internal.telephony.ITelephony;
+import android.util.Log;
+import android.view.WindowManager;
+
+public final class ShutdownThread extends Thread {
+ // constants
+ private static final String TAG = "ShutdownThread";
+ private static final int MAX_NUM_PHONE_STATE_READS = 16;
+ private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
+ // maximum time we wait for the shutdown broadcast before going on.
+ private static final int MAX_BROADCAST_TIME = 10*1000;
+
+ // state tracking
+ private static Object sIsStartedGuard = new Object();
+ private static boolean sIsStarted = false;
+
+ // static instance of this thread
+ private static final ShutdownThread sInstance = new ShutdownThread();
+
+ private final Object mBroadcastDoneSync = new Object();
+ private boolean mBroadcastDone;
+ private Context mContext;
+ private Handler mHandler;
+
+ private ShutdownThread() {
+ }
+
+ /**
+ * Request a clean shutdown, waiting for subsystems to clean up their
+ * state etc. Must be called from a Looper thread in which its UI
+ * is shown.
+ *
+ * @param context Context used to display the shutdown progress dialog.
+ */
+ public static void shutdown(final Context context, boolean confirm) {
+ // ensure that only one thread is trying to power down.
+ // any additional calls are just returned
+ synchronized (sIsStartedGuard){
+ if (sIsStarted) {
+ Log.d(TAG, "Request to shutdown already running, returning.");
+ return;
+ }
+ }
+
+ Log.d(TAG, "Notifying thread to start radio shutdown");
+
+ if (confirm) {
+ final AlertDialog dialog = new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(com.android.internal.R.string.power_off)
+ .setMessage(com.android.internal.R.string.shutdown_confirm)
+ .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ beginShutdownSequence(context);
+ }
+ })
+ .setNegativeButton(com.android.internal.R.string.no, null)
+ .create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+ dialog.show();
+ } else {
+ beginShutdownSequence(context);
+ }
+ }
+
+ private static void beginShutdownSequence(Context context) {
+ synchronized (sIsStartedGuard) {
+ sIsStarted = true;
+ }
+
+ // throw up an indeterminate system dialog to indicate radio is
+ // shutting down.
+ ProgressDialog pd = new ProgressDialog(context);
+ pd.setTitle(context.getText(com.android.internal.R.string.power_off));
+ pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
+ pd.setIndeterminate(true);
+ pd.setCancelable(false);
+ pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+
+ pd.show();
+
+ // start the thread that initiates shutdown
+ sInstance.mContext = context;
+ sInstance.mHandler = new Handler() {
+ };
+ sInstance.start();
+ }
+
+ void broadcastDone() {
+ synchronized (mBroadcastDoneSync) {
+ mBroadcastDone = true;
+ mBroadcastDoneSync.notifyAll();
+ }
+ }
+
+ /**
+ * Makes sure we handle the shutdown gracefully.
+ * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
+ */
+ public void run() {
+ boolean bluetoothOff;
+ boolean radioOff;
+
+ BroadcastReceiver br = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+ // We don't allow apps to cancel this, so ignore the result.
+ broadcastDone();
+ }
+ };
+
+ Log.i(TAG, "Sending shutdown broadcast...");
+
+ // First send the high-level shut down broadcast.
+ mBroadcastDone = false;
+ mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
+ br, mHandler, 0, null, null);
+
+ final long endTime = System.currentTimeMillis() + MAX_BROADCAST_TIME;
+ synchronized (mBroadcastDoneSync) {
+ while (!mBroadcastDone) {
+ long delay = endTime - System.currentTimeMillis();
+ if (delay <= 0) {
+ Log.w(TAG, "Shutdown broadcast timed out");
+ break;
+ }
+ try {
+ mBroadcastDoneSync.wait(delay);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ Log.i(TAG, "Shutting down activity manager...");
+
+ final IActivityManager am =
+ ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
+ if (am != null) {
+ try {
+ am.shutdown(MAX_BROADCAST_TIME);
+ } catch (RemoteException e) {
+ }
+ }
+
+ final ITelephony phone =
+ ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+ final IBluetoothDevice bluetooth =
+ IBluetoothDevice.Stub.asInterface(ServiceManager.checkService(
+ Context.BLUETOOTH_SERVICE));
+
+ try {
+ bluetoothOff = bluetooth == null ||
+ bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ if (!bluetoothOff) {
+ Log.w(TAG, "Disabling Bluetooth...");
+ bluetooth.disable(false); // disable but don't persist new state
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
+ bluetoothOff = true;
+ }
+
+ try {
+ radioOff = phone == null || !phone.isRadioOn();
+ if (!radioOff) {
+ Log.w(TAG, "Turning off radio...");
+ phone.setRadio(false);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException during radio shutdown", ex);
+ radioOff = true;
+ }
+
+ Log.i(TAG, "Waiting for Bluetooth and Radio...");
+
+ // Wait a max of 32 seconds for clean shutdown
+ for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) {
+ if (!bluetoothOff) {
+ try {
+ bluetoothOff =
+ bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
+ bluetoothOff = true;
+ }
+ }
+ if (!radioOff) {
+ try {
+ radioOff = !phone.isRadioOn();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException during radio shutdown", ex);
+ radioOff = true;
+ }
+ }
+ if (radioOff && bluetoothOff) {
+ Log.i(TAG, "Radio and Bluetooth shutdown complete.");
+ break;
+ }
+ SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
+ }
+
+ //shutdown power
+ Log.i(TAG, "Performing low-level shutdown...");
+ Power.shutdown();
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1218fe3..e8356a2 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1115,7 +1115,21 @@
u.noteScanWifiLockReleasedLocked();
}
}
-
+
+ public void noteWifiMulticastEnabledLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteWifiMulticastEnabledLocked();
+ }
+ }
+
+ public void noteWifiMulticastDisabledLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteWifiMulticastDisabledLocked();
+ }
+ }
+
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@@ -1200,7 +1214,10 @@
boolean mScanWifiLockOut;
StopwatchTimer mScanWifiLockTimer;
-
+
+ boolean mWifiMulticastEnabled;
+ StopwatchTimer mWifiMulticastTimer;
+
Counter[] mUserActivityCounters;
/**
@@ -1228,6 +1245,8 @@
mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
+ mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
+ null, mUnpluggables);
}
@Override
@@ -1334,7 +1353,23 @@
mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
-
+
+ @Override
+ public void noteWifiMulticastEnabledLocked() {
+ if (!mWifiMulticastEnabled) {
+ mWifiMulticastEnabled = true;
+ mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ @Override
+ public void noteWifiMulticastDisabledLocked() {
+ if (mWifiMulticastEnabled) {
+ mWifiMulticastEnabled = false;
+ mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
@Override
public long getWifiTurnedOnTime(long batteryRealtime, int which) {
return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
@@ -1349,7 +1384,13 @@
public long getScanWifiLockTime(long batteryRealtime, int which) {
return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
}
-
+
+ @Override
+ public long getWifiMulticastTime(long batteryRealtime, int which) {
+ return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
+ which);
+ }
+
@Override
public void noteUserActivityLocked(int type) {
if (mUserActivityCounters == null) {
@@ -1423,6 +1464,7 @@
mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
+ mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
if (mUserActivityCounters == null) {
out.writeInt(0);
} else {
@@ -1482,6 +1524,9 @@
mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
mScanWifiLockOut = false;
mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
+ mWifiMulticastEnabled = false;
+ mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
+ null, mUnpluggables, in);
if (in.readInt() == 0) {
mUserActivityCounters = null;
} else {
@@ -2709,7 +2754,9 @@
u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
u.mScanWifiLockOut = false;
u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
-
+ u.mWifiMulticastEnabled = false;
+ u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
+
if (in.readInt() != 0) {
if (u.mUserActivityCounters == null) {
u.initUserActivityLocked();
@@ -2842,6 +2889,7 @@
u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
if (u.mUserActivityCounters == null) {
out.writeInt(0);
diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java
index 17f5c7c..1b974ce 100644
--- a/core/java/com/android/internal/util/BitwiseOutputStream.java
+++ b/core/java/com/android/internal/util/BitwiseOutputStream.java
@@ -17,7 +17,7 @@
package com.android.internal.util;
/**
- * An object that rovides bitwise incremental write access to a byte array.
+ * An object that provides bitwise incremental write access to a byte array.
*
* This is useful, for example, when writing a series of fields that
* may not be aligned on byte boundaries.
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index 6034a1e..b81c2b3 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -498,19 +498,23 @@
@Override
protected void onDraw(Canvas canvas) {
- if (mHorizontalDivider != null) {
+ Drawable drawable = mHorizontalDivider;
+ if (drawable != null) {
// If we have a horizontal divider to draw, draw it at the remembered positions
- for (int i = mHorizontalDividerRects.size() - 1; i >= 0; i--) {
- mHorizontalDivider.setBounds(mHorizontalDividerRects.get(i));
- mHorizontalDivider.draw(canvas);
+ final ArrayList<Rect> rects = mHorizontalDividerRects;
+ for (int i = rects.size() - 1; i >= 0; i--) {
+ drawable.setBounds(rects.get(i));
+ drawable.draw(canvas);
}
}
-
- if (mVerticalDivider != null) {
+
+ drawable = mVerticalDivider;
+ if (drawable != null) {
// If we have a vertical divider to draw, draw it at the remembered positions
- for (int i = mVerticalDividerRects.size() - 1; i >= 0; i--) {
- mVerticalDivider.setBounds(mVerticalDividerRects.get(i));
- mVerticalDivider.draw(canvas);
+ final ArrayList<Rect> rects = mVerticalDividerRects;
+ for (int i = rects.size() - 1; i >= 0; i--) {
+ drawable.setBounds(rects.get(i));
+ drawable.draw(canvas);
}
}
}
@@ -520,14 +524,12 @@
}
@Override
- public LayoutParams generateLayoutParams(AttributeSet attrs)
- {
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new IconMenuView.LayoutParams(getContext(), attrs);
}
@Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
- {
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
// Override to allow type-checking of LayoutParams.
return p instanceof IconMenuView.LayoutParams;
}
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 00d6cd9..1dc0314 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -102,6 +102,36 @@
rgn->translate(x, y);
}
+// Scale the rectangle by given scale and set the reuslt to the dst.
+static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
+ dst->fLeft = (int)::roundf(src.fLeft * scale);
+ dst->fTop = (int)::roundf(src.fTop * scale);
+ dst->fRight = (int)::roundf(src.fRight * scale);
+ dst->fBottom = (int)::roundf(src.fBottom * scale);
+}
+
+// Scale the region by given scale and set the reuslt to the dst.
+// dest and src can be the same region instance.
+static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
+ SkRegion tmp;
+ SkRegion::Iterator iter(src);
+
+ for (; !iter.done(); iter.next()) {
+ SkIRect r;
+ scale_rect(&r, iter.rect(), scale);
+ tmp.op(r, SkRegion::kUnion_Op);
+ }
+ dst->swap(tmp);
+}
+
+static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) {
+ SkRegion* rgn = GetSkRegion(env, region);
+ if (dst)
+ scale_rgn(GetSkRegion(env, dst), *rgn, scale);
+ else
+ scale_rgn(rgn, *rgn, scale);
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "Parcel.h"
@@ -139,6 +169,13 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, const SkRegion* r2)
+{
+ return (jboolean) (*r1 == *r2);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
struct RgnIterPair {
SkRegion fRgn; // a copy of the caller's region
SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn)
@@ -206,10 +243,12 @@
{ "quickContains", "(IIII)Z", (void*)Region_quickContains },
{ "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII },
{ "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
+ { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale },
{ "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
// parceling methods
{ "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel },
- { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel }
+ { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel },
+ { "nativeEquals", "(II)Z", (void*)Region_equals },
};
int register_android_graphics_Region(JNIEnv* env);
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e951431..21dde63 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -133,6 +133,14 @@
return SkTypeface::CreateFromStream(new AssetStream(asset, true));
}
+static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
+ NPE_CHECK_RETURN_ZERO(env, jpath);
+
+ AutoJavaStringToUTF8 str(env, jpath);
+
+ return SkTypeface::CreateFromFile(str.c_str());
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@@ -140,9 +148,10 @@
{ "nativeCreateFromTypeface", "(II)I", (void*)Typeface_createFromTypeface },
{ "nativeUnref", "(I)V", (void*)Typeface_unref },
{ "nativeGetStyle", "(I)I", (void*)Typeface_getStyle },
- { "nativeCreateFromAsset",
- "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
- (void*)Typeface_createFromAsset }
+ { "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
+ (void*)Typeface_createFromAsset },
+ { "nativeCreateFromFile", "(Ljava/lang/String;)I",
+ (void*)Typeface_createFromFile }
};
int register_android_graphics_Typeface(JNIEnv* env);
@@ -153,4 +162,3 @@
gTypefaceMethods,
SK_ARRAY_COUNT(gTypefaceMethods));
}
-
diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelper.cpp
index e8d60a0..c6de3a5 100644
--- a/core/jni/android_backup_FileBackupHelper.cpp
+++ b/core/jni/android_backup_FileBackupHelper.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "FileBackupHelper_native"
+#include <utils/Log.h>
+
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
@@ -22,29 +25,29 @@
namespace android
{
-static jfieldID s_descriptorField;
+static jfieldID s_descriptorField = 0;
static int
-performBackup_native(JNIEnv* env, jstring basePath,
- jobject oldSnapshot, jobject newSnapshot,
- jobject data, jobjectArray files)
+performBackup_native(JNIEnv* env, jobject clazz, jstring basePath, jobject oldState, jobject data,
+ jobject newState, jobjectArray files)
{
int err;
// all parameters have already been checked against null
-
- int oldSnapshotFD = env->GetIntField(oldSnapshot, s_descriptorField);
- int newSnapshotFD = env->GetIntField(newSnapshot, s_descriptorField);
+ LOGD("oldState=%p newState=%p data=%p\n", oldState, newState, data);
+ int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1;
+ int newStateFD = env->GetIntField(newState, s_descriptorField);
int dataFD = env->GetIntField(data, s_descriptorField);
char const* basePathUTF = env->GetStringUTFChars(basePath, NULL);
+ LOGD("basePathUTF=\"%s\"\n", basePathUTF);
const int fileCount = env->GetArrayLength(files);
char const** filesUTF = (char const**)malloc(sizeof(char*)*fileCount);
for (int i=0; i<fileCount; i++) {
filesUTF[i] = env->GetStringUTFChars((jstring)env->GetObjectArrayElement(files, i), NULL);
}
- err = back_up_files(oldSnapshotFD, newSnapshotFD, dataFD, basePathUTF, filesUTF, fileCount);
+ err = back_up_files(oldStateFD, dataFD, newStateFD, basePathUTF, filesUTF, fileCount);
for (int i=0; i<fileCount; i++) {
env->ReleaseStringUTFChars((jstring)env->GetObjectArrayElement(files, i), filesUTF[i]);
@@ -64,6 +67,8 @@
int register_android_backup_FileBackupHelper(JNIEnv* env)
{
+ LOGD("register_android_backup_FileBackupHelper");
+
jclass clazz;
clazz = env->FindClass("java/io/FileDescriptor");
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index 9c63fd2..004b0e3 100644
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -31,31 +31,31 @@
static jmethodID method_reportLocation;
static jmethodID method_reportStatus;
static jmethodID method_reportSvStatus;
-static jmethodID method_reportSuplStatus;
+static jmethodID method_reportAGpsStatus;
static jmethodID method_xtraDownloadRequest;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
-static const GpsSuplInterface* sGpsSuplInterface = NULL;
+static const AGpsInterface* sAGpsInterface = NULL;
// data written to by GPS callbacks
static GpsLocation sGpsLocation;
static GpsStatus sGpsStatus;
static GpsSvStatus sGpsSvStatus;
-static GpsSuplStatus sGpsSuplStatus;
+static AGpsStatus sAGpsStatus;
// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
// and android_location_GpsLocationProvider_read_status
static GpsLocation sGpsLocationCopy;
static GpsStatus sGpsStatusCopy;
static GpsSvStatus sGpsSvStatusCopy;
-static GpsSuplStatus sGpsSuplStatusCopy;
+static AGpsStatus sAGpsStatusCopy;
enum CallbackType {
kLocation = 1,
kStatus = 2,
kSvStatus = 4,
- kSuplStatus = 8,
+ kAGpsStatus = 8,
kXtraDownloadRequest = 16,
kDisableRequest = 32,
};
@@ -96,12 +96,12 @@
pthread_mutex_unlock(&sEventMutex);
}
-static void supl_status_callback(GpsSuplStatus* supl_status)
+static void agps_status_callback(AGpsStatus* agps_status)
{
pthread_mutex_lock(&sEventMutex);
- sPendingCallbacks |= kSuplStatus;
- memcpy(&sGpsSuplStatus, supl_status, sizeof(GpsSuplStatus));
+ sPendingCallbacks |= kAGpsStatus;
+ memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus));
pthread_cond_signal(&sEventCond);
pthread_mutex_unlock(&sEventMutex);
@@ -126,15 +126,15 @@
download_request_callback,
};
-GpsSuplCallbacks sGpsSuplCallbacks = {
- supl_status_callback,
+AGpsCallbacks sAGpsCallbacks = {
+ agps_status_callback,
};
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
- method_reportSuplStatus = env->GetMethodID(clazz, "reportSuplStatus", "(I)V");
+ method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
}
@@ -151,10 +151,10 @@
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return false;
- if (!sGpsSuplInterface)
- sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
- if (sGpsSuplInterface)
- sGpsSuplInterface->init(&sGpsSuplCallbacks);
+ if (!sAGpsInterface)
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ if (sAGpsInterface)
+ sAGpsInterface->init(&sAGpsCallbacks);
return true;
}
@@ -187,12 +187,6 @@
return (sGpsInterface->stop() == 0);
}
-static void android_location_GpsLocationProvider_set_fix_frequency(JNIEnv* env, jobject obj, jint fixFrequency)
-{
- if (sGpsInterface->set_fix_frequency)
- sGpsInterface->set_fix_frequency(fixFrequency);
-}
-
static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
{
sGpsInterface->delete_aiding_data(flags);
@@ -212,7 +206,7 @@
memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
- memcpy(&sGpsSuplStatusCopy, &sGpsSuplStatus, sizeof(sGpsSuplStatusCopy));
+ memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
pthread_mutex_unlock(&sEventMutex);
if (pendingCallbacks & kLocation) {
@@ -228,8 +222,8 @@
if (pendingCallbacks & kSvStatus) {
env->CallVoidMethod(obj, method_reportSvStatus);
}
- if (pendingCallbacks & kSuplStatus) {
- env->CallVoidMethod(obj, method_reportSuplStatus, sGpsSuplStatusCopy.status);
+ if (pendingCallbacks & kAGpsStatus) {
+ env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
}
if (pendingCallbacks & kXtraDownloadRequest) {
env->CallVoidMethod(obj, method_xtraDownloadRequest);
@@ -299,73 +293,72 @@
env->ReleaseByteArrayElements(data, bytes, 0);
}
-static void android_location_GpsLocationProvider_supl_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
+static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
{
- if (!sGpsSuplInterface) {
- sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ if (!sAGpsInterface) {
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
}
- if (sGpsSuplInterface) {
+ if (sAGpsInterface) {
if (apn == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
const char *apnStr = env->GetStringUTFChars(apn, NULL);
- sGpsSuplInterface->data_conn_open(apnStr);
+ sAGpsInterface->data_conn_open(apnStr);
env->ReleaseStringUTFChars(apn, apnStr);
}
}
-static void android_location_GpsLocationProvider_supl_data_conn_closed(JNIEnv* env, jobject obj)
+static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
{
- if (!sGpsSuplInterface) {
- sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ if (!sAGpsInterface) {
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
}
- if (sGpsSuplInterface) {
- sGpsSuplInterface->data_conn_closed();
+ if (sAGpsInterface) {
+ sAGpsInterface->data_conn_closed();
}
}
-static void android_location_GpsLocationProvider_supl_data_conn_failed(JNIEnv* env, jobject obj)
+static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
{
- if (!sGpsSuplInterface) {
- sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ if (!sAGpsInterface) {
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
}
- if (sGpsSuplInterface) {
- sGpsSuplInterface->data_conn_failed();
+ if (sAGpsInterface) {
+ sAGpsInterface->data_conn_failed();
}
}
-static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj,
- jint addr, jint port)
+static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
+ jint type, jint addr, jint port)
{
- if (!sGpsSuplInterface) {
- sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ if (!sAGpsInterface) {
+ sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
}
- if (sGpsSuplInterface) {
- sGpsSuplInterface->set_server(addr, port);
+ if (sAGpsInterface) {
+ sAGpsInterface->set_server(type, addr, port);
}
}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
- {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
- {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
- {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
- {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
- {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start},
- {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
- {"native_set_fix_frequency", "(I)V", (void*)android_location_GpsLocationProvider_set_fix_frequency},
- {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
- {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
- {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
- {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
- {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
- {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
- {"native_supl_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_supl_data_conn_open},
- {"native_supl_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_supl_data_conn_closed},
- {"native_supl_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_supl_data_conn_failed},
- {"native_set_supl_server", "(II)V", (void*)android_location_GpsLocationProvider_set_supl_server},
+ {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
+ {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
+ {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
+ {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
+ {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start},
+ {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
+ {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
+ {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
+ {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+ {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
+ {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
+ {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+ {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+ {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+ {"native_set_agps_server", "(III)V", (void*)android_location_GpsLocationProvider_set_agps_server},
};
int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index b8d6586..42ada54 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -335,7 +335,7 @@
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for start()");
}
-
+
lpTrack->start();
}
@@ -433,6 +433,45 @@
// ----------------------------------------------------------------------------
+jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,
+ jint offsetInBytes, jint sizeInBytes) {
+ // give the data to the native AudioTrack object (the data starts at the offset)
+ ssize_t written = 0;
+ // regular write() or copy the data to the AudioTrack's shared memory?
+ if (pTrack->sharedBuffer() == 0) {
+ written = pTrack->write(data + offsetInBytes, sizeInBytes);
+ } else {
+ if (audioFormat == javaAudioTrackFields.PCM16) {
+ // writing to shared memory, check for capacity
+ if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {
+ sizeInBytes = pTrack->sharedBuffer()->size();
+ }
+ memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
+ written = sizeInBytes;
+ } else if (audioFormat == javaAudioTrackFields.PCM8) {
+ // data contains 8bit data we need to expand to 16bit before copying
+ // to the shared memory
+ // writing to shared memory, check for capacity,
+ // note that input data will occupy 2X the input space due to 8 to 16bit conversion
+ if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) {
+ sizeInBytes = pTrack->sharedBuffer()->size() / 2;
+ }
+ int count = sizeInBytes;
+ int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer();
+ const int8_t *src = (const int8_t *)(data + offsetInBytes);
+ while(count--) {
+ *dst++ = (int16_t)(*src++^0x80) << 8;
+ }
+ // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
+ // the 8bit mixer restriction from the user of this function
+ written = sizeInBytes;
+ }
+ }
+ return written;
+
+}
+
+// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
jbyteArray javaAudioData,
jint offsetInBytes, jint sizeInBytes,
@@ -461,35 +500,13 @@
return 0;
}
- // give the data to the native AudioTrack object (the data starts at the offset)
- ssize_t written = 0;
- // regular write() or copy the data to the AudioTrack's shared memory?
- if (lpTrack->sharedBuffer() == 0) {
- written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes);
- } else {
- if (javaAudioFormat == javaAudioTrackFields.PCM16) {
- memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
- written = sizeInBytes;
- } else if (javaAudioFormat == javaAudioTrackFields.PCM8) {
- // cAudioData contains 8bit data we need to expand to 16bit before copying
- // to the shared memory
- int count = sizeInBytes;
- int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer();
- const int8_t *src = (const int8_t *)(cAudioData + offsetInBytes);
- while(count--) {
- *dst++ = (int16_t)(*src++^0x80) << 8;
- }
- // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
- // the 8bit mixer restriction from the user of this function
- written = sizeInBytes;
- }
- }
+ jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
//LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
// (int)written, (int)(sizeInBytes), (int)offsetInBytes);
- return (int)written;
+ return written;
}
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 7e388ef..482d8eb 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -24,6 +24,19 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+}
+
static int initialized = 0;
static jclass nioAccessClass;
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 6f2a438..11822e0 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -24,6 +24,19 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+}
+
static int initialized = 0;
static jclass nioAccessClass;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 02a6e92..05fbe64 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -803,6 +803,14 @@
android:description="@string/permdesc_runSetActivityWatcher"
android:protectionLevel="signature" />
+ <!-- Allows an application to watch and control how activities are
+ started globally in the system. Only for is in debugging
+ (usually the monkey command). -->
+ <permission android:name="android.permission.SHUTDOWN"
+ android:label="@string/permlab_shutdown"
+ android:description="@string/permdesc_shutdown"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to retrieve the current state of keys and
switches. This is only for use by the system.-->
<permission android:name="android.permission.READ_INPUT_STATE"
@@ -1029,7 +1037,7 @@
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR" >
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
diff --git a/core/res/res/drawable/btn_search_dialog_default.9.png b/core/res/res/drawable/btn_search_dialog_default.9.png
index ec39178..7275231 100644
--- a/core/res/res/drawable/btn_search_dialog_default.9.png
+++ b/core/res/res/drawable/btn_search_dialog_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_pressed.9.png b/core/res/res/drawable/btn_search_dialog_pressed.9.png
index 5f52fef..50a9209 100644
--- a/core/res/res/drawable/btn_search_dialog_pressed.9.png
+++ b/core/res/res/drawable/btn_search_dialog_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_selected.9.png b/core/res/res/drawable/btn_search_dialog_selected.9.png
index 9fc2fde..14b774a 100644
--- a/core/res/res/drawable/btn_search_dialog_selected.9.png
+++ b/core/res/res/drawable/btn_search_dialog_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_default.9.png b/core/res/res/drawable/btn_search_dialog_voice_default.9.png
index 2a3366c..febf222 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_default.9.png
+++ b/core/res/res/drawable/btn_search_dialog_voice_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
index 57d7a74..70a200b 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
+++ b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
index db3187e..6f2989f 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
+++ b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
new file mode 100644
index 0000000..30c9b2b
--- /dev/null
+++ b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
new file mode 100644
index 0000000..ce21acd
--- /dev/null
+++ b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background_apps.9.png b/core/res/res/drawable/search_dropdown_background_apps.9.png
new file mode 100644
index 0000000..56b697d
--- /dev/null
+++ b/core/res/res/drawable/search_dropdown_background_apps.9.png
Binary files differ
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54da326..7b48267 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -79,6 +79,13 @@
by applications. -->
<attr name="allowClearUserData" format="boolean" />
+ <!-- Option to indicate this application is only for testing purposes.
+ For example, it may expose functionality or data outside of itself
+ that would cause a security hole, but is useful for testing. This
+ kind of application can not be installed without the
+ INSTALL_ALLOW_TEST flag, which means only through adb install. -->
+ <attr name="testOnly" format="boolean" />
+
<!-- A unique name for the given item. This must use a Java-style naming
convention to ensure the name is unique, for example
"com.mycompany.MyName". -->
@@ -635,6 +642,7 @@
<!-- Name of activity to be launched for managing the application's space on the device. -->
<attr name="manageSpaceActivity" />
<attr name="allowClearUserData" />
+ <attr name="testOnly" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
@@ -753,9 +761,28 @@
{@link #AndroidManifest manifest} tag. -->
<declare-styleable name="AndroidManifestUsesSdk" parent="AndroidManifest">
<!-- This is the minimum SDK version number that the application
- requires. Currently there is only one SDK version, 1. If
- not supplied, the application will work on any SDK. -->
- <attr name="minSdkVersion" format="integer" />
+ requires. This number is an abstract integer, from the list
+ in {@link android.os.Build.VERSION_CODES} If
+ not supplied, the application will work on any SDK. This
+ may also be string (such as "Donut") if the application was built
+ against a development branch, in which case it will only work against
+ the development builds. -->
+ <attr name="minSdkVersion" format="integer|string" />
+ <!-- This is the SDK version number that the application is targeting.
+ It is able to run on older versions (down to minSdkVersion), but
+ was explicitly tested to work with the version specified here.
+ Specifying this version allows the platform to disable compatibility
+ code that are not required or enable newer features that are not
+ available to older applications. This may also be a string
+ (such as "Donut") if this is built against a development
+ branch, in which case minSdkVersion is also forced to be that
+ string. -->
+ <attr name="targetSdkVersion" format="integer|string" />
+ <!-- This is the maximum SDK version number that an application works
+ on. You can use this to ensure your application is filtered out
+ of later versions of the platform when you know you have
+ incompatibility with them. -->
+ <attr name="maxSdkVersion" format="integer" />
</declare-styleable>
<!-- The <code>uses-libraries</code> specifies a shared library that this
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9031157..3c1d931 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1087,7 +1087,7 @@
<public type="integer" name="config_longAnimTime" id="0x010e0002" />
<!-- ===============================================================
- Resources added in version 4 of the platform.
+ Resources added in Donut.
=============================================================== -->
<eat-comment />
@@ -1097,6 +1097,9 @@
<public type="attr" name="searchSuggestThreshold" id="0x0101026d" />
<public type="attr" name="includeInGlobalSearch" id="0x0101026e" />
<public type="attr" name="onClick" id="0x0101026f" />
+ <public type="attr" name="targetSdkVersion" id="0x01010270" />
+ <public type="attr" name="maxSdkVersion" id="0x01010271" />
+ <public type="attr" name="testOnly" id="0x01010274" />
<public type="anim" name="anticipate_interpolator" id="0x010a0007" />
<public type="anim" name="overshoot_interpolator" id="0x010a0008" />
@@ -1111,6 +1114,6 @@
=============================================================== -->
<eat-comment />
- <public type="attr" name="accountType" id="0x01010270" />
- <public type="attr" name="contentAuthority" id="0x01010271" />
+ <public type="attr" name="accountType" id="0x01010272" />
+ <public type="attr" name="contentAuthority" id="0x01010273" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1f20237..d016689 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -474,6 +474,12 @@
the system, and steal or corrupt any data on it.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_shutdown">partial shutdown</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_shutdown">Puts the activity manager into a shutdown
+ state. Does not perform a complete shutdown.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_runSetActivityWatcher">monitor and control all application launching</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_runSetActivityWatcher">Allows an application to
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a436f61..8160c9c 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -330,7 +330,7 @@
<item name="android:groupIndicator">@android:drawable/expander_group</item>
<item name="android:indicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
<item name="android:indicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
- <item name="android:childDivider">@android:drawable/divider_horizontal_dark</item>
+ <item name="android:childDivider">@android:drawable/divider_horizontal_dark_opaque</item>
</style>
<style name="Widget.ImageWell">
@@ -398,18 +398,18 @@
<style name="Widget.ListView" parent="Widget.AbsListView">
<item name="android:listSelector">@android:drawable/list_selector_background</item>
<item name="android:cacheColorHint">?android:attr/colorBackground</item>
- <item name="android:divider">@android:drawable/divider_horizontal_dark</item>
+ <item name="android:divider">@android:drawable/divider_horizontal_dark_opaque</item>
</style>
<style name="Widget.ListView.White" parent="Widget.AbsListView">
<item name="android:listSelector">@android:drawable/list_selector_background</item>
<item name="android:background">@android:color/white</item>
- <item name="android:divider">@android:drawable/divider_horizontal_bright</item>
+ <item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
</style>
<style name="Widget.ListView.DropDown">
<item name="android:cacheColorHint">@null</item>
- <item name="android:divider">@android:drawable/divider_horizontal_bright</item>
+ <item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
</style>
<style name="Widget.ListView.Menu">
diff --git a/docs/html/community/index.jd b/docs/html/community/index.jd
index ab1599a..91c54aa 100644
--- a/docs/html/community/index.jd
+++ b/docs/html/community/index.jd
@@ -74,6 +74,14 @@
</ul>
</li>
+<li><b>Android ndk</b> - A place for discussing the Android NDK and topics related to using native code in Android applications.
+<ul>
+<li>Subscribe using Google Groups: <a href="http://groups.google.com/group/android-ndk">android-ndk</a></li>
+<li>Subscribe via email: <a href="mailto:android-ndk-subscribe@googlegroups.com">android-ndk-subscribe@googlegroups.com</a><a href="mailto:android-platform-subscribe@googlegroups.com">
+ </a></li>
+</ul>
+</li>
+
<li><b>Android security discuss</b> - A place for open discussion on secure development, emerging security concerns, and best practices for and by android developers. Please don't disclose vulnerabilities directly on this list, you'd be putting all Android users at risk.
<ul>
<li>Subscribe using Google Groups: <a href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a></li>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 5367cb2..a044cea 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -95,7 +95,7 @@
</ul>
</li> -->
<!-- <li><a style="color:gray;">Localization</a></li> -->
- <li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html">AppWidgets</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html">App Widgets</a></li>
</ul>
</li>
@@ -146,7 +146,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/index.html">UI Guidelines</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/widget_design.html">Widget Design</a></li>
+ <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/widget_design.html">App Widget Design</a></li>
</ul>
</li>
<li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">Designing for Performance</a></li>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index f9db356..01a9648 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -1,4 +1,4 @@
-page.title=AppWidgets
+page.title=App Widgets
@jd:body
<div id="qv-wrapper">
@@ -6,131 +6,338 @@
<h2>Key classes</h2>
<ol>
<li>{@link android.appwidget.AppWidgetProvider}</li>
- <li>{@link android.appwidget.AppWidgetHost}</li>
+ <li>{@link android.appwidget.AppWidgetProviderInfo}</li>
+ <li>{@link android.appwidget.AppWidgetManager}</li>
</ol>
<h2>In this document</h2>
<ol>
- <li><a href="#Providers">AppWidget Providers</a>
+ <li><a href="#Basics">The Basics</a></li>
+ <li><a href="#Manifest">Declaring an App Widget in the Manifest</a></li>
+ <li><a href="#MetaData">Adding the AppWidgetProviderInfo Metadata</a></li>
+ <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li>
+ <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a>
<ol>
- <li><a href="#provider_manifest">Declaring a widget in the AndroidManifest</a></li>
- <li><a href="#provider_meta_data">Adding the AppWidgetProviderInfo meta-data</a></li>
- <li><a href="#provider_AppWidgetProvider">Using the AppWidgetProvider class</a></li>
- <li><a href="#provider_configuration">AppWidget Configuration UI</a></li>
- <li><a href="#provider_broadcasts">AppWidget Broadcast Intents</a></li>
+ <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast Intents</a></li>
</ol>
</li>
- <li><a href="#Hosts">AppWidget Hosts</a></li>
+ <li><a href="#Configuring">Creating an App Widget Configuration Activity</a>
+ <ol>
+ <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget from
+ the configuration Activity</a></li>
+ </ol>
+ </li>
</ol>
<h2>See also</h2>
<ol>
+ <li><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+ Guidelines</a></li>
<li><a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html">Introducing
- home screen widgets and the AppWidget framework »</a></li>
+ home screen widgets and the AppWidget framework »</a></li>
</ol>
</div>
</div>
-<p>AppWidgets are miniature application views that can be embedded in other applications
-(e.g., the Home). These views are called "widgets" and you can publish one with
-an "AppWidget provider." An application component that is able to hold other widgets is
-called an "AppWidget host."</p>
+
+<p>App Widgets are miniature application views that can be embedded in other applications
+(such as the Home screen) and receive periodic updates. These views are referred
+to as Widgets in the user interface,
+and you can publish one with an App Widget provider. An application component that is
+able to hold other App Widgets is called an App Widget host. The screenshot below shows
+the Music App Widget.</p>
+
+<img src="{@docRoot}images/appwidget.png" alt="" />
+
+<p>This document describes how to publish an App Widget using an App Widget provider.</p>
+<h2 id="Basics">The Basics</h2>
+
+<p>To create an App Widget, you need the following:</p>
+
+<dl>
+ <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt>
+ <dd>Describes the metadata for an App Widget, such as the App Widget's layout, update frequency,
+ and the AppWidgetProvider class. This should be defined in XML.</dd>
+ <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt>
+ <dd>Defines the basic methods that allow you to programmatically interface with the App Widget,
+ based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated,
+ enabled, disabled and deleted.</dd>
+ <dt>View layout</dt>
+ <dd>Defines the initial layout for the App Widget, defined in XML.</dd>
+</dl>
+
+<p>Additionally, you can implement an App Widget configuration Activity. This is an optional
+{@link android.app.Activity} that launches when the user adds your App Widget and allows him or her
+to modify App Widget settings at create-time.</p>
+
+<p>The following sections describe how to setup each of these components.</p>
-<h2 id="Providers">AppWidget Providers</h2>
-<p>Any application can publish widgets. All an application needs to do to publish a widget is
-to have a {@link android.content.BroadcastReceiver} that receives the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} intent,
-and provide some meta-data about the widget. Android provides the
-{@link android.appwidget.AppWidgetProvider} class, which extends BroadcastReceiver, as a convenience
-class to aid in handling the broadcasts.
+<h2 id="Manifest">Declaring an App Widget in the Manifest</h2>
+<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your application's
+<code>AndroidManifest.xml</code> file. For example:</p>
-<h3 id="provider_manifest">Declaring a widget in the AndroidManifest</h3>
+<pre>
+<receiver android:name="ExampleAppWidgetProvider" >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/example_appwidget_info" />
+</receiver>
+</pre>
-<p>First, declare the {@link android.content.BroadcastReceiver} in your application's
-<code>AndroidManifest.xml</code> file.
+<p>The <code><receiver></code> element requires the <code>android:name</code>
+attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used
+by the App Widget.</p>
-{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml AppWidgetProvider}
+<p>The <code><intent-filter></code> element must include an <code><action></code>
+element with the <code>android:name</code> attribute. This attribute specifies
+that the {@link android.appwidget.AppWidgetProvider} accepts the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE ACTION_APPWIDGET_UPDATE} broadcast.
+This is the only broadcast that you must explicitly declare. The {@link android.appwidget.AppWidgetManager}
+automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.</p>
-<p>
-The <code><receiver></code> element has the following attributes:
+<p>The <code><meta-data></code> element specifies the
+{@link android.appwidget.AppWidgetProviderInfo} resource and requires the
+following attributes:</p>
<ul>
- <li><code>android:name</code> - specifies the
- {@link android.content.BroadcastReceiver} or {@link android.appwidget.AppWidgetProvider}
- class.</li>
- <li><code>android:label</code> - specifies the string resource that
- will be shown by the widget picker as the label.</li>
- <li><code>android:icon</code> - specifies the drawable resource that
- will be shown by the widget picker as the icon.</li>
-</ul>
-
-<p>
-The <code><intent-filter></code> element tells the {@link android.content.pm.PackageManager}
-that this {@link android.content.BroadcastReceiver} receives the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
-The widget manager will send other broadcasts directly to your widget provider as required.
-It is only necessary to explicitly declare that you accept the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
-
-<p>
-The <code><meta-data></code> element tells the widget manager which xml resource to
-read to find the {@link android.appwidget.AppWidgetProviderInfo} for your widget provider. It has the following
-attributes:
-<ul>
- <li><code>android:name="android.appwidget.provider"</code> - identifies this meta-data
- as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
- <li><code>android:resource</code> - is the xml resource to use as that descriptor.</li>
+ <li><code>android:name</code> - Specifies the metadata name. Use <code>android.appwidget.provider</code>
+ to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
+ <li><code>android:resource</code> - Specifies the {@link android.appwidget.AppWidgetProviderInfo}
+ resource location.</li>
</ul>
-<h3 id="provider_meta_data">Adding the AppWidgetProviderInfo meta-data</h3>
+<h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2>
-<p>For a widget, the values in the {@link android.appwidget.AppWidgetProviderInfo} structure are supplied
-in an XML resource. In the example above, the xml resource is referenced with
-<code>android:resource="@xml/appwidget_info"</code>. That XML file would go in your application's
-directory at <code>res/xml/appwidget_info.xml</code>. Here is a simple example.
+<p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential
+qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource,
+how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time.
+Define the AppWidgetProviderInfo object in an XML resource using a single
+<code><appwidget-provider></code> element and save it in the project's <code>res/xml/</code>
+folder.</p>
-{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml AppWidgetProviderInfo}
+<p>For example:</p>
-<p>The attributes are as documented in the
-{@link android.appwidget.AppWidgetProviderInfo} class.
+<pre>
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="294dp" <!-- density-independent pixels -->
+ android:minHeight="72dp"
+ android:updatePeriodMillis="86400000" <!-- once per day -->
+ android:initialLayout="@layout/example_appwidget"
+ android:configure="com.example.android.ExampleAppWidgetConfigure" >
+</appwidget-provider>
+</pre>
+
+<p>Here's a summary of the <code><appwidget-provider></code> attributes:</p>
+<ul>
+ <li>The values for the <code>minWidth</code> and <code>minHeight</code> attributes specify the minimum
+ area required by the App Widget's layout.
+ <p>The default Home screen positions App Widgets in its window based on a grid of
+ cells that have a defined height and width. If the values for an App Widget's minimum width
+ or height don't match the dimensions of the cells,
+ then the App Widget dimensions round <em>up</em> to the nearest cell size.
+ (See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+ Guidelines</a> for more information on the Home screen cell sizes.)</p>
+ <p>Because the Home screen's layout orientation (and thus, the cell sizes) can change,
+ as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height
+ <em>and</em> width of a cell. However, you must subtract 2 from the final dimension to account
+ for any integer rounding errors that occur in the pixel count. To find your minimum width
+ and height in density-independent pixels (dp), use this formula:<br/>
+ <code>(number of cells * 74) - 2</code><br/>
+ Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.</p>
+ </li>
+ <li>The <code>updatePerdiodMillis</code> attribute defines how often the App Widget framework should
+ request an update from the {@link android.appwidget.AppWidgetProvider} by calling the
+ {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+ onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value
+ and we suggest updating as infrequently as possible—perhaps no more than once an hour to
+ conserve the battery. You might also allow the user to adjust the frequency in a
+ configuration—some people might want a stock ticker to update every 15 minutes, or maybe
+ only four times a day.</li>
+ <li>The <code>initialLayout</code> attribute points to the layout resource that defines the
+ App Widget layout.</li>
+ <li>The <code>configure</code> attribute defines the {@link android.app.Activity} to launch when
+ the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional
+ (read <a href="#Configuring">Creating an App Widget Configuration Activity</a> below).</li>
+</ul>
+
+<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more information on the
+attributes accepted by the <code><appwidget-provider></code> element.</p>
-<h3 id="provider_AppWidgetProvider">Using the AppWidgetProvider class</h3>
+<h2 id="CreatingLayout">Creating the App Widget Layout</h2>
-<p>The AppWidgetProvider class is the easiest way to handle the widget provider intent broadcasts.
-See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java</code>
-sample class in ApiDemos for an example.
+<p>You must define an initial layout for your App Widget in XML and save it in the project's
+<code>res/layout/</code> directory. You can design your App Widget using the View objects listed
+below, but before you begin designing your App Widget, please read and understand the
+<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+Guidelines</a>.</p>
-<p class="note">Keep in mind that since the the AppWidgetProvider is a BroadcastReceiver,
-your process is not guaranteed to keep running after the callback methods return. See
-<a href="../../../guide/topics/fundamentals.html#broadlife">Application Fundamentals >
-Broadcast Receiver Lifecycle</a> for more information.
+<p>Creating the App Widget layout is simple if you're
+familiar with <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in XML</a>.
+However, you must be aware that App Widget layouts are based on {@link android.widget.RemoteViews},
+which do not support every kind of layout or view widget.</p>
+
+<p>A RemoteViews object (and, consequently, an App Widget) can support the
+following layout classes:</p>
+
+<ul class="nolist">
+ <li>{@link android.widget.FrameLayout}</li>
+ <li>{@link android.widget.LinearLayout}</li>
+ <li>{@link android.widget.RelativeLayout}</li>
+</ul>
+
+<p>And the following widget classes:</p>
+<ul class="nolist">
+ <li>{@link android.widget.AnalogClock}</li>
+ <li>{@link android.widget.Button}</li>
+ <li>{@link android.widget.Chronometer}</li>
+ <li>{@link android.widget.ImageButton}</li>
+ <li>{@link android.widget.ImageView}</li>
+ <li>{@link android.widget.ProgressBar}</li>
+ <li>{@link android.widget.TextView}</li>
+</ul>
+
+<p>Descendants of these classes are not supported.</p>
+<h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2>
-<h3 id="provider_configuration">AppWidget Configuration UI</h3>
+<div class="sidebox-wrapper">
+ <div class="sidebox-inner">
+ <p>You must declare your AppWidgetProvider class implementation as a broadcast receiver
+ using the <code><receiver></code> element in the AndroidManifest (see
+ <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p>
+ </div>
+</div>
-<p>
-Widget hosts have the ability to start a configuration activity when a widget is instantiated.
-The activity should be declared as normal in AndroidManifest.xml, and it should be listed in
-the AppWidgetProviderInfo XML file in the <code>android:configure</code> attribute.
+<p>The {@link android.appwidget.AppWidgetProvider} class extends BroadcastReceiver as a convenience
+class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that
+are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled.
+When these broadcast events occur, the AppWidgetProvider receives the following method calls:</p>
-<p>The activity you specified will be launched with the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE} action. See the documentation for that
-action for more info.
+<dl>
+ <dt>{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])}</dt>
+ <dd>This is called to update the App Widget at intervals defined by the <code>updatePeriodMillis</code>
+ attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the
+ AppWidgetProviderInfo Metadata</a> above). This method is also called
+ when the user adds the App Widget, so it should perform the essential setup,
+ such as define event handlers for Views and start a temporary
+ {@link android.app.Service}, if necessary. However, if you have declared a configuration
+ Activity, <strong>this method is not called</strong> when the user adds the App Widget,
+ but is called for the subsequent updates. It is the responsibility of the
+ configuration Activity to perform the first update when configuration is done.
+ (See <a href="#Configuring">Creating an App Widget Configuration Activity</a> below.)</dd>
+ <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt>
+ <dd>This is called every time an App Widget is deleted from the App Widget host.</dd>
+ <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt>
+ <dd>This is called when an instance the App Widget is created for the first time. For example, if the user
+ adds two instances of your App Widget, this is only called the first time.
+ If you need to open a new database or perform other setup that only needs to occur once
+ for all App Widget instances, then this is a good place to do it.</dd>
+ <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt>
+ <dd>This is called when the last instance of your App Widget is deleted from the App Widget host.
+ This is where you should clean up any work done in
+ {@link android.appwidget.AppWidgetProvider#onEnabled(Context)},
+ such as delete a temporary database.</dd>
+ <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt>
+ <dd>This is called for every broadcast and before each of the above callback methods.
+ You normally don't need to implement this method because the default AppWidgetProvider
+ implementation filters all App Widget broadcasts and calls the above
+ methods as appropriate.</dd>
+</dl>
-<p>See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java</code>
-sample class in ApiDemos for an example.
+<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue in which the
+<code>onDeleted()</code> method will not be called when it should be. To work around this issue,
+you can implement {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
+onReceive()} as described in this
+<a href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">Group post</a>
+to receive the <code>onDeleted()</code> callback.
+</p>
+
+<p>The most important AppWidgetProvider callback is
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+onUpdated()} because it is called when each App Widget is added to a host (unless you use
+a configuration Activity). If your App Widget accepts any
+user interaction events, then you need to register the event handlers in this callback.
+If your App Widget doesn't create temporary
+files or databases, or perform other work that requires clean-up, then
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+onUpdated()} may be the only callback method you need to define. For example, if you want an App Widget
+with a button that launches an Activity when clicked, you could use the following
+implementation of AppWidgetProvider:</p>
+
+<pre>
+public class ExampleAppWidgetProvider extends AppWidgetProvider {
+
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ final int N = appWidgetIds.length;
+
+ // Perform this loop procedure for each App Widget that belongs to this provider
+ for (int i=0; i<N; i++) {
+ int appWidgetId = appWidgetIds[i];
+
+ // Create an Intent to launch ExampleActivity
+ Intent intent = new Intent(context, ExampleActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+
+ // Get the layout for the App Widget and attach an on-click listener to the button
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
+ views.setOnClickPendingIntent(R.id.button, pendingIntent);
+
+ // Tell the AppWidgetManager to perform an update on the current App Widget
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+ }
+}
+</pre>
+
+<p>This AppWidgetProvider defines only the
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+onUpdated()} method for the purpose
+of defining a {@link android.app.PendingIntent} that launches an {@link android.app.Activity}
+and attaching it to the App Widget's button
+with {@link android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}.
+Notice that it includes a loop that iterates through each entry in <code>appWidgetIds</code>, which
+is an array of IDs that identify each App Widget created by this provider.
+In this way, if the user creates more than one instance of the App Widget, then they are
+all updated simultaneously. However, only one <code>updatePeriodMillis</code> schedule will be
+managed for all instances of the App Widget. For example, if the update schedule is defined
+to be every two hours, and a second instance
+of the App Widget is added one hour after the first one, then they will both be updated
+on the period defined by the first one and the second update period will be ignored
+(they'll both be updated every two hours, not every hour).</p>
+
+<p class="note"><strong>Note:</strong> Because the AppWidgetProvider is a BroadcastReceiver,
+your process is not guaranteed to keep running after the callback methods return (see
+<a href="{@docRoot}guide/topics/fundamentals.html#broadlife">Application Fundamentals >
+Broadcast Receiver Lifecycle</a> for more information). If your App Widget setup process can take several
+seconds (perhaps while performing web requests) and you require that your process continues,
+consider starting a {@link android.app.Service}
+in the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+onUpdated()} method. From within the Service, you can perform your own updates to the App Widget
+without worrying about the AppWidgetProvider closing down due to an
+<a href="{@docRoot}guide/practices/design/responsiveness.html">Application Not Responding</a>
+(ANR) error. See the
+<a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/WordWidget.java">Wiktionary
+sample's AppWidgetProvider</a> for an example of an App Widget running a {@link android.app.Service}.</p>
+
+<p>Also see the <a
+href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html">
+ExampleAppWidgetProvider.java</a> sample class.</p>
-
-<h3 id="provider_broadcasts">AppWidget Broadcast Intents</h3>
+<h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3>
<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like
-to receive the widget broadcasts directly, you can. The four intents you need to care about are:
+to receive the App Widget broadcasts directly, you can implement your own
+{@link android.content.BroadcastReceiver} or override the
+{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback.
+The four Intents you need to care about are:</p>
<ul>
<li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li>
<li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li>
@@ -138,17 +345,119 @@
<li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li>
</ul>
-<p>By way of example, the implementation of
-{@link android.appwidget.AppWidgetProvider#onReceive} is quite simple:</p>
-
-{@sample frameworks/base/core/java/android/appwidget/AppWidgetProvider.java onReceive}
-<h2 id="Hosts">AppWidget Hosts</h2>
+<h2 id="Configuring">Creating an App Widget Configuration Activity</h2>
-<p>Widget hosts are the containers in which widgets can be placed. Most of the look and feel
-details are left up to the widget hosts. For example, the home screen has one way of viewing
-widgets, but the lock screen could also contain widgets, and it would have a different way of
-adding, removing and otherwise managing widgets.</p>
-<p>For more information on implementing your own widget host, see the
-{@link android.appwidget.AppWidgetHost AppWidgetHost} class.</p>
+<p>If you would like the user to configure settings when he or she adds a new App Widget,
+you can create an App Widget configuration Activity. This {@link android.app.Activity}
+will be automatically launched by the App Widget host and allows the user to configure
+available settings for the App Widget at create-time, such as the App Widget color, size,
+update period or other functionality settings.</p>
+
+<p>The configuration Activity should be declared as a normal Activity in the Android manifest file.
+However, it will be launched by the App Widget host with the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE ACTION_APPWIDGET_CONFIGURE} action,
+so the Activity needs to accept this Intent. For example:</p>
+
+<pre>
+<activity android:name=".ExampleAppWidgetConfigure">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
+ </intent-filter>
+</activity>
+</pre>
+
+<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the
+<code>android:configure</code> attribute (see <a href="#MetaData">Adding
+the AppWidgetProvierInfo Metadata</a> above). For example, the configuration Activity
+can be declared like this:</p>
+
+<pre>
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ ...
+ android:configure="com.example.android.ExampleAppWidgetConfigure"
+ ... >
+</appwidget-provider>
+</pre>
+
+<p>Notice that the Activity is declared with a fully-qualified namespace, because
+it will be referenced from outside your package scope.</p>
+
+<p>That's all you need to get started with a configuration Activity. Now all you need is the actual
+Activity. There are, however, two important things to remember when you implement the Activity:</p>
+<ul>
+ <li>The App Widget host calls the configuration Activity and the configuration Activity should always
+ return a result. The result should include the App Widget ID
+ passed by the Intent that launched the Activity (saved in the Intent extras as
+ {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li>
+ <li>The {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+ onUpdate()} method <strong>will not be called</strong> when the App Widget is created
+ (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity
+ is launched). It is the responsibility of the configuration Activity to request an update from the
+ AppWidgetManager when the App Widget is first created. However,
+ {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
+ onUpdate()} will be called for subsequent updates—it is only skipped the first time.</li>
+</ul>
+
+<p>See the code snippets in the following section for an example of how to return a result
+from the configuration and update the App Widget.</p>
+
+
+<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the configuration Activity</h3>
+
+<p>When an App Widget uses a configuration Activity, it is the responsibility of the Activity
+to update the App Widget when configuration is complete.
+You can do so by requesting an update directly from the
+{@link android.appwidget.AppWidgetManager}.</p>
+
+<p>Here's a summary of the procedure to properly update the App Widget and close
+the configuration Activity:</p>
+
+<ol>
+ <li>First, get the App Widget ID from the Intent that launched the Activity:
+<pre>
+Intent intent = getIntent();
+Bundle extras = intent.getExtras();
+if (extras != null) {
+ mAppWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+}
+</pre>
+ </li>
+ <li>Perform your App Widget configuration.</li>
+ <li>When the configuration is complete, get an instance of the AppWidgetManager by calling
+ {@link android.appwidget.AppWidgetManager#getInstance(Context)}:
+<pre>
+AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+</pre>
+ </li>
+ <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by calling
+ {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}:
+<pre>
+RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
+appWidgetManager.updateAppWidget(mAppWidgetId, views);
+</pre>
+ </li>
+ <li>Finally, create the return Intent, set it with the Activity result, and finish the Activity:</li>
+<pre>
+Intent resultValue = new Intent();
+resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+setResult(RESULT_OK, resultValue);
+finish();
+</pre>
+ </li>
+</ol>
+
+<p class="note"><strong>Tip:</strong> When your configuration Activity first opens, set
+the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before
+reaching the end, the App Widget host is notified that the configuration was cancelled and the
+App Widget will not be added.</p>
+
+<p>See the <a
+href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html">
+ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p>
+
+
+
diff --git a/docs/html/images/appwidget.png b/docs/html/images/appwidget.png
new file mode 100644
index 0000000..b72b80b
--- /dev/null
+++ b/docs/html/images/appwidget.png
Binary files differ
diff --git a/docs/html/sdk/ndk/1.5-r1/index.jd b/docs/html/sdk/ndk/1.5-r1/index.jd
new file mode 100644
index 0000000..3d3137c
--- /dev/null
+++ b/docs/html/sdk/ndk/1.5-r1/index.jd
@@ -0,0 +1,311 @@
+ndk=true
+ndk.version=1.5
+ndk.rel.id=1
+ndk.date=May 2009
+
+ndk.win_download=android-ndk-1.5_r1-windows.zip
+ndk.win_bytes=22450814
+ndk.win_checksum=7b7836f705ec7e66225794edda34000f
+
+ndk.mac_download=android-ndk-1.5_r1-darwin-x86.zip
+ndk.mac_bytes=17165450
+ndk.mac_checksum=214ccfd704c0307609fbabeb7bf86acc
+
+ndk.linux_download=android-ndk-1.5_r1-linux-x86.zip
+ndk.linux_bytes=15976032
+ndk.linux_checksum=808fd4d6a7e45f76d546ba04ab9ef060
+
+ndk.linux_64_download=android-ndk-1.5_r1-linux-x86_64.zip
+ndk.linux_64_bytes=18112300
+ndk.linux_64_checksum=f8664c187b3ae077bcfe2b44294d0758
+
+page.title=Android 1.5 NDK, Release 1
+@jd:body
+
+<h2>What is the NDK?</h2>
+
+<p>The Android 1.5 NDK provides tools that allow Android application developers
+to embed and deploy native code within their Android applications. It
+provides:</p>
+
+<ul>
+<li>A set of tools and build files used to generate native code libraries from C
+and C++ sources</li>
+<li>A way to embed the corresponding native libraries into application package
+files (.apks) that can be deployed on Android devices</li>
+<li>A set of native system headers and libraries that will be supported in all
+future versions of the Android platform, starting from Android 1.5 </li>
+</ul>
+
+<p>This release of the NDK release supports the ARMv5TE machine instruction set
+and provides stable headers for libc (the C library), libm (the Math library)
+and the JNI interface.</p>
+
+<p>Using the NDK may not be relevant for all Android applications. As a
+developer, you will need to balance its benefits (faster execution) and its
+drawbacks (no portability, JNI overhead, no access to system libraries, and
+difficult debugging). Typical good candidates for the NDK are CPU-intensive
+operations that don't allocate too much memory, such as signal processing,
+physics simulation, custom bytecode/instruction interpreters, and so on.</p>
+
+<p>Please note that the NDK <em>does not</em> enable you to develop native-only
+applications. Android's primary runtime remains the Dalvik virtual machine.</p>
+
+<h2 id="contents">Contents of the NDK</h2>
+
+<h4>Development tools</h4>
+
+<p>The NDK includes a set of cross-toolchains (compilers, linkers, etc..) that
+can generate native ARM binaries on Linux, OS X, and Windows (with Cygwin)
+platforms.</p>
+
+<p>It provides a set of system headers for stable native APIs that are
+guaranteed to be supported in all later releases of the platform:</p>
+
+<ul>
+<li>libc (C library) headers</li>
+<li>libm (Math library) headers</li>
+<li>JNI interface headers</li>
+</ul>
+
+<p>The NDK also provides a build system that lets you work efficiently with your
+sources, without having to handle the toolchain/platform/CPU/ABI details. You
+create very short build files to describe which sources to compile and which
+Android application will use them — the build system compiles the sources
+and places the shared libraries directly in your application project. </p>
+
+<p class="caution"><strong>Important:</strong> With the exception of the
+libraries listed above, native system libraries in the Android 1.5 platform are
+<em>not</em> stable and may change in future platform versions.
+Your applications should <em>only</em> make use of the stable native system
+libraries provided in this NDK. </p>
+
+<h4>Documentation</h4>
+
+<p>The NDK package includes a set of documentation that describes the
+capabilities of the NDK and how to use it to create shared libraries for your
+Android applications. In this release, the documentation is provided only in the
+downloadable NDK package. You can find the documentation in the
+<code><ndk>/docs/</code> directory. Included are these files:</p>
+
+<ul>
+<li>INSTALL.TXT — describes how to install the NDK and configure it for
+your host system</li>
+<li>OVERVIEW.TXT — provides an overview of the NDK capabilities and
+usage</li>
+<li>ANDROID-MK.TXT — describes the use of the Android.mk file, which
+defines the native sources you want to compile</li>
+<li>APPLICATION-MK.TXT — describes the use of the Application.mk file,
+which describes the native sources required by your Android application</li>
+</ul>
+
+<h4>Sample applications</h4>
+
+<p>The NDK includes two sample Android applications that illustrate how to use
+native code in your Android applications:</p>
+
+<ul>
+<li><code>hello-jni</code> — A simple application that loads a string from
+a native method implemented in a shared library and then displays it in the
+application UI. </li>
+<li><code>two-libs</code> — A simple application that loads a shared
+library dynamically and calls a native method provided by the library. In this
+case, the method is implemented in a static library that is imported by the
+shared library. </li>
+</ul>
+
+<p>For more information, see <a href="#samples">Using the Sample
+Applications</a>.</p>
+
+<h2 id="requirements">System and Software Requirements</h2>
+
+<p>The sections below describe the system and software requirements for using
+the Android NDK, as well as platform compatibility considerations that affect
+appplications using libraries produced with the NDK. </p>
+
+<h4>The Android SDK</h4>
+<ul>
+ <li>A complete Android SDK installation (including all dependencies) is
+required.</li>
+ <li>Android 1.5 SDK or later version is required.</li>
+</ul>
+
+<h4>Supported operating systems</h4>
+<ul>
+ <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
+ <li>Mac OS X 10.4.8 or later (x86 only)</li>
+ <li>Linux (32- or 64-bit, tested on Linux Ubuntu Dapper Drake)</li>
+</ul>
+
+<h4>Required development tools</h4>
+<ul>
+ <li>For all development platforms, GNU Make 3.81 or later is required. Earlier
+versions of GNU Make might work but have not been tested.</li>
+ <li>For Windows, a recent release of <a
+href="http://www.cygwin.com">Cygwin</a> is required.</li>
+</ul>
+
+<h4>Android platform compatibility</h4>
+<ul>
+ <li>The native libraries created by the Android NDK can only be used on
+devices running the Android 1.5 platform version or later. This is due to subtle
+toolchain and ABI related changes that make the native libraries incompatible
+with 1.0 and 1.1 system images.</li>
+ <li>For this reason, you should use native libraries produced with the NDK in
+applications that are deployable to devices running the Android 1.5 platform
+version or later. To ensure compatibility, an application using a native library
+produced with the NDK must declare a <code><uses-library></code> element
+in its manifest file, with the attribute
+<code>android:minSdkVersion="3"</code>.</li>
+</ul>
+
+<h2 id="installing">Installing the NDK</h2>
+
+<p>Installing the NDK on your development computer is straightforward and
+involves extracting the NDK from its download package and running a host-setup
+script. </p>
+
+<p>Before you get started make sure that you have downloaded the latest <a
+href="{@docRoot}sdk/index.html">Android SDK</a> and upgraded your applications
+and environment as needed. The NDK will not work with older versions of the
+Android SDK. Also, take a moment to review the <a href="#requirements">System
+and Software Requirements</a> for the NDK, if you haven't already. </p>
+
+<p>To install the NDK, follow these steps:</p>
+
+<ol>
+<li>From the table at the top of this page, select the NDK package that is
+appropriate for your development computer and download the package.</li>
+<li>Uncompress the NDK download package using tools available on your computer.
+When uncompressed, the NDK files are contained in a directory called
+<code>android-ndk-<version></code>. You can rename the NDK directory if
+necessary and you can move it to any location on your computer. This
+documentation refers to the NDK directory as <code><ndk></code>. </li>
+<li>Open a terminal, change to the NDK directory, and run the host-setup script.
+The script sets up your environment and generates a host configuration file used
+later, when building your shared libraries. The path to the host-setup script
+is:
+
+<p><code><ndk>/build/host-setup.sh</code></p>
+
+<p>If the script completes successfully, it prints a "Host setup complete."
+message. If it fails, it prints instructions that you can follow to correct any
+problems. </p>
+</li>
+</ol>
+
+<p>Once you have run the host-setup script, you are ready start working with the
+NDK. </p>
+
+<h2 id="gettingstarted">Getting Started with the NDK</h2>
+
+<p>Once you've installed the NDK successfully, take a few minutes to read the
+documentation included in the NDK. You can find the documentation in the
+<code><ndk>/docs/</code> directory. In particular, please read the
+OVERVIEW.TXT document completely, so that you understand the intent of the NDK
+and how to use it.</p>
+
+<p>Here's the general outline of how you work with the NDK tools:</p>
+
+<ol>
+<li>Place your native sources under
+<code><ndk>/sources/<my_src>/...</code>. If you want, you can place
+a symlink to your sources, rather than the sources themselves. The sources you
+reference here are not strictly associated with a specific shared library or
+Android application. Instead, they are accessible to any build configuration and
+can be used to produce any number of shared libraries that can be used by any
+Android application.</li>
+<li>Create <code><ndk>/sources/<my_src>/Android.mk</code> to
+describe your native sources to the NDK build system</li>
+<li>Create <code><ndk>/apps/<my_app>/Application.mk</code> to
+describe your Android application and native sources it needs to the NDK build
+system. This file sets up the link between an Android SDK application project
+and any number of shared libraries defined in the
+<code><ndk>/sources/</code> folder and it specifies the path to the
+application project that will receive the shared library built from the
+sources.</li>
+<li>Build your native code by running this make command from the top-level NDK
+directory:
+
+<p><code>$ make APP=<my_app></code></p>
+
+<p>The build tools copy the stripped, shared libraries needed by your
+application to the proper location in the application's project directory.</p>
+</li>
+
+<li>Finally, compile your application using the SDK tools in the usual way. The
+SDK build tools will package the shared libraries in the application's
+deployable .apk file. </p></li>
+
+</ol>
+
+<p>For complete information on all of the steps listed above, please see the
+documentation included with the NDK package. </p>
+
+
+<h2 id="samples">Using the Sample Applications</h2>
+
+<p>The NDK includes two sample applications that illustrate how to use native
+code in your Android applications:</p>
+
+<ul>
+<li><code>hello-jni</code> — A simple application that loads a string from
+a native method implemented in a shared library and then displays it in the
+application UI. </li>
+<li><code>two-libs</code> — A simple application that loads a shared
+library dynamically and calls a native method provided by the library. In this
+case, the method is implemented in a static library imported by the shared
+library. </li>
+</ul>
+
+<p>For each sample, the NDK includes an Android application project, as well as
+the corresponding C source code and the necessary Android.mk and Application.mk
+files. The application projects are provided in
+<code><ndk>/apps/<app_name>/project/</code> and the C source for
+each application is provided in
+<code><ndk>/sources/samples/<library>/</code>.</p>
+
+<p>Once you have installed the NDK, you can build the shared libraries from the
+NDK by using these commands from the root of the NDK directory:</p>
+<ul>
+<li><code>$ make APP=hello-jni</code> — compiles
+<code><ndk>/sources/samples/hello-jni/hello-jni.c</code> and outputs a
+shared library to
+<code><ndk>/apps/hello-jni/project/libs/armeabi/libhello-jni.so</code>.
+</li>
+<li><code>$ make APP=two-libs</code> — compiles
+<code><ndk>/sources/samples/two-libs/second.c</code> and
+<code>first.c</code> and outputs a shared library to
+<code><ndk>/apps/two-libs/project/libs/armeabi/libtwolib-second.so</code>.
+</li>
+</ul>
+
+<p>Next, build the sample Android applications that use the shared
+libraries:</p>
+
+<ul>
+<li>If you are developing in Eclipse with ADT, use the New Project Wizard to
+create a new Android project for each sample, using the "Import from Existing
+Source" option and importing the source from
+<code><ndk>/apps/<app_name>/project/</code>. Then, set up an AVD, if
+necessary, and build/run the application in the emulator. For more information
+about creating a new Android project in Eclipse, see <a
+href="{@docRoot}guide/developing/eclipse-adt.html">Developing in
+Eclipse</a>.</li>
+<li>If you are developing with Ant, use the <code>android</code> tool to create
+the build file for each of the sample projects at
+<code><ndk>/apps/<app_name>/project/</code>. Then set up an AVD, if
+necessary, build your project in the usual way, and run it in the emulator.
+For more information, see <a
+href="{@docRoot}guide/developing/other-ide.html">Developing in Other
+IDEs</a>.</li>
+</ul>
+
+<h2>Discussion Forum and Mailing List</h2>
+
+<p>If you have questions about the NDK or would like to read or contribute to
+discussions about it, please visit the <a
+href="http://groups.google.com/group/android-ndk">android-ndk</a> group and
+mailing list.</p>
+
+
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 1e5122f..4b55b56 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -27,6 +27,12 @@
</ul>
</li>
<li>
+ <h2>Native Development Tools</h2>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/ndk/1.5-r1/index.html">Android 1.5 NDK, r1</a></li>
+ </ul>
+ </li>
+ <li>
<h2>Previous SDK Releases</h2>
<ul>
<li><a href="<?cs var:toroot ?>sdk/1.1_r1/index.html">Android 1.1 SDK, r1</a></li>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 0b398bc..fda584d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -400,7 +400,7 @@
* @param y The y coordinate of the first pixel in source
* @param width The number of pixels in each row
* @param height The number of rows
- * @param m Option matrix to be applied to the pixels
+ * @param m Optional matrix to be applied to the pixels
* @param filter true if the source should be filtered.
* Only applies if the matrix contains more than just
* translation.
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 81980d9..862e827 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1084,8 +1084,9 @@
* not null, return in it the actual width measured.
*
* @param text The text to measure
- * @param measureForwards If true, measure forwards, starting at index.
- * Otherwise, measure backwards, starting with the
+ * @param measureForwards If true, measure forwards, starting with the
+ * first character in the string. Otherwise,
+ * measure backwards, starting with the
* last character in the string.
* @param maxWidth The maximum width to accumulate.
* @param measuredWidth Optional. If not null, returns the actual width
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index 544ff4f..2b080aa 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -211,6 +211,26 @@
*/
public native void translate(int dx, int dy, Region dst);
+ /**
+ * Scale the region by the given scale amount. This re-constructs new region by
+ * scaling the rects that this region consists of. New rectis are computed by scaling
+ * coordinates by float, then rounded by roundf() function to integers. This may results
+ * in less internal rects if 0 < scale < 1. Zero and Negative scale result in
+ * an empty region. If this region is empty, do nothing.
+ *
+ * @hide
+ */
+ public void scale(float scale) {
+ scale(scale, null);
+ }
+
+ /**
+ * Set the dst region to the result of scaling this region by the given scale amount.
+ * If this region is empty, then dst will be set to empty.
+ * @hide
+ */
+ public native void scale(float scale, Region dst);
+
public final boolean union(Rect r) {
return op(r, Op.UNION);
}
@@ -294,7 +314,16 @@
throw new RuntimeException();
}
}
-
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof Region)) {
+ return false;
+ }
+ Region peer = (Region) obj;
+ return nativeEquals(mNativeRegion, peer.mNativeRegion);
+ }
+
protected void finalize() throws Throwable {
nativeDestructor(mNativeRegion);
}
@@ -340,5 +369,7 @@
private static native boolean nativeWriteToParcel(int native_region,
Parcel p);
+ private static native boolean nativeEquals(int native_r1, int native_r2);
+
private final int mNativeRegion;
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c69c92c..e40e84a 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -18,6 +18,8 @@
import android.content.res.AssetManager;
+import java.io.File;
+
/**
* The Typeface class specifies the typeface and intrinsic style of a font.
* This is used in the paint, along with optionally Paint settings like
@@ -118,7 +120,27 @@
public static Typeface createFromAsset(AssetManager mgr, String path) {
return new Typeface(nativeCreateFromAsset(mgr, path));
}
-
+
+ /**
+ * Create a new typeface from the specified font file.
+ *
+ * @param path The path to the font data.
+ * @return The new typeface.
+ */
+ public static Typeface createFromFile(File path) {
+ return new Typeface(nativeCreateFromFile(path.getAbsolutePath()));
+ }
+
+ /**
+ * Create a new typeface from the specified font file.
+ *
+ * @param path The full path to the font data.
+ * @return The new typeface.
+ */
+ public static Typeface createFromFile(String path) {
+ return new Typeface(nativeCreateFromFile(path));
+ }
+
// don't allow clients to call this directly
private Typeface(int ni) {
native_instance = ni;
@@ -140,14 +162,14 @@
}
protected void finalize() throws Throwable {
+ super.finalize();
nativeUnref(native_instance);
}
private static native int nativeCreate(String familyName, int style);
- private static native int nativeCreateFromTypeface(int native_instance,
- int style);
+ private static native int nativeCreateFromTypeface(int native_instance, int style);
private static native void nativeUnref(int native_instance);
private static native int nativeGetStyle(int native_instance);
- private static native int nativeCreateFromAsset(AssetManager mgr,
- String path);
+ private static native int nativeCreateFromAsset(AssetManager mgr, String path);
+ private static native int nativeCreateFromFile(String path);
}
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 29f2a00..f8b88d0 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -181,7 +181,8 @@
@Override
public int getOpacity() {
- return mDrawableContainerState.getOpacity();
+ return mCurrDrawable == null || !mCurrDrawable.isVisible() ? PixelFormat.TRANSPARENT :
+ mDrawableContainerState.getOpacity();
}
public boolean selectDrawable(int idx)
@@ -336,13 +337,11 @@
return pos;
}
- public final int getChildCount()
- {
+ public final int getChildCount() {
return mNumChildren;
}
- public final Drawable[] getChildren()
- {
+ public final Drawable[] getChildren() {
return mDrawables;
}
@@ -350,13 +349,11 @@
* all frames in the set (false), or to use the padding value of the frame
* being shown (true). Default value is false.
*/
- public final void setVariablePadding(boolean variable)
- {
+ public final void setVariablePadding(boolean variable) {
mVariablePadding = variable;
}
- public final Rect getConstantPadding()
- {
+ public final Rect getConstantPadding() {
if (mVariablePadding) {
return null;
}
@@ -364,11 +361,12 @@
return mConstantPadding;
}
- Rect r = new Rect(0, 0, 0, 0);
- Rect t = new Rect();
+ final Rect r = new Rect(0, 0, 0, 0);
+ final Rect t = new Rect();
final int N = getChildCount();
- for (int i=0; i<N; i++) {
- if (mDrawables[i].getPadding(t)) {
+ final Drawable[] drawables = mDrawables;
+ for (int i = 0; i < N; i++) {
+ if (drawables[i].getPadding(t)) {
if (t.left > r.left) r.left = t.left;
if (t.top > r.top) r.top = t.top;
if (t.right > r.right) r.right = t.right;
@@ -378,18 +376,15 @@
return (mConstantPadding=r);
}
- public final void setConstantSize(boolean constant)
- {
+ public final void setConstantSize(boolean constant) {
mConstantSize = constant;
}
- public final boolean isConstantSize()
- {
+ public final boolean isConstantSize() {
return mConstantSize;
}
- public final int getConstantWidth()
- {
+ public final int getConstantWidth() {
if (!mComputedConstantSize) {
computeConstantSize();
}
@@ -397,8 +392,7 @@
return mConstantWidth;
}
- public final int getConstantHeight()
- {
+ public final int getConstantHeight() {
if (!mComputedConstantSize) {
computeConstantSize();
}
@@ -406,8 +400,7 @@
return mConstantHeight;
}
- public final int getConstantMinimumWidth()
- {
+ public final int getConstantMinimumWidth() {
if (!mComputedConstantSize) {
computeConstantSize();
}
@@ -415,8 +408,7 @@
return mConstantMinimumWidth;
}
- public final int getConstantMinimumHeight()
- {
+ public final int getConstantMinimumHeight() {
if (!mComputedConstantSize) {
computeConstantSize();
}
@@ -424,15 +416,15 @@
return mConstantMinimumHeight;
}
- private void computeConstantSize()
- {
+ private void computeConstantSize() {
mComputedConstantSize = true;
final int N = getChildCount();
+ final Drawable[] drawables = mDrawables;
mConstantWidth = mConstantHeight = 0;
mConstantMinimumWidth = mConstantMinimumHeight = 0;
- for (int i=0; i<N; i++) {
- Drawable dr = mDrawables[i];
+ for (int i = 0; i < N; i++) {
+ Drawable dr = drawables[i];
int s = dr.getIntrinsicWidth();
if (s > mConstantWidth) mConstantWidth = s;
s = dr.getIntrinsicHeight();
@@ -444,23 +436,22 @@
}
}
- public final int getOpacity()
- {
+ public final int getOpacity() {
if (mHaveOpacity) {
return mOpacity;
}
final int N = getChildCount();
- int op = N > 0
- ? mDrawables[0].getOpacity() : PixelFormat.TRANSPARENT;
- for (int i=1; i<N; i++) {
- op = Drawable.resolveOpacity(op, mDrawables[i].getOpacity());
+ final Drawable[] drawables = mDrawables;
+ int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
+ for (int i = 1; i < N; i++) {
+ op = Drawable.resolveOpacity(op, drawables[i].getOpacity());
}
mOpacity = op;
mHaveOpacity = true;
return op;
}
-
+
public final boolean isStateful() {
if (mHaveStateful) {
return mStateful;
@@ -480,8 +471,7 @@
return stateful;
}
- public void growArray(int oldSize, int newSize)
- {
+ public void growArray(int oldSize, int newSize) {
Drawable[] newDrawables = new Drawable[newSize];
System.arraycopy(mDrawables, 0, newDrawables, 0, oldSize);
mDrawables = newDrawables;
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 901c7a9..048bdd5 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -63,6 +63,23 @@
#define FRAME_CALLBACK_FLAG_CAMERA 0x05
#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07
+// msgType in notifyCallback function
+enum {
+ CAMERA_MSG_ERROR,
+ CAMERA_MSG_SHUTTER,
+ CAMERA_MSG_FOCUS,
+ CAMERA_MSG_ZOOM
+};
+
+// msgType in dataCallback function
+enum {
+ CAMERA_MSG_PREVIEW_FRAME,
+ CAMERA_MSG_VIDEO_FRAME,
+ CAMERA_MSG_POSTVIEW_FRAME,
+ CAMERA_MSG_RAW_IMAGE,
+ CAMERA_MSG_COMPRESSED_IMAGE
+};
+
class ICameraService;
class ICamera;
class Surface;
@@ -136,15 +153,8 @@
void setAutoFocusCallback(autofocus_callback cb, void *cookie);
// ICameraClient interface
- virtual void shutterCallback();
- virtual void rawCallback(const sp<IMemory>& picture);
- virtual void jpegCallback(const sp<IMemory>& picture);
- virtual void previewCallback(const sp<IMemory>& frame);
- virtual void errorCallback(status_t error);
- virtual void autoFocusCallback(bool focused);
- virtual void recordingCallback(const sp<IMemory>& frame);
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
- virtual void dataCallback(int32_t msgType, const sp<IMemory>& frame);
+ virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
sp<ICamera> remote();
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index 1645ef8..c4bdd07 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -29,30 +29,6 @@
public:
DECLARE_META_INTERFACE(CameraClient);
- // msgType in notifyCallback function
- enum {
- ERROR,
- SHUTTER,
- FOCUSED,
- ZOOM
- } notify_callback_message_type;
-
- // msgType in dataCallback function
- enum {
- PREVIEW,
- RECORD,
- POSTVIEW,
- RAW,
- COMPRESSED
- } data_callback_message_type;
-
- virtual void shutterCallback() = 0;
- virtual void rawCallback(const sp<IMemory>& picture) = 0;
- virtual void jpegCallback(const sp<IMemory>& picture) = 0;
- virtual void previewCallback(const sp<IMemory>& frame) = 0;
- virtual void errorCallback(status_t error) = 0;
- virtual void autoFocusCallback(bool focused) = 0;
- virtual void recordingCallback(const sp<IMemory>& frame) = 0;
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
diff --git a/include/utils/backup_helpers.h b/include/utils/backup_helpers.h
index 61bee340..137c5f1 100644
--- a/include/utils/backup_helpers.h
+++ b/include/utils/backup_helpers.h
@@ -1,7 +1,7 @@
#ifndef _UTILS_BACKUP_HELPERS_H
#define _UTILS_BACKUP_HELPERS_H
-int back_up_files(int oldSnapshotFD, int newSnapshotFD, int oldDataStream,
+int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
char const* fileBase, char const* const* files, int fileCount);
#define TEST_BACKUP_HELPERS 0
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index ed4f3b8..6613700 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -337,76 +337,66 @@
mErrorCallbackCookie = cookie;
}
-void Camera::autoFocusCallback(bool focused)
-{
- LOGV("autoFocusCallback");
- if (mAutoFocusCallback) {
- mAutoFocusCallback(focused, mAutoFocusCallbackCookie);
- }
-}
-
-void Camera::shutterCallback()
-{
- LOGV("shutterCallback");
- if (mShutterCallback) {
- mShutterCallback(mShutterCallbackCookie);
- }
-}
-
-void Camera::rawCallback(const sp<IMemory>& picture)
-{
- LOGV("rawCallback");
- if (mRawCallback) {
- mRawCallback(picture, mRawCallbackCookie);
- }
-}
-
-// callback from camera service when image is ready
-void Camera::jpegCallback(const sp<IMemory>& picture)
-{
- LOGV("jpegCallback");
- if (mJpegCallback) {
- mJpegCallback(picture, mJpegCallbackCookie);
- }
-}
-
-// callback from camera service when preview frame is ready
-void Camera::previewCallback(const sp<IMemory>& frame)
-{
- LOGV("frameCallback");
- if (mPreviewCallback) {
- mPreviewCallback(frame, mPreviewCallbackCookie);
- }
-}
-
-// callback from camera service when a recording frame is ready
-void Camera::recordingCallback(const sp<IMemory>& frame)
-{
- LOGV("recordingCallback");
- if (mRecordingCallback) {
- mRecordingCallback(frame, mRecordingCallbackCookie);
- }
-}
-
-// callback from camera service when an error occurs in preview or takePicture
-void Camera::errorCallback(status_t error)
-{
- LOGV("errorCallback");
- if (mErrorCallback) {
- mErrorCallback(error, mErrorCallbackCookie);
- }
-}
-
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
- LOGV("notifyCallback");
+ switch(msgType) {
+ case CAMERA_MSG_ERROR:
+ LOGV("errorCallback");
+ if (mErrorCallback) {
+ mErrorCallback((status_t)ext1, mErrorCallbackCookie);
+ }
+ break;
+ case CAMERA_MSG_FOCUS:
+ LOGV("autoFocusCallback");
+ if (mAutoFocusCallback) {
+ mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie);
+ }
+ break;
+ case CAMERA_MSG_SHUTTER:
+ LOGV("shutterCallback");
+ if (mShutterCallback) {
+ mShutterCallback(mShutterCallbackCookie);
+ }
+ break;
+ default:
+ LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
+ break;
+ }
}
-// callback from camera service when image is ready
-void Camera::dataCallback(int32_t msgType, const sp<IMemory>& frame)
+// callback from camera service when frame or image is ready
+void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
{
- LOGV("dataCallback");
+ switch(msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ LOGV("previewCallback");
+ if (mPreviewCallback) {
+ mPreviewCallback(dataPtr, mPreviewCallbackCookie);
+ }
+ break;
+ case CAMERA_MSG_VIDEO_FRAME:
+ LOGV("recordingCallback");
+ if (mRecordingCallback) {
+ mRecordingCallback(dataPtr, mRecordingCallbackCookie);
+ }
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ LOGV("rawCallback");
+ if (mRawCallback) {
+ mRawCallback(dataPtr, mRawCallbackCookie);
+ }
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ LOGV("jpegCallback");
+ if (mJpegCallback) {
+ mJpegCallback(dataPtr, mJpegCallbackCookie);
+ }
+ break;
+ default:
+ LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
+ break;
+ }
}
void Camera::binderDied(const wp<IBinder>& who) {
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index ae07b67..c6cf75c 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -25,14 +25,7 @@
namespace android {
enum {
- SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
- RAW_CALLBACK,
- JPEG_CALLBACK,
- PREVIEW_CALLBACK,
- ERROR_CALLBACK,
- AUTOFOCUS_CALLBACK,
- RECORDING_CALLBACK,
- NOTIFY_CALLBACK,
+ NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
DATA_CALLBACK,
};
@@ -44,75 +37,6 @@
{
}
- // callback to let the app know the shutter has closed, ideal for playing the shutter sound
- void shutterCallback()
- {
- LOGV("shutterCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app with picture data
- void rawCallback(const sp<IMemory>& picture)
- {
- LOGV("rawCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeStrongBinder(picture->asBinder());
- remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app with picture data
- void jpegCallback(const sp<IMemory>& picture)
- {
- LOGV("jpegCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeStrongBinder(picture->asBinder());
- remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app with preview frame data
- void previewCallback(const sp<IMemory>& frame)
- {
- LOGV("previewCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeStrongBinder(frame->asBinder());
- remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app with recording frame data
- void recordingCallback(const sp<IMemory>& frame)
- {
- LOGV("recordingCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeStrongBinder(frame->asBinder());
- remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app to report error
- void errorCallback(status_t error)
- {
- LOGV("errorCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeInt32(error);
- remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- // callback from camera service to app to report autofocus completion
- void autoFocusCallback(bool focused)
- {
- LOGV("autoFocusCallback");
- Parcel data, reply;
- data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
- data.writeInt32(focused);
- remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
// generic callback from camera service to app
void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
@@ -152,54 +76,6 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
- case SHUTTER_CALLBACK: {
- LOGV("SHUTTER_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- shutterCallback();
- return NO_ERROR;
- } break;
- case RAW_CALLBACK: {
- LOGV("RAW_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
- rawCallback(picture);
- return NO_ERROR;
- } break;
- case JPEG_CALLBACK: {
- LOGV("JPEG_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
- jpegCallback(picture);
- return NO_ERROR;
- } break;
- case PREVIEW_CALLBACK: {
- LOGV("PREVIEW_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
- previewCallback(frame);
- return NO_ERROR;
- } break;
- case RECORDING_CALLBACK: {
- LOGV("RECORDING_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
- recordingCallback(frame);
- return NO_ERROR;
- } break;
- case ERROR_CALLBACK: {
- LOGV("ERROR_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- status_t error = data.readInt32();
- errorCallback(error);
- return NO_ERROR;
- } break;
- case AUTOFOCUS_CALLBACK: {
- LOGV("AUTOFOCUS_CALLBACK");
- CHECK_INTERFACE(ICameraClient, data, reply);
- bool focused = (bool)data.readInt32();
- autoFocusCallback(focused);
- return NO_ERROR;
- } break;
case NOTIFY_CALLBACK: {
LOGV("NOTIFY_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
diff --git a/libs/utils/file_backup_helper.cpp b/libs/utils/file_backup_helper.cpp
index 111f88d..453084a 100644
--- a/libs/utils/file_backup_helper.cpp
+++ b/libs/utils/file_backup_helper.cpp
@@ -24,6 +24,9 @@
#define MAGIC0 0x70616e53 // Snap
#define MAGIC1 0x656c6946 // File
+#define LOGP(x...) LOGD(x)
+//#define LOGP(x...) printf(x)
+
struct SnapshotHeader {
int magic0;
int fileCount;
@@ -159,14 +162,14 @@
static int
write_delete_file(const String8& key)
{
- printf("write_delete_file %s\n", key.string());
+ LOGP("write_delete_file %s\n", key.string());
return 0;
}
static int
write_update_file(const String8& realFilename, const String8& key)
{
- printf("write_update_file %s (%s)\n", realFilename.string(), key.string());
+ LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
return 0;
}
@@ -195,7 +198,7 @@
}
int
-back_up_files(int oldSnapshotFD, int newSnapshotFD, int oldDataStream,
+back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
char const* fileBase, char const* const* files, int fileCount)
{
int err;
@@ -260,10 +263,10 @@
const FileState& f = oldSnapshot.valueAt(n);
const FileState& g = newSnapshot.valueAt(m);
- printf("%s\n", q.string());
- printf(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
+ LOGP("%s\n", q.string());
+ LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
- printf(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
+ LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
|| f.size != g.size || f.crc32 != g.crc32) {
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index aef8985..872838c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1257,7 +1257,7 @@
}
/**
- * Installs a network location provider.
+ * Installs a location provider.
*
* @param name of the location provider
* @param provider Binder interface for the location provider
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 21c7adb..565859c 100644
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -109,13 +109,13 @@
private static final int GPS_STATUS_ENGINE_ON = 3;
private static final int GPS_STATUS_ENGINE_OFF = 4;
- // these need to match GpsSuplStatusValue defines in gps.h
- /** SUPL status event values. */
- private static final int GPS_REQUEST_SUPL_DATA_CONN = 1;
- private static final int GPS_RELEASE_SUPL_DATA_CONN = 2;
- private static final int GPS_SUPL_DATA_CONNECTED = 3;
- private static final int GPS_SUPL_DATA_CONN_DONE = 4;
- private static final int GPS_SUPL_DATA_CONN_FAILED = 5;
+ // these need to match GpsApgsStatusValue defines in gps.h
+ /** AGPS status event values. */
+ private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
+ private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
+ private static final int GPS_AGPS_DATA_CONNECTED = 3;
+ private static final int GPS_AGPS_DATA_CONN_DONE = 4;
+ private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
// these need to match GpsLocationFlags enum in gps.h
private static final int LOCATION_INVALID = 0;
@@ -124,8 +124,8 @@
private static final int LOCATION_HAS_SPEED = 4;
private static final int LOCATION_HAS_BEARING = 8;
private static final int LOCATION_HAS_ACCURACY = 16;
-
-// IMPORTANT - the GPS_DELETE_* symbols here must match constants in GpsLocationProvider.java
+
+// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
private static final int GPS_DELETE_EPHEMERIS = 0x0001;
private static final int GPS_DELETE_ALMANAC = 0x0002;
private static final int GPS_DELETE_POSITION = 0x0004;
@@ -140,10 +140,14 @@
private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
private static final int GPS_DELETE_ALL = 0xFFFF;
- // for mSuplDataConnectionState
- private static final int SUPL_DATA_CONNECTION_CLOSED = 0;
- private static final int SUPL_DATA_CONNECTION_OPENING = 1;
- private static final int SUPL_DATA_CONNECTION_OPEN = 2;
+ // these need to match AGpsType enum in gps.h
+ private static final int AGPS_TYPE_SUPL = 1;
+ private static final int AGPS_TYPE_C2K = 2;
+
+ // for mAGpsDataConnectionState
+ private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
+ private static final int AGPS_DATA_CONNECTION_OPENING = 1;
+ private static final int AGPS_DATA_CONNECTION_OPEN = 2;
private static final String PROPERTIES_FILE = "/etc/gps.conf";
@@ -156,11 +160,14 @@
private long mStatusUpdateTime = SystemClock.elapsedRealtime();
// turn off GPS fix icon if we haven't received a fix in 10 seconds
- private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
+ private static final long RECENT_FIX_TIMEOUT = 10;
// number of fixes to receive before disabling GPS
private static final int MIN_FIX_COUNT = 10;
+ // stop trying if we do not receive a fix within 60 seconds
+ private static final int NO_FIX_TIMEOUT = 60;
+
// true if we are enabled
private boolean mEnabled;
@@ -203,9 +210,12 @@
private String mSuplHost;
private int mSuplPort;
+ private String mC2KHost;
+ private int mC2KPort;
private boolean mSetSuplServer;
- private String mSuplApn;
- private int mSuplDataConnectionState;
+ private boolean mSetC2KServer;
+ private String mAGpsApn;
+ private int mAGpsDataConnectionState;
private final ConnectivityManager mConnMgr;
// Wakelocks
@@ -214,8 +224,10 @@
// Alarms
private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
+ private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
private final AlarmManager mAlarmManager;
private final PendingIntent mWakeupIntent;
+ private final PendingIntent mTimeoutIntent;
private final IBatteryStats mBatteryStats;
private final SparseIntArray mClientUids = new SparseIntArray();
@@ -285,6 +297,9 @@
if (action.equals(ALARM_WAKEUP)) {
if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
startNavigating();
+ } else if (action.equals(ALARM_TIMEOUT)) {
+ if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
+ hibernate();
} else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
String state = intent.getStringExtra(Phone.STATE_KEY);
String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
@@ -293,11 +308,12 @@
if (Config.LOGD) {
Log.d(TAG, "state: " + state + " apnName: " + apnName + " reason: " + reason);
}
+ // FIXME - might not have an APN on CDMA
if ("CONNECTED".equals(state) && apnName != null && apnName.length() > 0) {
- mSuplApn = apnName;
- if (mSuplDataConnectionState == SUPL_DATA_CONNECTION_OPENING) {
- native_supl_data_conn_open(mSuplApn);
- mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPEN;
+ mAGpsApn = apnName;
+ if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
+ native_agps_data_conn_open(mAGpsApn);
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
}
}
}
@@ -318,9 +334,11 @@
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
+ mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ALARM_WAKEUP);
+ intentFilter.addAction(ALARM_TIMEOUT);
intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
context.registerReceiver(mBroadcastReciever, intentFilter);
@@ -336,14 +354,26 @@
mProperties.load(stream);
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
+
mSuplHost = mProperties.getProperty("SUPL_HOST");
- String suplPortString = mProperties.getProperty("SUPL_PORT");
- if (mSuplHost != null && suplPortString != null) {
+ String portString = mProperties.getProperty("SUPL_PORT");
+ if (mSuplHost != null && portString != null) {
try {
- mSuplPort = Integer.parseInt(suplPortString);
+ mSuplPort = Integer.parseInt(portString);
mSetSuplServer = true;
} catch (NumberFormatException e) {
- Log.e(TAG, "unable to parse SUPL_PORT: " + suplPortString);
+ Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
+ }
+ }
+
+ mC2KHost = mProperties.getProperty("C2K_HOST");
+ portString = mProperties.getProperty("C2K_PORT");
+ if (mC2KHost != null && portString != null) {
+ try {
+ mC2KPort = Integer.parseInt(portString);
+ mSetC2KServer = true;
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
}
} catch (IOException e) {
@@ -358,7 +388,8 @@
public boolean requiresNetwork() {
// We want updateNetworkState() to get called when the network state changes
// for XTRA and NTP time injection support.
- return (mNtpServer != null || native_supports_xtra() || mSuplHost != null);
+ return (mNtpServer != null || native_supports_xtra() ||
+ mSuplHost != null || mC2KHost != null);
}
public void updateNetworkState(int state) {
@@ -548,6 +579,7 @@
startNavigating();
} else {
mAlarmManager.cancel(mWakeupIntent);
+ mAlarmManager.cancel(mTimeoutIntent);
stopNavigating();
}
}
@@ -561,7 +593,6 @@
interval = 1;
}
mFixInterval = interval;
- native_set_fix_frequency(mFixInterval);
}
}
@@ -652,12 +683,19 @@
if (!native_start(mPositionMode, false, mFixInterval)) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
+ return;
}
// reset SV count to zero
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
mFixCount = 0;
mFixRequestTime = System.currentTimeMillis();
+ // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
+ // and our fix interval is not short
+ if (mFixInterval >= NO_FIX_TIMEOUT) {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT * 1000, mTimeoutIntent);
+ }
}
}
@@ -675,6 +713,17 @@
}
}
+ private void hibernate() {
+ // stop GPS until our next fix interval arrives
+ stopNavigating();
+ mFixCount = 0;
+ mAlarmManager.cancel(mTimeoutIntent);
+ mAlarmManager.cancel(mWakeupIntent);
+ long now = SystemClock.elapsedRealtime();
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent);
+ }
+
/**
* called from native code to update our position.
*/
@@ -742,6 +791,7 @@
}
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
+ mAlarmManager.cancel(mTimeoutIntent);
// send an intent to notify that the GPS is receiving fixes.
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
intent.putExtra(EXTRA_ENABLED, true);
@@ -751,12 +801,7 @@
if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) {
if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT");
- stopNavigating();
- mFixCount = 0;
- mAlarmManager.cancel(mWakeupIntent);
- long now = SystemClock.elapsedRealtime();
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent);
+ hibernate();
}
}
@@ -861,7 +906,7 @@
updateStatus(mStatus, svCount);
if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
- System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
+ System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT * 1000) {
// send an intent to notify that the GPS is no longer receiving fixes.
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
intent.putExtra(EXTRA_ENABLED, false);
@@ -871,38 +916,38 @@
}
/**
- * called from native code to update SUPL status
+ * called from native code to update AGPS status
*/
- private void reportSuplStatus(int status) {
+ private void reportAGpsStatus(int type, int status) {
switch (status) {
- case GPS_REQUEST_SUPL_DATA_CONN:
+ case GPS_REQUEST_AGPS_DATA_CONN:
int result = mConnMgr.startUsingNetworkFeature(
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
if (result == Phone.APN_ALREADY_ACTIVE) {
- native_supl_data_conn_open(mSuplApn);
- mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPEN;
+ native_agps_data_conn_open(mAGpsApn);
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
} else if (result == Phone.APN_REQUEST_STARTED) {
- mSuplDataConnectionState = SUPL_DATA_CONNECTION_OPENING;
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
} else {
- native_supl_data_conn_failed();
+ native_agps_data_conn_failed();
}
break;
- case GPS_RELEASE_SUPL_DATA_CONN:
- if (mSuplDataConnectionState != SUPL_DATA_CONNECTION_CLOSED) {
+ case GPS_RELEASE_AGPS_DATA_CONN:
+ if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
mConnMgr.stopUsingNetworkFeature(
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
- native_supl_data_conn_closed();
- mSuplDataConnectionState = SUPL_DATA_CONNECTION_CLOSED;
+ native_agps_data_conn_closed();
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
}
break;
- case GPS_SUPL_DATA_CONNECTED:
- // Log.d(TAG, "GPS_SUPL_DATA_CONNECTED");
+ case GPS_AGPS_DATA_CONNECTED:
+ // Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
break;
- case GPS_SUPL_DATA_CONN_DONE:
- // Log.d(TAG, "GPS_SUPL_DATA_CONN_DONE");
+ case GPS_AGPS_DATA_CONN_DONE:
+ // Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
break;
- case GPS_SUPL_DATA_CONN_FAILED:
- // Log.d(TAG, "GPS_SUPL_DATA_CONN_FAILED");
+ case GPS_AGPS_DATA_CONN_FAILED:
+ // Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
break;
}
}
@@ -914,6 +959,29 @@
}
}
+ private boolean setAGpsServer(int type, String host, int port) {
+ try {
+ InetAddress inetAddress = InetAddress.getByName(host);
+ if (inetAddress != null) {
+ byte[] addrBytes = inetAddress.getAddress();
+ long addr = 0;
+ for (int i = 0; i < addrBytes.length; i++) {
+ int temp = addrBytes[i];
+ // signed -> unsigned
+ if (temp < 0) temp = 256 + temp;
+ addr = addr * 256 + temp;
+ }
+ // use MS-Based position mode if SUPL support is enabled
+ mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ native_set_agps_server(type, (int)addr, port);
+ }
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "unknown host for server " + host);
+ return false;
+ }
+ return true;
+ }
+
private class GpsEventThread extends Thread {
public GpsEventThread() {
@@ -985,7 +1053,8 @@
}
}
waitTime = getWaitTime();
- } while (!mDone && ((!mXtraDownloadRequested && !mSetSuplServer && waitTime > 0)
+ } while (!mDone && ((!mXtraDownloadRequested &&
+ !mSetSuplServer && !mSetC2KServer && waitTime > 0)
|| !mNetworkAvailable));
if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
@@ -1012,26 +1081,15 @@
}
}
- // Set the SUPL server address if we have not yet
+ // Set the AGPS server addresses if we have not yet
if (mSetSuplServer) {
- try {
- InetAddress inetAddress = InetAddress.getByName(mSuplHost);
- if (inetAddress != null) {
- byte[] addrBytes = inetAddress.getAddress();
- long addr = 0;
- for (int i = 0; i < addrBytes.length; i++) {
- int temp = addrBytes[i];
- // signed -> unsigned
- if (temp < 0) temp = 256 + temp;
- addr = addr * 256 + temp;
- }
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
- native_set_supl_server((int)addr, mSuplPort);
- mSetSuplServer = false;
- }
- } catch (UnknownHostException e) {
- Log.e(TAG, "unknown host for SUPL server " + mSuplHost);
+ if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) {
+ mSetSuplServer = false;
+ }
+ }
+ if (mSetC2KServer) {
+ if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) {
+ mSetC2KServer = false;
}
}
@@ -1125,9 +1183,9 @@
private native boolean native_supports_xtra();
private native void native_inject_xtra_data(byte[] data, int length);
- // SUPL Support
- private native void native_supl_data_conn_open(String apn);
- private native void native_supl_data_conn_closed();
- private native void native_supl_data_conn_failed();
- private native void native_set_supl_server(int addr, int port);
+ // AGPS Support
+ private native void native_agps_data_conn_open(String apn);
+ private native void native_agps_data_conn_closed();
+ private native void native_agps_data_conn_failed();
+ private native void native_set_agps_server(int type, int addr, int port);
}
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 80303f4..b40cdca 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -21,6 +21,7 @@
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -31,7 +32,7 @@
*
* {@hide}
*/
-public class LocationProviderProxy {
+public class LocationProviderProxy implements IBinder.DeathRecipient {
private static final String TAG = "LocationProviderProxy";
@@ -39,16 +40,27 @@
private final ILocationProvider mProvider;
private boolean mLocationTracking = false;
private long mMinTime = 0;
+ private boolean mDead;
public LocationProviderProxy(String name, ILocationProvider provider) {
mName = name;
mProvider = provider;
+ try {
+ provider.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath failed", e);
+ mDead = true;
+ }
}
public String getName() {
return mName;
}
+ public boolean isDead() {
+ return mDead;
+ }
+
public boolean requiresNetwork() {
try {
return mProvider.requiresNetwork();
@@ -231,4 +243,9 @@
Log.e(TAG, "removeListener failed", e);
}
}
+
+ public void binderDied() {
+ Log.w(TAG, "Location Provider " + mName + " died");
+ mDead = true;
+ }
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e43c9c4..cfdf5e3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -39,11 +39,6 @@
private final Context mContext;
private final Handler mHandler;
- // used to listen for updates to the sound effects settings so we don't
- // poll it for every UI sound
- private ContentObserver mContentObserver;
-
-
private static String TAG = "AudioManager";
private static boolean DEBUG = false;
private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index f05842d..8be11df 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -31,7 +31,7 @@
*/
public class MediaFile {
// comma separated list of all file extensions supported by the media scanner
- public static String sFileExtensions;
+ public final static String sFileExtensions;
// Audio file types
public static final int FILE_TYPE_MP3 = 1;
@@ -93,7 +93,7 @@
= new HashMap<String, Integer>();
static void addFileType(String extension, int fileType, String mimeType) {
sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
- sMimeTypeMap.put(mimeType, new Integer(fileType));
+ sMimeTypeMap.put(mimeType, Integer.valueOf(fileType));
}
static {
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index b13c2e6..3803d9d 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -149,7 +149,9 @@
fd.close();
}
}
- } catch (java.io.IOException e) {}
+ } catch (java.io.IOException e) {
+ Log.d(TAG, "error loading " + path);
+ }
return id;
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 209b09f..cac65d6 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -150,6 +150,11 @@
static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
{
+ // we should not pass a null camera to get_native_camera() call.
+ if (camera == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "camera object is a NULL pointer");
+ return;
+ }
sp<Camera> c = get_native_camera(env, camera, NULL);
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setCamera(c->remote()),
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index 4c01871a..a8fe2e9 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -599,21 +599,6 @@
#define GL_EXT_texture_filter_anisotropic 1
#endif
-/*------------------------------------------------------------------------*
- * dalvik extension functions
- *------------------------------------------------------------------------*/
-#ifdef ANDROID
-void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
- const GLvoid *ptr, GLsizei count);
-void glNormalPointerBounds(GLenum type, GLsizei stride,
- const GLvoid *pointer, GLsizei count);
-void glTexCoordPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count);
-void glVertexPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count);
-#endif
-
-
#ifdef __cplusplus
}
#endif
diff --git a/opengl/include/KHR/khrplatform.h b/opengl/include/KHR/khrplatform.h
index 4cc27c5..1660bd7 100644
--- a/opengl/include/KHR/khrplatform.h
+++ b/opengl/include/KHR/khrplatform.h
@@ -91,6 +91,8 @@
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
+#elif defined(ANDROID)
+# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index af5a700..946e849 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -44,6 +44,8 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
+LOCAL_CFLAGS += -fvisibility=hidden
+
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libagl
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index da00cc5..538e943 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -24,6 +24,7 @@
LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
@@ -53,5 +54,6 @@
LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 6c80538..7cdf494 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -178,8 +178,8 @@
// ----------------------------------------------------------------------------
-gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
-pthread_key_t gGLWrapperKey = -1;
+EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+EGLAPI pthread_key_t gGLWrapperKey = -1;
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
index 3f9fd63..f9dc5f1 100644
--- a/opengl/libs/EGL/gpu.cpp
+++ b/opengl/libs/EGL/gpu.cpp
@@ -53,7 +53,7 @@
static Mutex gRegionsLock;
static request_gpu_t gRegions;
static sp<ISurfaceComposer> gSurfaceManager;
-ISurfaceComposer* GLES_localSurfaceManager = 0;
+GL_API ISurfaceComposer* GLES_localSurfaceManager = 0;
extern egl_connection_t gEGLImpl[2];
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index d1b9ac6..3204d9a 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -35,6 +35,17 @@
// extensions for the framework
// ----------------------------------------------------------------------------
+extern "C" {
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+}
+
void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
const GLvoid *ptr, GLsizei count) {
glColorPointer(size, type, stride, ptr);
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 4e0c7bf..80455d0 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -21,6 +21,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <EGL/eglplatform.h>
// ----------------------------------------------------------------------------
namespace android {
@@ -37,7 +38,7 @@
int unavailable;
};
-EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
+EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index 7aa18b6..3948fd3 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -23,6 +23,19 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+}
+
static int initialized = 0;
static jclass nioAccessClass;
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 8f174c7..11c6087 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -23,6 +23,19 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+}
+
static int initialized = 0;
static jclass nioAccessClass;
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index 6ecda48..c254d93 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
<receiver android:name="SubscribedFeedsBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="GSYNC_TICKLE"/>
</intent-filter>
<intent-filter>
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 0d05286..2326b46 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -43,8 +43,7 @@
private static final String sSubscribedFeedsPrefs = "subscribedFeeds";
- private static final String GTALK_DATA_MESSAGE_RECEIVED =
- "android.intent.action.GTALK_DATA_MESSAGE_RECEIVED";
+ private static final String REMOTE_INTENT_ACTION = Intent.ACTION_REMOTE_INTENT;
private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
"com.android.subscribedfeeds.action.REFRESH";
@@ -56,8 +55,9 @@
}
protected void onHandleIntent(Intent intent) {
- if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
- boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
+ if (REMOTE_INTENT_ACTION.equals(intent.getAction())) {
+ boolean fromTrustedServer = intent.getBooleanExtra(
+ "android.intent.extra.from_trusted_server", false);
if (fromTrustedServer) {
String accountName = intent.getStringExtra("account");
String token = intent.getStringExtra("message_token");
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index e582fb15..983329b 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -46,6 +46,8 @@
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.lang.String;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -74,137 +76,16 @@
fullBackup = isFull;
}
}
- private HashSet<BackupRequest> mPendingBackups = new HashSet<BackupRequest>();
+ // Backups that we haven't started yet.
+ private HashMap<ComponentName,BackupRequest> mPendingBackups = new HashMap();
+ // Backups that we have started. These are separate to prevent starvation
+ // if an app keeps re-enqueuing itself.
+ private ArrayList<BackupRequest> mBackupQueue;
private final Object mQueueLock = new Object();
private File mStateDir;
private File mDataDir;
- // ----- Handler that runs the actual backup process asynchronously -----
-
- private class BackupHandler extends Handler implements ServiceConnection {
- private volatile Object mBindSignaller = new Object();
- private volatile boolean mBinding = false;
- private IBackupService mTargetService = null;
-
- public void handleMessage(Message msg) {
-
- switch (msg.what) {
- case MSG_RUN_BACKUP:
- {
- // snapshot the pending-backup set and work on that
- HashSet<BackupRequest> queue;
- synchronized (mQueueLock) {
- queue = mPendingBackups;
- mPendingBackups = new HashSet<BackupRequest>();
- // !!! TODO: start a new backup-queue journal file too
- }
-
- // Walk the set of pending backups, setting up the relevant files and
- // invoking the backup service in each participant
- Intent backupIntent = new Intent(BackupService.SERVICE_ACTION);
- for (BackupRequest request : queue) {
- mBinding = true;
- mTargetService = null;
-
- backupIntent.setClassName(request.service.packageName, request.service.name);
- Log.d(TAG, "binding to " + backupIntent);
- if (mContext.bindService(backupIntent, this, 0)) {
- synchronized (mBindSignaller) {
- while (mTargetService == null && mBinding == true) {
- try {
- mBindSignaller.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- if (mTargetService != null) {
- try {
- Log.d(TAG, "invoking doBackup() on " + backupIntent);
-
- // !!! TODO right now these naming schemes limit applications to
- // one backup service per package
- File savedStateName = new File(mStateDir,
- request.service.packageName);
- File backupDataName = new File(mDataDir,
- request.service.packageName + ".data");
- File newStateName = new File(mStateDir,
- request.service.packageName + ".new");
-
- // In a full backup, we pass a null ParcelFileDescriptor as
- // the saved-state "file"
- ParcelFileDescriptor savedState = (request.fullBackup) ? null
- : ParcelFileDescriptor.open(savedStateName,
- ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE);
-
- backupDataName.delete();
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
-
- newStateName.delete();
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
-
- // Run the target's backup pass
- try {
- mTargetService.doBackup(savedState, backupData, newState);
- } finally {
- savedState.close();
- backupData.close();
- newState.close();
- }
-
- // !!! TODO: Now propagate the newly-backed-up data to the transport
-
- // !!! TODO: After successful transport, delete the now-stale data
- // and juggle the files so that next time the new state is passed
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
-
- } catch (FileNotFoundException fnf) {
- Log.d(TAG, "File not found on backup: ");
- fnf.printStackTrace();
- } catch (RemoteException e) {
- Log.d(TAG, "Remote target " + backupIntent
- + " threw during backup:");
- e.printStackTrace();
- } catch (Exception e) {
- Log.w(TAG, "Final exception guard in backup: ");
- e.printStackTrace();
- }
- mContext.unbindService(this);
- }
- } else {
- Log.d(TAG, "Unable to bind to " + backupIntent);
- }
- }
- }
- break;
- }
- }
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mBindSignaller) {
- mTargetService = IBackupService.Stub.asInterface(service);
- mBinding = false;
- mBindSignaller.notifyAll();
- }
- }
-
- public void onServiceDisconnected(ComponentName name) {
- synchronized (mBindSignaller) {
- mTargetService = null;
- mBinding = false;
- mBindSignaller.notifyAll();
- }
- }
- }
-
public BackupManagerService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -268,6 +149,143 @@
}
};
+ // ----- Run the actual backup process asynchronously -----
+
+ private class BackupHandler extends Handler implements ServiceConnection {
+ public void handleMessage(Message msg) {
+
+ switch (msg.what) {
+ case MSG_RUN_BACKUP:
+ // snapshot the pending-backup set and work on that
+ synchronized (mQueueLock) {
+ mBackupQueue = new ArrayList();
+ for (BackupRequest b: mPendingBackups.values()) {
+ mBackupQueue.add(b);
+ }
+ mPendingBackups = new HashMap<ComponentName,BackupRequest>();
+ // !!! TODO: start a new backup-queue journal file too
+ // WARNING: If we crash after this line, anything in mPendingBackups will
+ // be lost. FIX THIS.
+ }
+ startOneService();
+ break;
+ }
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "onServiceConnected name=" + name + " service=" + service);
+ IBackupService bs = IBackupService.Stub.asInterface(service);
+ processOneBackup(name, bs);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ // TODO: handle backup being interrupted
+ }
+ }
+
+ void startOneService() {
+ // Loop until we find someone to start or the queue empties out.
+ Intent intent = new Intent(BackupService.SERVICE_ACTION);
+ while (true) {
+ BackupRequest request;
+ synchronized (mQueueLock) {
+ int queueSize = mBackupQueue.size();
+ if (queueSize == 0) {
+ mBackupQueue = null;
+ // TODO: Anything else to do here?
+ return;
+ }
+ request = mBackupQueue.get(0);
+ // Take it off the queue when we're done.
+ }
+
+ intent.setClassName(request.service.packageName, request.service.name);
+ Log.d(TAG, "binding to " + intent);
+ try {
+ if (mContext.bindService(intent, mBackupHandler, Context.BIND_AUTO_CREATE)) {
+ Log.d(TAG, "awaiting service object for " + intent);
+ // success
+ return;
+ }
+ } catch (SecurityException ex) {
+ // Try for the next one.
+ Log.d(TAG, "error in bind", ex);
+ }
+ }
+ }
+
+ void processOneBackup(ComponentName name, IBackupService bs) {
+ try {
+ Log.d(TAG, "processOneBackup doBackup() on " + name);
+
+ BackupRequest request;
+ synchronized (mQueueLock) {
+ if (mBackupQueue == null) {
+ Log.d(TAG, "mBackupQueue is null. WHY?");
+ }
+ request = mBackupQueue.get(0);
+ }
+
+ // !!! TODO right now these naming schemes limit applications to
+ // one backup service per package
+ File savedStateName = new File(mStateDir, request.service.packageName);
+ File backupDataName = new File(mDataDir, request.service.packageName + ".data");
+ File newStateName = new File(mStateDir, request.service.packageName + ".new");
+
+ // In a full backup, we pass a null ParcelFileDescriptor as
+ // the saved-state "file"
+ ParcelFileDescriptor savedState = (request.fullBackup) ? null
+ : ParcelFileDescriptor.open(savedStateName,
+ ParcelFileDescriptor.MODE_READ_ONLY |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ backupDataName.delete();
+ ParcelFileDescriptor backupData =
+ ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ newStateName.delete();
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ // Run the target's backup pass
+ try {
+ // TODO: Make this oneway
+ bs.doBackup(savedState, backupData, newState);
+ } finally {
+ if (savedState != null) {
+ savedState.close();
+ }
+ backupData.close();
+ newState.close();
+ }
+
+ // !!! TODO: Now propagate the newly-backed-up data to the transport
+
+ // !!! TODO: After successful transport, delete the now-stale data
+ // and juggle the files so that next time the new state is passed
+ backupDataName.delete();
+ newStateName.renameTo(savedStateName);
+
+ } catch (FileNotFoundException fnf) {
+ Log.d(TAG, "File not found on backup: ");
+ fnf.printStackTrace();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Remote target " + name + " threw during backup:");
+ e.printStackTrace();
+ } catch (Exception e) {
+ Log.w(TAG, "Final exception guard in backup: ");
+ e.printStackTrace();
+ }
+ synchronized (mQueueLock) {
+ mBackupQueue.remove(0);
+ }
+ mContext.unbindService(mBackupHandler);
+ }
+
// Add the backup services in the given package to our set of known backup participants.
// If 'packageName' is null, adds all backup services in the system.
void addPackageParticipantsLocked(String packageName) {
@@ -305,7 +323,8 @@
removePackageParticipantsLockedInner(packageName, services);
}
- private void removePackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
+ private void removePackageParticipantsLockedInner(String packageName,
+ List<ResolveInfo> services) {
for (ResolveInfo ri : services) {
if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
int uid = ri.serviceInfo.applicationInfo.uid;
@@ -353,10 +372,11 @@
// validate the caller-supplied package name against the known set of
// packages associated with this uid
if (service.packageName.equals(packageName)) {
- // add the caller to the set of pending backups
- if (mPendingBackups.add(new BackupRequest(service, false))) {
- // !!! TODO: write to the pending-backup journal file in case of crash
- }
+ // Add the caller to the set of pending backups. If there is
+ // one already there, then overwrite it, but no harm done.
+ mPendingBackups.put(new ComponentName(service.packageName, service.name),
+ new BackupRequest(service, true));
+ // !!! TODO: write to the pending-backup journal file in case of crash
}
}
@@ -381,7 +401,8 @@
HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
for (ServiceInfo service: servicesAtUid) {
if (service.packageName.equals(packageName)) {
- mPendingBackups.add(new BackupRequest(service, true));
+ mPendingBackups.put(new ComponentName(service.packageName, service.name),
+ new BackupRequest(service, true));
}
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 90d8c9d..caad7d0 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -92,6 +92,8 @@
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
+ private static final int BATTERY_LEVEL_WARNING = 15;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -260,6 +262,17 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent);
}
+
+ final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+ final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+ /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+ * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
+ * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
+ */
+ final boolean sendBatteryLow = !plugged
+ && mBatteryLevel < BATTERY_LEVEL_WARNING
+ && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
@@ -269,8 +282,11 @@
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
-
+
sendIntent();
+ if (sendBatteryLow) {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
+ }
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 85861bb..52e09ca 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -74,7 +74,7 @@
private boolean mLowMemFlag=false;
private Context mContext;
private ContentResolver mContentResolver;
- int mBlkSize;
+ long mBlkSize;
long mTotalMemory;
StatFs mFileStats;
private static final String DATA_PATH="/data";
@@ -251,7 +251,7 @@
//initialize block size
mBlkSize = mFileStats.getBlockSize();
//initialize total storage on device
- mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100;
+ mTotalMemory = ((long)mFileStats.getBlockCount()*mBlkSize)/100L;
mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
checkMemory(true);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 14c834b..05888e0 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -215,8 +215,7 @@
public int hashCode() {
return mKey.hashCode();
}
-
-
+
@Override
public String toString() {
if (mListener != null) {
@@ -611,6 +610,17 @@
}
synchronized (mLock) {
+ // check to see if we are reinstalling a dead provider
+ LocationProviderProxy oldProvider = mProvidersByName.get(name);
+ if (oldProvider != null) {
+ if (oldProvider.isDead()) {
+ Log.d(TAG, "replacing dead provider");
+ removeProvider(oldProvider);
+ } else {
+ throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+ }
+ }
+
LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
addProvider(proxy);
updateProvidersLocked();
@@ -1616,6 +1626,7 @@
mCollector.updateLocation(location);
} catch (RemoteException e) {
Log.w(TAG, "mCollector.updateLocation failed");
+ mCollector = null;
}
}
@@ -1750,6 +1761,7 @@
variant, appName, addrs);
} catch (RemoteException e) {
Log.e(TAG, "getFromLocation failed", e);
+ mGeocodeProvider = null;
}
}
return null;
@@ -1768,6 +1780,7 @@
maxResults, language, country, variant, appName, addrs);
} catch (RemoteException e) {
Log.e(TAG, "getFromLocationName failed", e);
+ mGeocodeProvider = null;
}
}
return null;
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index 5a42e76..3c366da 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -30,8 +30,8 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) {
- if (!intent.getBooleanExtra("from_trusted_server", false)) {
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index f1dd1d2..adc4de8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -59,6 +59,7 @@
import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Parcel;
@@ -140,8 +141,9 @@
Process.THREAD_PRIORITY_BACKGROUND);
final Handler mHandler;
- final int mSdkVersion = SystemProperties.getInt(
- "ro.build.version.sdk", 0);
+ final int mSdkVersion = Build.VERSION.SDK_INT;
+ final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
+ ? null : Build.VERSION.CODENAME;
final Context mContext;
final boolean mFactoryTest;
@@ -1754,7 +1756,7 @@
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(scanFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
- pp.setSdkVersion(mSdkVersion);
+ pp.setSdkVersion(mSdkVersion, mSdkCodename);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
if (pkg == null) {
@@ -1764,8 +1766,7 @@
PackageSetting ps;
PackageSetting updatedPkg;
synchronized (mPackages) {
- ps = mSettings.peekPackageLP(pkg.packageName,
- scanFile.toString());
+ ps = mSettings.peekPackageLP(pkg.packageName);
updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
}
if (updatedPkg != null) {
@@ -1774,13 +1775,21 @@
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// Check for updated system applications here
- if ((updatedPkg != null) && (ps == null)) {
- // The system package has been updated and the code path does not match
- // Ignore entry. Just return
- Log.w(TAG, "Package:" + pkg.packageName +
- " has been updated. Ignoring the one from path:"+scanFile);
- mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
- return null;
+ if (updatedPkg != null) {
+ if ((ps != null) && (!ps.codePath.getPath().equals(scanFile.getPath()))) {
+ if (pkg.mVersionCode <= ps.versionCode) {
+ // The system package has been updated and the code path does not match
+ // Ignore entry. Just return
+ Log.w(TAG, "Package:" + pkg.packageName +
+ " has been updated. Ignoring the one from path:"+scanFile);
+ mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
+ return null;
+ } else {
+ // Delete the older apk pointed to by ps
+ deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
+ mSettings.enableSystemPackageLP(ps.name);
+ }
+ }
}
}
if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
@@ -3225,20 +3234,27 @@
private final String mRootDir;
private final boolean mIsRom;
}
-
+
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
+ installPackage(packageURI, observer, flags, null);
+ }
+
+ /* Called when a downloaded package installation has been confirmed by the user */
+ public void installPackage(
+ final Uri packageURI, final IPackageInstallObserver observer, final int flags,
+ final String installerPackageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES, null);
-
+
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
PackageInstalledInfo res;
synchronized (mInstallLock) {
- res = installPackageLI(packageURI, flags, true);
+ res = installPackageLI(packageURI, flags, true, installerPackageName);
}
if (observer != null) {
try {
@@ -3286,7 +3302,7 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
res.name = pkgName;
@@ -3322,7 +3338,8 @@
destResourceFile, pkg,
newPackage,
true,
- forwardLocked,
+ forwardLocked,
+ installerPackageName,
res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
@@ -3343,26 +3360,27 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
- PackageParser.Package deletedPackage;
+ String installerPackageName, PackageInstalledInfo res) {
+
+ PackageParser.Package oldPackage;
// First find the old package info and check signatures
synchronized(mPackages) {
- deletedPackage = mPackages.get(pkgName);
- if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) {
+ oldPackage = mPackages.get(pkgName);
+ if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
}
}
- boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
if(sysPkg) {
- replaceSystemPackageLI(deletedPackage,
+ replaceSystemPackageLI(oldPackage,
tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, res);
+ newInstall, installerPackageName, res);
} else {
- replaceNonSystemPackageLI(deletedPackage, tmpPackageFile, destFilePath,
+ replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, res);
+ newInstall, installerPackageName, res);
}
}
@@ -3370,12 +3388,18 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean updatedSettings = false;
- int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE;
+
+ String oldInstallerPackageName = null;
+ synchronized (mPackages) {
+ oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
+ }
+
+ int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING;
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
res.removedInfo)) {
@@ -3403,6 +3427,7 @@
newPackage,
true,
forwardLocked,
+ installerPackageName,
res);
updatedSettings = true;
}
@@ -3446,8 +3471,8 @@
installPackageLI(
Uri.fromFile(new File(deletedPackage.mPath)),
isForwardLocked(deletedPackage)
- ? PackageManager.FORWARD_LOCK_PACKAGE
- : 0, false);
+ ? PackageManager.INSTALL_FORWARD_LOCK
+ : 0, false, oldInstallerPackageName);
}
}
}
@@ -3456,10 +3481,10 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
boolean updatedSettings = false;
- int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE |
+ int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING |
PackageParser.PARSE_IS_SYSTEM;
String packageName = deletedPackage.packageName;
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -3506,7 +3531,8 @@
destResourceFile, pkg,
newPackage,
true,
- forwardLocked,
+ forwardLocked,
+ installerPackageName,
res);
updatedSettings = true;
}
@@ -3533,6 +3559,8 @@
synchronized(mPackages) {
if(updatedSettings) {
mSettings.enableSystemPackageLP(packageName);
+ mSettings.setInstallerPackageName(packageName,
+ oldPkgSetting.installerPackageName);
}
mSettings.writeLP();
}
@@ -3546,7 +3574,7 @@
PackageParser.Package newPackage,
boolean replacingExistingPackage,
boolean forwardLocked,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
@@ -3593,6 +3621,7 @@
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+ mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLP();
@@ -3600,7 +3629,7 @@
}
private PackageInstalledInfo installPackageLI(Uri pPackageURI,
- int pFlags, boolean newInstall) {
+ int pFlags, boolean newInstall, String installerPackageName) {
File tmpPackageFile = null;
String pkgName = null;
boolean forwardLocked = false;
@@ -3671,13 +3700,13 @@
res.name = pkgName;
//initialize some variables before installing pkg
final String pkgFileName = pkgName + ".apk";
- final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0)
+ final File destDir = ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0)
? mDrmAppPrivateInstallDir
: mAppInstallDir;
final File destPackageFile = new File(destDir, pkgFileName);
final String destFilePath = destPackageFile.getAbsolutePath();
File destResourceFile;
- if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) {
+ if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
final String publicZipFileName = pkgName + ".zip";
destResourceFile = new File(mAppInstallDir, publicZipFileName);
forwardLocked = true;
@@ -3689,13 +3718,19 @@
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(tmpPackageFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
- pp.setSdkVersion(mSdkVersion);
+ pp.setSdkVersion(mSdkVersion, mSdkCodename);
final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
if (pkg == null) {
res.returnCode = pp.getParseError();
break main_flow;
}
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+ if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
+ res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
+ break main_flow;
+ }
+ }
if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
res.returnCode = pp.getParseError();
break main_flow;
@@ -3703,7 +3738,7 @@
synchronized (mPackages) {
//check if installing already existing package
- if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0
+ if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
&& mPackages.containsKey(pkgName)) {
replacingExistingPackage = true;
}
@@ -3713,13 +3748,13 @@
replacePackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall,
+ pkg, forwardLocked, newInstall, installerPackageName,
res);
} else {
installNewPackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall,
+ pkg, forwardLocked, newInstall, installerPackageName,
res);
}
} finally {
@@ -3999,7 +4034,7 @@
* Tries to delete system package.
*/
private boolean deleteSystemPackageLI(PackageParser.Package p,
- boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
+ int flags, PackageRemovedInfo outInfo) {
ApplicationInfo applicationInfo = p.applicationInfo;
//applicable for non-partially installed applications only
if (applicationInfo == null) {
@@ -4021,6 +4056,19 @@
}
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
+ boolean deleteCodeAndResources = false;
+ if (ps.versionCode < p.mVersionCode) {
+ // Delete code and resources for downgrades
+ deleteCodeAndResources = true;
+ if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
+ flags &= ~PackageManager.DONT_DELETE_DATA;
+ }
+ } else {
+ // Preserve data by setting flag
+ if ((flags & PackageManager.DONT_DELETE_DATA) == 0) {
+ flags |= PackageManager.DONT_DELETE_DATA;
+ }
+ }
boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
if (!ret) {
return false;
@@ -4044,6 +4092,28 @@
return true;
}
+ private void deletePackageResourcesLI(String packageName,
+ String sourceDir, String publicSourceDir) {
+ File sourceFile = new File(sourceDir);
+ if (!sourceFile.exists()) {
+ Log.w(TAG, "Package source " + sourceDir + " does not exist.");
+ }
+ // Delete application's code and resources
+ sourceFile.delete();
+ final File publicSourceFile = new File(publicSourceDir);
+ if (publicSourceFile.exists()) {
+ publicSourceFile.delete();
+ }
+ if (mInstaller != null) {
+ int retCode = mInstaller.rmdex(sourceFile.toString());
+ if (retCode < 0) {
+ Log.w(TAG, "Couldn't remove dex file for package: "
+ + packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ }
+ }
+
private boolean deleteInstalledPackageLI(PackageParser.Package p,
boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
ApplicationInfo applicationInfo = p.applicationInfo;
@@ -4051,11 +4121,6 @@
Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
- // Delete application's source directory
- File sourceFile = new File(applicationInfo.sourceDir);
- if (!sourceFile.exists()) {
- Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist.");
- }
outInfo.uid = applicationInfo.uid;
// Delete package data from internal structures and also remove data if flag is set
@@ -4063,19 +4128,8 @@
// Delete application code and resources
if (deleteCodeAndResources) {
- sourceFile.delete();
- final File publicSourceFile = new File(applicationInfo.publicSourceDir);
- if (publicSourceFile.exists()) {
- publicSourceFile.delete();
- }
- if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile.toString());
- if (retCode < 0) {
- Log.w(TAG, "Couldn't remove dex file for package: "
- + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
+ deletePackageResourcesLI(applicationInfo.packageName,
+ applicationInfo.sourceDir, applicationInfo.publicSourceDir);
}
return true;
}
@@ -4123,7 +4177,7 @@
Log.i(TAG, "Removing system package:"+p.packageName);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
- return deleteSystemPackageLI(p, true, flags, outInfo);
+ return deleteSystemPackageLI(p, flags, outInfo);
}
Log.i(TAG, "Removing non-system package:"+p.packageName);
return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
@@ -4518,6 +4572,16 @@
}
}
+ public String getInstallerPackageName(String packageName) {
+ synchronized (mPackages) {
+ PackageSetting pkg = mSettings.mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.installerPackageName;
+ }
+ }
+
public int getApplicationEnabledSetting(String appPackageName) {
synchronized (mPackages) {
PackageSetting pkg = mSettings.mPackages.get(appPackageName);
@@ -5155,6 +5219,7 @@
final String resourcePathString;
private long timeStamp;
private String timeStampString = "0";
+ final int versionCode;
PackageSignatures signatures = new PackageSignatures();
@@ -5166,17 +5231,29 @@
HashSet<String> enabledComponents = new HashSet<String>(0);
int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
int installStatus = PKG_INSTALL_COMPLETE;
+
+ /* package name of the app that installed this package */
+ String installerPackageName;
PackageSettingBase(String name, File codePath, File resourcePath,
- int pkgFlags) {
+ int pVersionCode, int pkgFlags) {
super(pkgFlags);
this.name = name;
this.codePath = codePath;
this.codePathString = codePath.toString();
this.resourcePath = resourcePath;
this.resourcePathString = resourcePath.toString();
+ this.versionCode = pVersionCode;
}
+ public void setInstallerPackageName(String packageName) {
+ installerPackageName = packageName;
+ }
+
+ String getInstallerPackageName() {
+ return installerPackageName;
+ }
+
public void setInstallStatus(int newStatus) {
installStatus = newStatus;
}
@@ -5255,8 +5332,8 @@
SharedUserSetting sharedUser;
PackageSetting(String name, File codePath, File resourcePath,
- int pkgFlags) {
- super(name, codePath, resourcePath, pkgFlags);
+ int pVersionCode, int pkgFlags) {
+ super(name, codePath, resourcePath, pVersionCode, pkgFlags);
}
@Override
@@ -5354,8 +5431,8 @@
final int sharedId;
PendingPackage(String name, File codePath, File resourcePath,
- int sharedId, int pkgFlags) {
- super(name, codePath, resourcePath, pkgFlags);
+ int sharedId, int pVersionCode, int pkgFlags) {
+ super(name, codePath, resourcePath, pVersionCode, pkgFlags);
this.sharedId = sharedId;
}
}
@@ -5379,7 +5456,7 @@
int pkgFlags, boolean create, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLP(name, sharedUser, codePath,
- resourcePath, pkgFlags, create, add);
+ resourcePath, pkg.mVersionCode, pkgFlags, create, add);
if (p != null) {
p.pkg = pkg;
@@ -5387,12 +5464,15 @@
return p;
}
- PackageSetting peekPackageLP(String name, String codePath) {
+ PackageSetting peekPackageLP(String name) {
+ return mPackages.get(name);
+ /*
PackageSetting p = mPackages.get(name);
if (p != null && p.codePath.getPath().equals(codePath)) {
return p;
}
return null;
+ */
}
void setInstallStatus(String pkgName, int status) {
@@ -5404,6 +5484,19 @@
}
}
+ void setInstallerPackageName(String pkgName,
+ String installerPkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ p.setInstallerPackageName(installerPkgName);
+ }
+ }
+
+ String getInstallerPackageName(String pkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ return (p == null) ? null : p.getInstallerPackageName();
+ }
+
int getInstallStatus(String pkgName) {
PackageSetting p = mPackages.get(pkgName);
if(p != null) {
@@ -5464,13 +5557,13 @@
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
PackageSetting ret = addPackageLP(name, p.codePath,
- p.resourcePath, p.userId, p.pkgFlags);
+ p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
mDisabledSysPackages.remove(name);
return ret;
}
PackageSetting addPackageLP(String name, File codePath,
- File resourcePath, int uid, int pkgFlags) {
+ File resourcePath, int uid, int vc, int pkgFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.userId == uid) {
@@ -5480,7 +5573,7 @@
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, codePath, resourcePath, pkgFlags);
+ p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
p.userId = uid;
if (addUserIdLP(uid, p, name)) {
mPackages.put(name, p);
@@ -5510,7 +5603,7 @@
private PackageSetting getPackageLP(String name,
SharedUserSetting sharedUser, File codePath, File resourcePath,
- int pkgFlags, boolean create, boolean add) {
+ int vc, int pkgFlags, boolean create, boolean add) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (!p.codePath.equals(codePath)) {
@@ -5552,8 +5645,9 @@
if (!create) {
return null;
}
- p = new PackageSetting(name, codePath, resourcePath, pkgFlags);
+ p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
p.setTimeStamp(codePath.lastModified());
+ p.sharedUser = sharedUser;
if (sharedUser != null) {
p.userId = sharedUser.userId;
} else if (MULTIPLE_APPLICATION_UIDS) {
@@ -5819,6 +5913,7 @@
serializer.attribute(null, "name", pkg.name);
serializer.attribute(null, "codePath", pkg.codePathString);
serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
@@ -5862,6 +5957,7 @@
(pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
? "true" : "false");
serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId",
Integer.toString(pkg.userId));
@@ -5877,6 +5973,9 @@
if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
serializer.attribute(null, "installStatus", "false");
}
+ if (pkg.installerPackageName != null) {
+ serializer.attribute(null, "installer", pkg.installerPackageName);
+ }
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
serializer.startTag(null, "perms");
@@ -5911,6 +6010,7 @@
}
serializer.endTag(null, "enabled-components");
}
+
serializer.endTag(null, "package");
}
@@ -6053,7 +6153,7 @@
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLP(pp.name,
(SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
- pp.pkgFlags, true, true);
+ pp.versionCode, pp.pkgFlags, true, true);
if (p == null) {
Log.w(TAG, "Unable to create application package for "
+ pp.name);
@@ -6172,12 +6272,20 @@
if(resourcePathStr == null) {
resourcePathStr = codePathStr;
}
+ String version = parser.getAttributeValue(null, "version");
+ int versionCode = 0;
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
int pkgFlags = 0;
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
PackageSetting ps = new PackageSetting(name,
new File(codePathStr),
- new File(resourcePathStr), pkgFlags);
+ new File(resourcePathStr), versionCode, pkgFlags);
String timeStampStr = parser.getAttributeValue(null, "ts");
if (timeStampStr != null) {
try {
@@ -6224,17 +6332,28 @@
String codePathStr = null;
String resourcePathStr = null;
String systemStr = null;
+ String installerPackageName = null;
int pkgFlags = 0;
String timeStampStr;
long timeStamp = 0;
PackageSettingBase packageSetting = null;
+ String version = null;
+ int versionCode = 0;
try {
name = parser.getAttributeValue(null, "name");
idStr = parser.getAttributeValue(null, "userId");
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ version = parser.getAttributeValue(null, "version");
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
systemStr = parser.getAttributeValue(null, "system");
+ installerPackageName = parser.getAttributeValue(null, "installer");
if (systemStr != null) {
if ("true".equals(systemStr)) {
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
@@ -6267,7 +6386,7 @@
+ parser.getPositionDescription());
} else if (userId > 0) {
packageSetting = addPackageLP(name.intern(), new File(codePathStr),
- new File(resourcePathStr), userId, pkgFlags);
+ new File(resourcePathStr), userId, versionCode, pkgFlags);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
+ ": userId=" + userId + " pkg=" + packageSetting);
if (packageSetting == null) {
@@ -6283,7 +6402,7 @@
? Integer.parseInt(sharedIdStr) : 0;
if (userId > 0) {
packageSetting = new PendingPackage(name.intern(), new File(codePathStr),
- new File(resourcePathStr), userId, pkgFlags);
+ new File(resourcePathStr), userId, versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp, timeStampStr);
mPendingPackages.add((PendingPackage) packageSetting);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
@@ -6308,6 +6427,7 @@
+ parser.getPositionDescription());
}
if (packageSetting != null) {
+ packageSetting.installerPackageName = installerPackageName;
final String enabledStr = parser.getAttributeValue(null, "enabled");
if (enabledStr != null) {
if (enabledStr.equalsIgnoreCase("true")) {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 8850c31..348f0a1 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -96,6 +96,11 @@
private int mScanLocksAcquired;
private int mScanLocksReleased;
+ private final List<WifiMulticaster> mMulticasters =
+ new ArrayList<WifiMulticaster>();
+ private int mMulticastEnabled;
+ private int mMulticastDisabled;
+
private final IBatteryStats mBatteryStats;
/**
@@ -1727,21 +1732,9 @@
}
}
- private class WifiLock implements IBinder.DeathRecipient {
- String mTag;
- int mLockMode;
- IBinder mBinder;
-
+ private class WifiLock extends WifiDeathRecipient {
WifiLock(int lockMode, String tag, IBinder binder) {
- super();
- mTag = tag;
- mLockMode = lockMode;
- mBinder = binder;
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
+ super(lockMode, tag, binder);
}
public void binderDied() {
@@ -1751,7 +1744,7 @@
}
public String toString() {
- return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}";
+ return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
}
}
@@ -1771,7 +1764,7 @@
return WifiManager.WIFI_MODE_FULL;
}
for (WifiLock l : mList) {
- if (l.mLockMode == WifiManager.WIFI_MODE_FULL) {
+ if (l.mMode == WifiManager.WIFI_MODE_FULL) {
return WifiManager.WIFI_MODE_FULL;
}
}
@@ -1826,7 +1819,7 @@
int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
- switch(wifiLock.mLockMode) {
+ switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksAcquired;
mBatteryStats.noteFullWifiLockAcquired(uid);
@@ -1862,7 +1855,7 @@
int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
- switch(wifiLock.mLockMode) {
+ switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksReleased;
mBatteryStats.noteFullWifiLockReleased(uid);
@@ -1881,4 +1874,110 @@
updateWifiState();
return hadLock;
}
+
+ private abstract class WifiDeathRecipient
+ implements IBinder.DeathRecipient {
+ String mTag;
+ int mMode;
+ IBinder mBinder;
+
+ WifiDeathRecipient(int mode, String tag, IBinder binder) {
+ super();
+ mTag = tag;
+ mMode = mode;
+ mBinder = binder;
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+ }
+
+ private class WifiMulticaster extends WifiDeathRecipient {
+ WifiMulticaster(String tag, IBinder binder) {
+ super(Binder.getCallingUid(), tag, binder);
+ }
+
+ public void binderDied() {
+ Log.e(TAG, "WifiMulticaster binderDied");
+ synchronized (mMulticasters) {
+ int i = mMulticasters.indexOf(this);
+ if (i != -1) {
+ removeMulticasterLocked(i, mMode);
+ }
+ }
+ }
+
+ public String toString() {
+ return "WifiMulticaster{" + mTag + " binder=" + mBinder + "}";
+ }
+
+ public int getUid() {
+ return mMode;
+ }
+ }
+
+ public void enableWifiMulticast(IBinder binder, String tag) {
+ enforceChangePermission();
+
+ synchronized (mMulticasters) {
+ mMulticastEnabled++;
+ mMulticasters.add(new WifiMulticaster(tag, binder));
+ // Note that we could call stopPacketFiltering only when
+ // our new size == 1 (first call), but this function won't
+ // be called often and by making the stopPacket call each
+ // time we're less fragile and self-healing.
+ WifiNative.stopPacketFiltering();
+ }
+
+ int uid = Binder.getCallingUid();
+ Long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteWifiMulticastEnabled(uid);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void disableWifiMulticast() {
+ enforceChangePermission();
+
+ int uid = Binder.getCallingUid();
+ synchronized (mMulticasters) {
+ mMulticastDisabled++;
+ int size = mMulticasters.size();
+ for (int i = size - 1; i >= 0; i--) {
+ WifiMulticaster m = mMulticasters.get(i);
+ if ((m != null) && (m.getUid() == uid)) {
+ removeMulticasterLocked(i, uid);
+ }
+ }
+ }
+ }
+
+ private void removeMulticasterLocked(int i, int uid)
+ {
+ mMulticasters.remove(i);
+ if (mMulticasters.size() == 0) {
+ WifiNative.startPacketFiltering();
+ }
+
+ Long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteWifiMulticastDisabled(uid);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public boolean isWifiMulticastEnabled() {
+ enforceAccessPermission();
+
+ synchronized (mMulticasters) {
+ return (mMulticasters.size() > 0);
+ }
+ }
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b04f5a8..9471eff 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -169,6 +169,10 @@
static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
+ // The flags that are set for all calls we make to the package manager.
+ static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.GET_SUPPORTS_DENSITIES;
+
private static final String SYSTEM_SECURE = "ro.secure";
// This is the maximum number of application processes we would like
@@ -707,6 +711,11 @@
boolean mSleeping = false;
/**
+ * Set if we are shutting down the system, similar to sleeping.
+ */
+ boolean mShuttingDown = false;
+
+ /**
* Set when the system is going to sleep, until we have
* successfully paused the current activity and released our wake lock.
* At that point the system is allowed to actually sleep.
@@ -868,7 +877,7 @@
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
- if (!mSleeping) {
+ if (!mSleeping && !mShuttingDown) {
Dialog d = new AppErrorDialog(
mContext, res, proc,
(Integer)data.get("flags"),
@@ -1053,7 +1062,7 @@
ApplicationInfo info =
mSelf.mContext.getPackageManager().getApplicationInfo(
- "android", PackageManager.GET_SHARED_LIBRARY_FILES);
+ "android", STOCK_PM_FLAGS);
synchronized (mSelf) {
ProcessRecord app = mSelf.newProcessRecordLocked(
mSystemThread.getApplicationThread(), info,
@@ -1893,7 +1902,7 @@
// If we are not going to sleep, we want to ensure the device is
// awake until the next activity is started.
- if (!mSleeping) {
+ if (!mSleeping && !mShuttingDown) {
mLaunchingActivity.acquire();
if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
// To be safe, don't allow the wake lock to be held for too long.
@@ -1972,12 +1981,15 @@
mPausingActivity = null;
}
- if (!mSleeping) {
+ if (!mSleeping && !mShuttingDown) {
resumeTopActivityLocked(prev);
} else {
if (mGoingToSleep.isHeld()) {
mGoingToSleep.release();
}
+ if (mShuttingDown) {
+ notifyAll();
+ }
}
if (prev != null) {
@@ -2216,7 +2228,7 @@
}
ActivityInfo aInfo =
intent.resolveActivityInfo(mContext.getPackageManager(),
- PackageManager.GET_SHARED_LIBRARY_FILES);
+ STOCK_PM_FLAGS);
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
@@ -2243,7 +2255,8 @@
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
- if (mSleeping && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
+ if ((mSleeping || mShuttingDown)
+ && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mWindowManager.executeAppTransition();
@@ -3172,7 +3185,7 @@
ActivityThread.getPackageManager().resolveIntent(
intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY
- | PackageManager.GET_SHARED_LIBRARY_FILES);
+ | STOCK_PM_FLAGS);
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
@@ -3233,8 +3246,7 @@
List<ResolveInfo> resolves =
ActivityThread.getPackageManager().queryIntentActivities(
intent, r.resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | PackageManager.GET_SHARED_LIBRARY_FILES);
+ PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
// Look for the original activity in the list...
final int N = resolves != null ? resolves.size() : 0;
@@ -3316,8 +3328,7 @@
ResolveInfo rInfo =
ActivityThread.getPackageManager().resolveIntent(
intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | PackageManager.GET_SHARED_LIBRARY_FILES);
+ PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
@@ -4599,7 +4610,8 @@
mWaitForDebugger = mOrigWaitForDebugger;
}
}
- thread.bindApplication(processName, app.info, providers,
+ thread.bindApplication(processName, app.instrumentationInfo != null
+ ? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
mConfiguration, getCommonServicesLocked());
@@ -6642,8 +6654,7 @@
try {
providers = ActivityThread.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
- PackageManager.GET_SHARED_LIBRARY_FILES
- | PackageManager.GET_URI_PERMISSION_PATTERNS);
+ STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (providers != null) {
@@ -6747,7 +6758,8 @@
} else {
try {
cpi = ActivityThread.getPackageManager().
- resolveContentProvider(name, PackageManager.GET_URI_PERMISSION_PATTERNS);
+ resolveContentProvider(name,
+ STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (cpi == null) {
@@ -6768,7 +6780,7 @@
ActivityThread.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
- PackageManager.GET_SHARED_LIBRARY_FILES);
+ STOCK_PM_FLAGS);
if (ai == null) {
Log.w(TAG, "No package info for content provider "
+ cpi.name);
@@ -7098,8 +7110,45 @@
}
}
+ public boolean shutdown(int timeout) {
+ if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SHUTDOWN);
+ }
+
+ boolean timedout = false;
+
+ synchronized(this) {
+ mShuttingDown = true;
+ mWindowManager.setEventDispatching(false);
+
+ if (mResumedActivity != null) {
+ pauseIfSleepingLocked();
+ final long endTime = System.currentTimeMillis() + timeout;
+ while (mResumedActivity != null || mPausingActivity != null) {
+ long delay = endTime - System.currentTimeMillis();
+ if (delay <= 0) {
+ Log.w(TAG, "Activity manager shutdown timed out");
+ timedout = true;
+ break;
+ }
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ mUsageStatsService.shutdown();
+ mBatteryStatsService.shutdown();
+
+ return timedout;
+ }
+
void pauseIfSleepingLocked() {
- if (mSleeping) {
+ if (mSleeping || mShuttingDown) {
if (!mGoingToSleep.isHeld()) {
mGoingToSleep.acquire();
if (mLaunchingActivity.isHeld()) {
@@ -7467,7 +7516,7 @@
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
- 0);
+ STOCK_PM_FLAGS);
CharSequence errorMsg = null;
if (ri != null) {
ActivityInfo ai = ri.activityInfo;
@@ -7503,7 +7552,7 @@
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
List apps = ActivityThread.getPackageManager().
- getPersistentApplications(PackageManager.GET_SHARED_LIBRARY_FILES);
+ getPersistentApplications(STOCK_PM_FLAGS);
if (apps != null) {
int N = apps.size();
int i;
@@ -8064,7 +8113,7 @@
+ " mBooting=" + mBooting
+ " mBooted=" + mBooted
+ " mFactoryTest=" + mFactoryTest);
- pw.println(" mSleeping=" + mSleeping);
+ pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
pw.println(" mGoingToSleep=" + mGoingToSleep);
pw.println(" mLaunchingActivity=" + mLaunchingActivity);
pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
@@ -8918,7 +8967,7 @@
try {
ResolveInfo rInfo =
ActivityThread.getPackageManager().resolveService(
- service, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES);
+ service, resolvedType, STOCK_PM_FLAGS);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
@@ -10136,7 +10185,7 @@
if (intent.getComponent() != null) {
// Broadcast is going to one specific receiver class...
ActivityInfo ai = ActivityThread.getPackageManager().
- getReceiverInfo(intent.getComponent(), 0);
+ getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
if (ai != null) {
receivers = new ArrayList();
ResolveInfo ri = new ResolveInfo();
@@ -10149,7 +10198,7 @@
== 0) {
receivers =
ActivityThread.getPackageManager().queryIntentReceivers(
- intent, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES);
+ intent, resolvedType, STOCK_PM_FLAGS);
}
registeredReceivers = mReceiverResolver.queryIntent(resolver,
intent, resolvedType, false);
@@ -10886,9 +10935,9 @@
ApplicationInfo ai = null;
try {
ii = mContext.getPackageManager().getInstrumentationInfo(
- className, 0);
+ className, STOCK_PM_FLAGS);
ai = mContext.getPackageManager().getApplicationInfo(
- ii.targetPackage, PackageManager.GET_SHARED_LIBRARY_FILES);
+ ii.targetPackage, STOCK_PM_FLAGS);
} catch (PackageManager.NameNotFoundException e) {
}
if (ii == null) {
@@ -10920,6 +10969,7 @@
uninstallPackageLocked(ii.targetPackage, -1, true);
ProcessRecord app = addAppLocked(ai);
app.instrumentationClass = className;
+ app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
app.instrumentationArguments = arguments;
app.instrumentationWatcher = watcher;
@@ -10967,6 +11017,7 @@
}
app.instrumentationWatcher = null;
app.instrumentationClass = null;
+ app.instrumentationInfo = null;
app.instrumentationProfileFile = null;
app.instrumentationArguments = null;
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index ddc3e68..0387be5 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -25,8 +25,7 @@
import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
-import android.telephony.TelephonyManager;
-import android.util.PrintWriterPrinter;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -50,6 +49,13 @@
ServiceManager.addService("batteryinfo", asBinder());
}
+ public void shutdown() {
+ Log.w("BatteryStats", "Writing battery stats before shutdown...");
+ synchronized (mStats) {
+ mStats.writeLocked();
+ }
+ }
+
public static IBatteryStats getService() {
if (sService != null) {
return sService;
@@ -255,6 +261,20 @@
}
}
+ public void noteWifiMulticastEnabled(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastEnabledLocked(uid);
+ }
+ }
+
+ public void noteWifiMulticastDisabled(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastDisabledLocked(uid);
+ }
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index b76547a..68aebc3 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.PrintWriterPrinter;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -62,6 +63,7 @@
IBinder forcingToForeground;// Token that is forcing this process to be foreground
int adjSeq; // Sequence id for identifying repeated trav
ComponentName instrumentationClass;// class installed to instrument app
+ ApplicationInfo instrumentationInfo; // the application being instrumented
String instrumentationProfileFile; // where to save profiling
IInstrumentationWatcher instrumentationWatcher; // who is waiting
Bundle instrumentationArguments;// as given to us
@@ -125,6 +127,11 @@
pw.println(instrumentationProfileFile);
pw.print(prefix); pw.print("instrumentationArguments=");
pw.println(instrumentationArguments);
+ pw.print(prefix); pw.print("instrumentationInfo=");
+ pw.println(instrumentationInfo);
+ if (instrumentationInfo != null) {
+ instrumentationInfo.dump(new PrintWriterPrinter(pw), prefix + " ");
+ }
}
pw.print(prefix); pw.print("thread="); pw.print(thread);
pw.print(" curReceiver="); pw.println(curReceiver);
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index b6f9158..866334b 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import com.android.internal.app.IUsageStats;
+
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
@@ -418,6 +419,11 @@
ServiceManager.addService(SERVICE_NAME, asBinder());
}
+ public void shutdown() {
+ Log.w(TAG, "Writing usage stats before shutdown...");
+ writeStatsToFile(true);
+ }
+
public static IUsageStats getService() {
if (sService != null) {
return sService;
diff --git a/services/java/com/android/server/status/IconMerger.java b/services/java/com/android/server/status/IconMerger.java
index 37fdbfb..5b80638 100644
--- a/services/java/com/android/server/status/IconMerger.java
+++ b/services/java/com/android/server/status/IconMerger.java
@@ -8,8 +8,6 @@
public class IconMerger extends LinearLayout {
- private static final boolean SPEW = false;
-
StatusBarService service;
StatusBarIcon moreIcon;
@@ -29,7 +27,7 @@
int fitRight = -1;
for (i=N-1; i>=0; i--) {
final View child = getChildAt(i);
- if (child != null && child.getVisibility() != GONE) {
+ if (child.getVisibility() != GONE) {
fitRight = child.getRight();
break;
}
@@ -45,7 +43,7 @@
moreView = child;
startIndex = i+1;
}
- else if (child != null && child.getVisibility() != GONE) {
+ else if (child.getVisibility() != GONE) {
fitLeft = child.getLeft();
break;
}
@@ -71,7 +69,7 @@
int number = 0;
for (i=startIndex; i<N; i++) {
final View child = getChildAt(i);
- if (child != null && child.getVisibility() != GONE) {
+ if (child.getVisibility() != GONE) {
int childLeft = child.getLeft();
int childRight = child.getRight();
if (childLeft < breakingPoint) {
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 0b161d6..b17ba82 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -78,10 +78,7 @@
private static final int EVENT_DATA_ACTIVITY = 3;
private static final int EVENT_BATTERY_CLOSE = 4;
- // indices into mBatteryThresholds
- private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
- private static final int BATTERY_THRESHOLD_WARNING = 1;
- private static final int BATTERY_THRESHOLD_EMPTY = 2;
+ private static final int BATTERY_LEVEL_CLOSE_WARNING = 20;
private final Context mContext;
private final StatusBarService mService;
@@ -99,8 +96,6 @@
private boolean mBatteryFirst = true;
private boolean mBatteryPlugged;
private int mBatteryLevel;
- private int mBatteryThreshold = 0; // index into mBatteryThresholds
- private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
private AlertDialog mLowBatteryDialog;
private TextView mBatteryLevelTextView;
private View mBatteryView;
@@ -276,6 +271,9 @@
else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
updateBattery(intent);
}
+ else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+ onBatteryLow(intent);
+ }
else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
@@ -403,6 +401,7 @@
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
@@ -446,19 +445,6 @@
//mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
}
- private void pickNextBatteryLevel(int level) {
- final int N = mBatteryThresholds.length;
- for (int i=0; i<N; i++) {
- if (level >= mBatteryThresholds[i]) {
- mBatteryThreshold = i;
- break;
- }
- }
- if (mBatteryThreshold >= N) {
- mBatteryThreshold = N-1;
- }
- }
-
private final void updateBattery(Intent intent) {
mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
@@ -471,13 +457,10 @@
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
- + " mBatteryThreshold=" + mBatteryThreshold
+ " mBatteryFirst=" + mBatteryFirst);
}
boolean oldPlugged = mBatteryPlugged;
- int oldThreshold = mBatteryThreshold;
- pickNextBatteryLevel(level);
mBatteryPlugged = plugged;
mBatteryLevel = level;
@@ -499,35 +482,29 @@
}
*/
if (false) {
- Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
- + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
+ Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
- if (!plugged
- && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
- || (mBatteryThreshold > oldThreshold
- && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
- // Broadcast the low battery warning
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
- if (SHOW_LOW_BATTERY_WARNING) {
- if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
- + " mLowBatteryDialog=" + mLowBatteryDialog
- + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
- }
+ if (mLowBatteryDialog != null
+ && mBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING
+ && SHOW_LOW_BATTERY_WARNING) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
+ }
+ }
- if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
- showLowBatteryWarning();
- } else {
- mBatteryShowLowOnEndCall = true;
- }
+ private void onBatteryLow(Intent intent) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (false) {
+ Log.d(TAG, "mPhoneState=" + mPhoneState
+ + " mLowBatteryDialog=" + mLowBatteryDialog
+ + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
- } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) {
- if (SHOW_LOW_BATTERY_WARNING) {
- if (mLowBatteryDialog != null) {
- mLowBatteryDialog.dismiss();
- mBatteryShowLowOnEndCall = false;
- }
+
+ if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ showLowBatteryWarning();
+ } else {
+ mBatteryShowLowOnEndCall = true;
}
}
}
@@ -593,9 +570,11 @@
private void showLowBatteryWarning() {
closeLastBatteryView();
- int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0];
+ /* Show exact battery level.
+ * Add 1 because the text says "less than X%".
+ */
CharSequence levelText = mContext.getString(
- com.android.internal.R.string.battery_low_percent_format, level);
+ com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
if (mBatteryLevelTextView != null) {
mBatteryLevelTextView.setText(levelText);
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index aec7238..5a1bb7e 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1023,6 +1023,21 @@
*/
void setLocationUpdates(boolean enable, Message response);
+ /**
+ * Gets the default SMSC address.
+ *
+ * @param result Callback message contains the SMSC address.
+ */
+ void getSmscAddress(Message result);
+
+ /**
+ * Sets the default SMSC address.
+ *
+ * @param address new SMSC address
+ * @param result Callback message is empty on completion
+ */
+ void setSmscAddress(String address, Message result);
+
void invokeOemRilRequestRaw(byte[] data, Message response);
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 3f210ca..03c1c56 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -925,6 +925,21 @@
void getPreferredNetworkType(Message response);
/**
+ * Gets the default SMSC address.
+ *
+ * @param result Callback message contains the SMSC address.
+ */
+ void getSmscAddress(Message result);
+
+ /**
+ * Sets the default SMSC address.
+ *
+ * @param address new SMSC address
+ * @param result Callback message is empty on completion
+ */
+ void setSmscAddress(String address, Message result);
+
+ /**
* Query neighboring cell IDs. <code>response</code> is dispatched when
* this is complete. <code>response.obj</code> will be an AsyncResult,
* and <code>response.obj.exception</code> will be non-null on failure.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 1ff0f7e..0314034 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -574,6 +574,14 @@
mCM.getPreferredNetworkType(response);
}
+ public void getSmscAddress(Message result) {
+ mCM.getSmscAddress(result);
+ }
+
+ public void setSmscAddress(String address, Message result) {
+ mCM.setSmscAddress(address, result);
+ }
+
public void setTTYModeEnabled(boolean enable, Message onComplete) {
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index dd36f0b..b76d801 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -671,5 +671,13 @@
public void notifyDataActivity() {
mActivePhone.notifyDataActivity();
}
+
+ public void getSmscAddress(Message result) {
+ mActivePhone.getSmscAddress(result);
+ }
+
+ public void setSmscAddress(String address, Message result) {
+ mActivePhone.setSmscAddress(address, result);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3123111..be18a39 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1760,6 +1760,32 @@
send(rr);
}
+ /**
+ * {@inheritDoc}
+ */
+ public void getSmscAddress(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SMSC_ADDRESS, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSmscAddress(String address, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SMSC_ADDRESS, result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(address);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " : " + address);
+
+ send(rr);
+ }
+
//***** Private Methods
private void sendScreenState(boolean on) {
@@ -2027,6 +2053,8 @@
case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break;
case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break;
case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break;
+ case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break;
+ case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break;
default:
throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
//break;
@@ -2885,6 +2913,8 @@
case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM";
case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM";
case RIL_REQUEST_DEVICE_IDENTITY: return "RIL_REQUEST_DEVICE_IDENTITY";
+ case RIL_REQUEST_GET_SMSC_ADDRESS: return "RIL_REQUEST_GET_SMSC_ADDRESS";
+ case RIL_REQUEST_SET_SMSC_ADDRESS: return "RIL_REQUEST_SET_SMSC_ADDRESS";
default: return "<unknown request>";
}
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index cbbdec6..bcf5141 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -208,6 +208,8 @@
int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96;
int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97;
int RIL_REQUEST_DEVICE_IDENTITY = 98;
+ int RIL_REQUEST_GET_SMSC_ADDRESS = 100;
+ int RIL_REQUEST_SET_SMSC_ADDRESS = 101;
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index cb09cea..5c69017 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1001,6 +1001,14 @@
unimplemented(response);
}
+ public void getSmscAddress(Message result) {
+ unimplemented(result);
+ }
+
+ public void setSmscAddress(String address, Message result) {
+ unimplemented(result);
+ }
+
private boolean isSimLocked() {
if (mSimLockedState != SimLockState.NONE) {
return true;
diff --git a/test-runner/android/test/mock/MockContentProvider.java b/test-runner/android/test/mock/MockContentProvider.java
index f40329d..fdba2e2 100644
--- a/test-runner/android/test/mock/MockContentProvider.java
+++ b/test-runner/android/test/mock/MockContentProvider.java
@@ -18,7 +18,8 @@
import android.content.ContentValues;
import android.content.IContentProvider;
-import android.content.ISyncAdapter;
+import android.content.Entity;
+import android.content.EntityIterator;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
@@ -48,6 +49,10 @@
return 0;
}
+ public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, IContentObserver observer,
@@ -89,12 +94,21 @@
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public int update(Uri url, ContentValues values, String selection, String[] selectionArgs)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
public IBinder asBinder() {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index ea190e2..2236663 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -284,9 +284,17 @@
throw new UnsupportedOperationException();
}
+ /**
+ * @hide - to match hiding in superclass
+ */
@Override
public void installPackage(Uri packageURI, IPackageInstallObserver observer,
- int flags) {
+ int flags, String installerPackageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();
}
@@ -391,11 +399,6 @@
}
@Override
- public void installPackage(Uri packageURI) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
throw new UnsupportedOperationException();
diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java
index b64c156..9db6077 100644
--- a/tests/CoreTests/android/core/SocketTest.java
+++ b/tests/CoreTests/android/core/SocketTest.java
@@ -178,29 +178,35 @@
SocketChannel.open();
}
- // Regression test for issue 1018016, connecting ignored a set timeout.
- @LargeTest
- public void testSocketSetSOTimeout() throws IOException {
- Socket sock = new Socket();
- int timeout = 5000;
- long start = System.currentTimeMillis();
- try {
- sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
- } catch (SocketTimeoutException e) {
- // expected
- long delay = System.currentTimeMillis() - start;
- if (Math.abs(delay - timeout) > 1000) {
- fail("timeout was not accurate. expected: " + timeout
- + " actual: " + delay + " miliseconds.");
- }
- } finally {
- try {
- sock.close();
- } catch (IOException ioe) {
- // ignore
- }
- }
- }
+// Regression test for issue 1018016, connecting ignored a set timeout.
+//
+// Disabled because test behaves differently depending on networking
+// environment. It works fine in the emulator and one the device with
+// WLAN, but when 3G comes into play, the possible existence of a
+// proxy makes it fail.
+//
+// @LargeTest
+// public void testSocketSetSOTimeout() throws IOException {
+// Socket sock = new Socket();
+// int timeout = 5000;
+// long start = System.currentTimeMillis();
+// try {
+// sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
+// } catch (SocketTimeoutException e) {
+// // expected
+// long delay = System.currentTimeMillis() - start;
+// if (Math.abs(delay - timeout) > 1000) {
+// fail("timeout was not accurate. expected: " + timeout
+// + " actual: " + delay + " miliseconds.");
+// }
+// } finally {
+// try {
+// sock.close();
+// } catch (IOException ioe) {
+// // ignore
+// }
+// }
+// }
/**
* Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1)
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index 17c44ad..0e33d62 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -31,4 +31,5 @@
android:targetPackage="com.android.dumprendertree"
android:label="Layout test automation runner"
/>
+ <uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
diff --git a/tests/DumpRenderTree/assets/run_reliability_tests.py b/tests/DumpRenderTree/assets/run_reliability_tests.py
new file mode 100755
index 0000000..a242293
--- /dev/null
+++ b/tests/DumpRenderTree/assets/run_reliability_tests.py
@@ -0,0 +1,214 @@
+#!/usr/bin/python2.4
+
+"""Run reliability tests using Android instrumentation.
+
+ A test file consists of list web sites to test is needed as a parameter
+
+ Usage:
+ run_reliability_tests.py path/to/url/list
+"""
+
+import logging
+import optparse
+import random
+import subprocess
+import sys
+import time
+
+TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt"
+TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt"
+TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt"
+HTTP_URL_FILE = "urllist_http"
+HTTPS_URL_FILE = "urllist_https"
+NUM_URLS = 25
+
+
+def DumpRenderTreeFinished(adb_cmd):
+ """Check if DumpRenderTree finished running.
+
+ Args:
+ adb_cmd: adb command string
+
+ Returns:
+ True if DumpRenderTree has finished, False otherwise
+ """
+
+ # pull test status file and look for "#DONE"
+ shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
+ adb_output = subprocess.Popen(shell_cmd_str,
+ shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+ return adb_output.strip() == "#DONE"
+
+
+def RandomPick(file_name, approx_size, num_needed):
+ """Randomly pick lines from the text file specifed.
+
+ Args:
+ file_name: the text file where lines should be picked from
+ approx_size: an approximate size of the text file
+ num_needed: how many lines are needed from the file
+
+ Returns:
+ an array of string
+ """
+ p = float(num_needed) / approx_size
+ num_picked = 0
+ lines = []
+ random.seed()
+
+ while num_picked < num_needed:
+ file_handle = open(file_name, "r")
+ for line in file_handle:
+ line = line.strip()
+ if float(random.randint(0, approx_size)) / approx_size < p:
+ lines.append(line)
+ num_picked += 1
+ if num_picked == num_needed:
+ break
+ file_handle.close()
+ return lines
+
+
+def main(options, args):
+ """Send the url list to device and start testing, restart if crashed."""
+
+ generate_url = False
+
+ # Set up logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format="%(message)s")
+
+ # Include all tests if none are specified.
+ if not args:
+ path = "/tmp/url_list_%d.txt" % time.time()
+ generate_url = True
+ logging.info("A URL list is not provided, will be automatically generated.")
+ else:
+ path = args[0]
+
+ if not options.crash_file:
+ print "missing crash file name, use --crash-file to specify"
+ sys.exit(1)
+ else:
+ crashed_file = options.crash_file
+
+ if not options.timeout_file:
+ print "missing timeout file, use --timeout-file to specify"
+ sys.exit(1)
+ else:
+ timedout_file = options.timeout_file
+
+ http = RandomPick(HTTP_URL_FILE, 500000, NUM_URLS)
+ https = RandomPick(HTTPS_URL_FILE, 45000, NUM_URLS)
+
+ if generate_url:
+ file_handle = open(path, "w")
+ for i in range(0, NUM_URLS):
+ file_handle.write(http[i] + "\n")
+ file_handle.write(https[i] + "\n")
+ file_handle.close()
+
+ adb_cmd = "adb "
+ if options.adb_options:
+ adb_cmd += options.adb_options + " "
+
+ # push url list to device
+ test_cmd = adb_cmd + " push \"" + path + "\" \"" + TEST_LIST_FILE + "\""
+ proc = subprocess.Popen(test_cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (adb_output, adb_error) = proc.communicate()
+ if proc.returncode != 0:
+ logging.error("failed to push url list to device.")
+ logging.error(adb_output)
+ logging.error(adb_error)
+ sys.exit(1)
+
+ logging.info("Running the test ...")
+
+ # Count crashed tests.
+ crashed_tests = []
+
+ if options.time_out_ms:
+ timeout_ms = options.time_out_ms
+
+ # Run test until it's done
+ test_cmd_prefix = adb_cmd + " shell am instrument"
+ test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+ # Call ReliabilityTestsAutoTest#startReliabilityTests
+ test_cmd = (test_cmd_prefix + " -e class "
+ "com.android.dumprendertree.ReliabilityTestsAutoTest#"
+ "startReliabilityTests -e timeout " + timeout_ms
+ + test_cmd_postfix)
+
+ time_start = time.time()
+ adb_output = subprocess.Popen(test_cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+ while not DumpRenderTreeFinished(adb_cmd):
+ logging.error("DumpRenderTree exited before all URLs are visited.")
+ shell_cmd_str = adb_cmd + " shell cat " + TEST_STATUS_FILE
+ crashed_test = subprocess.Popen(shell_cmd_str, shell=True,
+ stdout=subprocess.PIPE).communicate()[0]
+ logging.info(crashed_test + " CRASHED")
+ crashed_tests.append(crashed_test)
+ logging.info("Resuming reliability test runner...")
+
+ test_cmd = (test_cmd_prefix + " -e class "
+ "com.android.dumprendertree.ReliabilityTestsAutoTest#"
+ "resumeReliabilityTests -e timeout " + timeout_ms
+ + test_cmd_postfix)
+ adb_output = subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+
+ time_end = time.time()
+ fp = open("time_stat", "a")
+ fp.writelines("%.2f\n" % ((time_end - time_start) / NUM_URLS / 2))
+ fp.close()
+ if (adb_output.find("INSTRUMENTATION_FAILED") != -1 or
+ adb_output.find("Process crashed.") != -1):
+ logging.error("Error happened : " + adb_output)
+ sys.exit(1)
+
+ logging.info(adb_output)
+ logging.info("Done\n")
+
+ if crashed_tests:
+ file_handle = open(crashed_file, "w")
+ file_handle.writelines("\n".join(crashed_tests))
+ logging.info("Crashed URL list stored in: " + crashed_file)
+ file_handle.close()
+ else:
+ logging.info("No crash found.")
+
+ test_cmd = (adb_cmd + "pull \"" + TEST_TIMEOUT_FILE + "\" \""
+ + timedout_file + "\"")
+
+ subprocess.Popen(test_cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()
+
+
+if "__main__" == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--time-out-ms",
+ default=60000,
+ help="set the timeout for each test")
+ option_parser.add_option("", "--verbose", action="store_true",
+ default=False,
+ help="include debug-level logging")
+ option_parser.add_option("", "--adb-options",
+ default=None,
+ help="pass options to adb, such as -d -e, etc")
+ option_parser.add_option("", "--crash-file",
+ default="reliability_crashed_sites.txt",
+ help="the list of sites that cause browser to crash")
+ option_parser.add_option("", "--timeout-file",
+ default="reliability_timedout_sites.txt",
+ help="the list of sites that timedout during test.")
+ opts, arguments = option_parser.parse_args()
+ main(opts, arguments)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 562b1f3..caef861 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -41,6 +41,7 @@
private BufferedOutputStream mBufferedOutputPassedStream;
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
+ private BufferedOutputStream mBufferedOutputTimedoutStream;
public void passed(String layout_file) {
try {
@@ -72,11 +73,22 @@
}
}
+ public void timedout(String url) {
+ try {
+ mBufferedOutputTimedoutStream.write(url.getBytes());
+ mBufferedOutputTimedoutStream.write('\n');
+ mBufferedOutputTimedoutStream.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
+ File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
@@ -84,6 +96,8 @@
new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
mBufferedOutputNoresultStream =
new BufferedOutputStream(new FileOutputStream(noExpectedResultFile, resume));
+ mBufferedOutputTimedoutStream =
+ new BufferedOutputStream(new FileOutputStream(resultTimedoutFile, resume));
} catch (Exception e) {
e.printStackTrace();
}
@@ -94,6 +108,7 @@
mBufferedOutputPassedStream.close();
mBufferedOutputFailedStream.close();
mBufferedOutputNoresultStream.close();
+ mBufferedOutputTimedoutStream.close();
} catch (Exception e) {
e.printStackTrace();
}
@@ -281,7 +296,10 @@
mFinished = true;
LayoutTestsAutoTest.this.notifyAll();
}
- }
+ }
+
+ public void timedOut(String url) {
+ }
});
String resultFile = getResultFile(test);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index 5cb5155..81cf3a8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -42,7 +42,7 @@
private boolean mFinished;
static final String LOAD_TEST_RUNNER_FILES[] = {
"run_page_cycler.py"
- };
+ };
public LoadTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
@@ -134,6 +134,9 @@
LoadTestsAutoTest.this.notifyAll();
}
}
+
+ public void timedOut(String url) {
+ }
});
mFinished = false;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java
new file mode 100644
index 0000000..347efde
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestsAutoTest.java
@@ -0,0 +1,209 @@
+package com.android.dumprendertree;
+
+import com.android.dumprendertree.TestShellActivity.DumpDataType;
+
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Vector;
+
+public class ReliabilityTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
+
+ private static final String LOGTAG = "ReliabilityTests";
+ private static final String TEST_LIST_FILE = "/sdcard/android/reliability_tests_list.txt";
+ private static final String TEST_STATUS_FILE = "/sdcard/android/reliability_running_test.txt";
+ private static final String TEST_TIMEOUT_FILE = "/sdcard/android/reliability_timeout_test.txt";
+ static final String RELIABILITY_TEST_RUNNER_FILES[] = {
+ "run_reliability_tests.py"
+ };
+
+ private boolean finished;
+ private List<String> testList;
+
+ public ReliabilityTestsAutoTest() {
+ super("com.android.dumprendertree", TestShellActivity.class);
+ }
+
+ private void getTestList() {
+ // Read test list.
+ testList = new Vector<String>();
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(TEST_LIST_FILE));
+ String line;
+ while ((line = inReader.readLine()) != null) {
+ testList.add(line);
+ }
+ inReader.close();
+ Log.v(LOGTAG, "Test list has " + testList.size() + " test(s).");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
+ }
+ }
+
+ private void resumeTestList() {
+ // read out the test name it stopped last time.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
+ String line = inReader.readLine();
+ for (int i = 0; i < testList.size(); i++) {
+ if (testList.get(i).equals(line)) {
+ testList = new Vector<String>(testList.subList(i+1, testList.size()));
+ break;
+ }
+ }
+ inReader.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
+ }
+ }
+
+ private void clearTestStatus() {
+ // Delete TEST_STATUS_FILE
+ try {
+ File f = new File(TEST_STATUS_FILE);
+ if (f.delete())
+ Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
+ else
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
+ }
+ }
+
+ private void clearTestTimeout() {
+ // Delete TEST_TIMEOUT_FILE
+ try {
+ File f = new File(TEST_TIMEOUT_FILE);
+ if (f.delete())
+ Log.v(LOGTAG, "Deleted " + TEST_TIMEOUT_FILE);
+ else
+ Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Fail to delete " + TEST_TIMEOUT_FILE + " : " + e.getMessage());
+ }
+ }
+
+ private void updateTestStatus(String s) {
+ // Write TEST_STATUS_FILE
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
+ bos.write(s.getBytes());
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
+ }
+ }
+
+ private void writeTimeoutFile(String s) {
+ // Write TEST_TIMEOUT_FILE
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_TIMEOUT_FILE, true));
+ bos.write(s.getBytes());
+ bos.write('\n');
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Cannot update file " + TEST_TIMEOUT_FILE);
+ }
+ }
+
+ private void runReliabilityTest(boolean resume) {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+
+ getTestList();
+ if(!resume)
+ clearTestStatus();
+ else
+ resumeTestList();
+
+ TestShellActivity activity = getActivity();
+ activity.setDefaultDumpDataType(DumpDataType.NO_OP);
+ // Run tests.
+ for (int i = 0; i < testList.size(); i++) {
+ String s = testList.get(i);
+ updateTestStatus(s);
+ // Run tests
+ runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis);
+ }
+
+ updateTestStatus("#DONE");
+
+ activity.finish();
+ }
+
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
+ activity.setCallback(new TestShellCallback() {
+ public void finished() {
+ synchronized (ReliabilityTestsAutoTest.this) {
+ finished = true;
+ ReliabilityTestsAutoTest.this.notifyAll();
+ }
+ }
+
+ public void timedOut(String url) {
+ writeTimeoutFile(url);
+ }
+ });
+
+ finished = false;
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(activity, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, url);
+ intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ activity.startActivity(intent);
+
+ // Wait until done.
+ synchronized (this) {
+ while(!finished){
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+ }
+ }
+
+ public void startReliabilityTests() {
+ clearTestTimeout();
+ runReliabilityTest(false);
+ }
+
+ public void resumeReliabilityTests() {
+ runReliabilityTest(true);
+ }
+
+ public void copyRunnerAssetsToCache() {
+ try {
+ String out_dir = getActivity().getApplicationContext()
+ .getCacheDir().getPath() + "/";
+
+ for( int i=0; i< RELIABILITY_TEST_RUNNER_FILES.length; i++) {
+ InputStream in = getActivity().getAssets().open(
+ RELIABILITY_TEST_RUNNER_FILES[i]);
+ OutputStream out = new FileOutputStream(
+ out_dir + RELIABILITY_TEST_RUNNER_FILES[i]);
+
+ byte[] buf = new byte[2048];
+ int len;
+
+ while ((len = in.read(buf)) >= 0 ) {
+ out.write(buf, 0, len);
+ }
+ out.close();
+ in.close();
+ }
+ }catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 404d101..1ba291c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -16,29 +16,40 @@
package com.android.dumprendertree;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.webkit.HttpAuthHandler;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;
-import android.app.Activity;
-import android.content.Intent;
-import android.util.Log;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.view.ViewGroup;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.widget.LinearLayout;
-import android.os.*;
-
public class TestShellActivity extends Activity implements LayoutTestController {
+
+ static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
+
public class AsyncHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_TIMEOUT) {
mTimedOut = true;
+ mCallback.timedOut(mWebView.getUrl());
requestWebKitData();
return;
} else if (msg.what == MSG_WEBKIT_DATA) {
@@ -57,10 +68,16 @@
throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
mRequestedWebKitData = true;
- if (mDumpAsText) {
- mWebView.documentAsText(callback);
- } else {
- mWebView.externalRepresentation(callback);
+ switch (mDumpDataType) {
+ case DUMP_AS_TEXT:
+ mWebView.documentAsText(callback);
+ break;
+ case EXT_REPR:
+ mWebView.externalRepresentation(callback);
+ break;
+ default:
+ finished();
+ break;
}
}
@@ -75,6 +92,41 @@
mWebView = new WebView(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebChromeClient(mChromeClient);
+ mWebView.setWebViewClient(new WebViewClient(){
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ Log.v(LOGTAG, "onPageFinished, url=" + url);
+ super.onPageFinished(view, url);
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ Log.v(LOGTAG, "onPageStarted, url=" + url);
+ super.onPageStarted(view, url, favicon);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
+ + ", desc=" + description + ", url=" + failingUrl);
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
+ String host, String realm) {
+ handler.cancel();
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ handler.proceed();
+ }
+
+ });
mEventSender = new WebViewEventSender(mWebView);
mCallbackProxy = new CallbackProxy(mEventSender, this);
@@ -186,10 +238,14 @@
}
}
+ public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) {
+ mDefaultDumpDataType = defaultDumpDataType;
+ }
+
// .......................................
// LayoutTestController Functions
public void dumpAsText() {
- mDumpAsText = true;
+ mDumpDataType = DumpDataType.DUMP_AS_TEXT;
if (mWebView != null) {
String url = mWebView.getUrl();
Log.v(LOGTAG, "dumpAsText called: "+url);
@@ -382,7 +438,7 @@
private void resetTestStatus() {
mWaitUntilDone = false;
- mDumpAsText = false;
+ mDumpDataType = mDefaultDumpDataType;
mTimedOut = false;
mDumpTitleChanges = false;
mRequestedWebKitData = false;
@@ -406,7 +462,8 @@
private boolean mFinishedRunning;
// Layout test controller variables.
- private boolean mDumpAsText;
+ private DumpDataType mDumpDataType;
+ private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR;
private boolean mWaitUntilDone;
private boolean mDumpTitleChanges;
private StringBuffer mTitleChanges;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
index 759c443..55bf947 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
@@ -18,4 +18,5 @@
public interface TestShellCallback {
public void finished();
+ public void timedOut(String url);
}
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index de68cb7..af7dfd4 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -83,6 +83,27 @@
bm.dataChanged();
}
},
+ new Test("Clear File") {
+ void run() {
+ PrintStream output = null;
+ try {
+ output = new PrintStream(openFileOutput(FILE_NAME, MODE_PRIVATE));
+ output.close();
+ } catch (IOException ex) {
+ if (output != null) {
+ output.close();
+ }
+ }
+ BackupManager bm = new BackupManager(BackupTestActivity.this);
+ bm.dataChanged();
+ }
+ },
+ new Test("Poke") {
+ void run() {
+ BackupManager bm = new BackupManager(BackupTestActivity.this);
+ bm.dataChanged();
+ }
+ },
new Test("Show Shared Pref") {
void run() {
SharedPreferences prefs = getSharedPreferences(PREF_GROUP_SETTINGS, MODE_PRIVATE);
diff --git a/tests/backup/src/com/android/backuptest/BackupTestService.java b/tests/backup/src/com/android/backuptest/BackupTestService.java
index 99f3e55..00eb86e 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestService.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestService.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.example.android.apis.app;
+package com.android.backuptest;
import android.backup.BackupService;
+import android.backup.BackupDataOutput;
+import android.backup.FileBackupHelper;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -25,10 +27,12 @@
static final String TAG = "BackupTestService";
@Override
- public void onBackup(ParcelFileDescriptor oldState,
- ParcelFileDescriptor data,
- ParcelFileDescriptor newState) {
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) {
Log.d(TAG, "onBackup");
+ FileBackupHelper.performBackup(this, oldState, data, newState, new String[] {
+ BackupTestActivity.FILE_NAME
+ });
}
@Override
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a09b1a6..ef11a83 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1225,7 +1225,7 @@
// pseudolocalize here
block.setPosition(parserPosition);
err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
- ident, *curTag, curIsStyled, curFormat, true, false, outTable);
+ ident, *curTag, curIsStyled, curFormat, true, overwrite, outTable);
if (err != NO_ERROR) {
hasErrors = localHasErrors = true;
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f9a0845..00829d6 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -69,5 +69,11 @@
boolean acquireWifiLock(IBinder lock, int lockType, String tag);
boolean releaseWifiLock(IBinder lock);
+
+ boolean isWifiMulticastEnabled();
+
+ void enableWifiMulticast(IBinder binder, String tag);
+
+ void disableWifiMulticast();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a51e88f..658a7b2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -823,4 +823,65 @@
public WifiLock createWifiLock(String tag) {
return new WifiLock(WIFI_MODE_FULL, tag);
}
+
+ /**
+ * Check multicast filter status.
+ *
+ * @return true if multicast packets are allowed.
+ *
+ * @hide pending API council approval
+ */
+ public boolean isWifiMulticastEnabled() {
+ try {
+ return mService.isWifiMulticastEnabled();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Turn on the reception of multicast packets.
+ * The default behavior is to disable multicast packets as they
+ * have a noticable negative effect on battery life. An
+ * application can turn them on, but should not leave it on for longer
+ * than needed. When the app quits (or crashes) its request will
+ * be reverted.
+ *
+ * @param tag a string associated with this request for debugging.
+ *
+ * @return true on success
+ *
+ * @see #disableWifiMulticast
+ *
+ * @hide pending API council approval
+ */
+ public boolean enableWifiMulticast(String tag) {
+ try {
+ mService.enableWifiMulticast(new Binder(), tag);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Return to the default multicast-off setting.
+ * Note that if others had turned on Multicast reception, your
+ * call will not turn it back off - they must also turn off their
+ * request for multicast reception.
+ *
+ * @return true on success
+ *
+ * @see #enableWifiMulticast
+ *
+ * @hide pending API council approval
+ */
+ public boolean disableWifiMulticast() {
+ try {
+ mService.disableWifiMulticast();
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 6ea35f5..64084cf 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -732,15 +732,19 @@
/*
* Filter out multicast packets. This saves battery power, since
* the CPU doesn't have to spend time processing packets that
- * are going to end up being thrown away. Obviously, if we
- * ever want to support multicast, this will have to change.
+ * are going to end up being thrown away.
+ *
+ * Note that rather than turn this off directly, we use the
+ * public api - this keeps us all in sync - turn multicast on
+ * first and then off.. if nobody else wants it on it'll be
+ * off then and it's all synchronized within the API.
*/
+ mWM.enableWifiMulticast("WifiStateTracker");
+ mWM.disableWifiMulticast();
+
if (mBluetoothA2dp == null) {
mBluetoothA2dp = new BluetoothA2dp(mContext);
}
- synchronized (this) {
- WifiNative.startPacketFiltering();
- }
checkIsBluetoothPlaying();
break;