Merge change 21259 into eclair
* changes:
Make certificate-handling-related constants public
diff --git a/Android.mk b/Android.mk
index a9caa20..3653c7b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -88,8 +88,8 @@
core/java/android/backup/IBackupManager.aidl \
core/java/android/backup/IRestoreObserver.aidl \
core/java/android/backup/IRestoreSession.aidl \
+ core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
- core/java/android/bluetooth/IBluetoothDevice.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/content/IContentService.aidl \
@@ -126,8 +126,6 @@
core/java/android/view/IWindow.aidl \
core/java/android/view/IWindowManager.aidl \
core/java/android/view/IWindowSession.aidl \
- core/java/android/speech/IRecognitionListener.aidl \
- core/java/android/speech/IRecognitionService.aidl \
core/java/android/speech/tts/ITts.aidl \
core/java/android/speech/tts/ITtsCallback.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
@@ -143,7 +141,6 @@
core/java/com/android/internal/view/IInputMethodClient.aidl \
core/java/com/android/internal/view/IInputMethodManager.aidl \
core/java/com/android/internal/view/IInputMethodSession.aidl \
- im/java/android/im/IImPlugin.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
@@ -230,7 +227,6 @@
frameworks/base/graphics/java/android/graphics/Bitmap.aidl \
frameworks/base/graphics/java/android/graphics/Rect.aidl \
frameworks/base/graphics/java/android/graphics/Region.aidl \
- frameworks/base/im/java/android/im/IImPlugin.aidl \
frameworks/base/location/java/android/location/Criteria.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
@@ -341,7 +337,7 @@
-since ./frameworks/base/api/1.xml 1 \
-since ./frameworks/base/api/2.xml 2 \
-since ./frameworks/base/api/3.xml 3 \
- -since ./frameworks/base/api/current.xml Donut \
+ -since ./frameworks/base/api/4.xml 4 \
-error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 \
-overview $(LOCAL_PATH)/core/java/overview.html
@@ -353,10 +349,18 @@
-hdf android.hasSamples 1 \
-samplecode $(sample_dir)/ApiDemos \
guide/samples/ApiDemos "API Demos" \
+ -samplecode $(sample_dir)/Home \
+ guide/samples/Home "Home" \
+ -samplecode $(sample_dir)/JetBoy \
+ guide/samples/JetBoy "JetBoy" \
-samplecode $(sample_dir)/LunarLander \
guide/samples/LunarLander "Lunar Lander" \
-samplecode $(sample_dir)/NotePad \
- guide/samples/NotePad "Note Pad"
+ guide/samples/NotePad "Note Pad" \
+ -samplecode $(sample_dir)/Snake \
+ guide/samples/Snake "Snake" \
+ -samplecode $(sample_dir)/SoftKeyboard \
+ guide/samples/SoftKeyboard "Soft Keyboard"
## SDK version identifiers used in the published docs
# major[.minor] version for current SDK. (full releases only)
diff --git a/api/current.xml b/api/current.xml
index d571984..ea70922 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4200,17 +4200,6 @@
visibility="public"
>
</field>
-<field name="includeInGlobalSearch"
- type="int"
- transient="false"
- volatile="false"
- value="16843374"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="indeterminate"
type="int"
transient="false"
@@ -6279,17 +6268,6 @@
visibility="public"
>
</field>
-<field name="queryAfterZeroResults"
- type="int"
- transient="false"
- volatile="false"
- value="16843394"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="radioButtonStyle"
type="int"
transient="false"
@@ -6785,17 +6763,6 @@
visibility="public"
>
</field>
-<field name="searchSettingsDescription"
- type="int"
- transient="false"
- volatile="false"
- value="16843402"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="searchSuggestAuthority"
type="int"
transient="false"
@@ -6851,17 +6818,6 @@
visibility="public"
>
</field>
-<field name="searchSuggestThreshold"
- type="int"
- transient="false"
- volatile="false"
- value="16843373"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="secondaryProgress"
type="int"
transient="false"
@@ -7489,6 +7445,17 @@
visibility="public"
>
</field>
+<field name="supportsUploading"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843414"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="syncable"
type="int"
transient="false"
@@ -8391,6 +8358,17 @@
visibility="public"
>
</field>
+<field name="userVisible"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843408"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="value"
type="int"
transient="false"
@@ -8556,6 +8534,50 @@
visibility="public"
>
</field>
+<field name="wallpaperActivityCloseEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843412"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityCloseExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843413"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843410"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843411"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="webViewStyle"
type="int"
transient="false"
@@ -8758,7 +8780,7 @@
type="int"
transient="false"
volatile="false"
- value="16843408"
+ value="16843409"
static="true"
final="true"
deprecated="not deprecated"
@@ -12076,6 +12098,17 @@
visibility="public"
>
</field>
+<field name="Animation_InputMethod"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973910"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Animation_Toast"
type="int"
transient="false"
@@ -13463,6 +13496,23 @@
<parameter name="accountType" type="java.lang.String">
</parameter>
</method>
+<method name="getAccountRemovalAllowed"
+ return="android.os.Bundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
<method name="getAuthToken"
return="android.os.Bundle"
abstract="true"
@@ -13615,7 +13665,7 @@
visibility="public"
>
</field>
-<field name="mName"
+<field name="name"
type="java.lang.String"
transient="false"
volatile="false"
@@ -13625,7 +13675,7 @@
visibility="public"
>
</field>
-<field name="mType"
+<field name="type"
type="java.lang.String"
transient="false"
volatile="false"
@@ -13781,7 +13831,7 @@
visibility="public"
>
<method name="addAccount"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -13800,13 +13850,13 @@
</parameter>
<parameter name="activity" type="android.app.Activity">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="addAccountExplicitly"
- return="android.accounts.Future1<java.lang.Boolean>"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -13815,16 +13865,12 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Boolean>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="password" type="java.lang.String">
</parameter>
<parameter name="extras" type="android.os.Bundle">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="addOnAccountsUpdatedListener"
return="void"
@@ -13843,81 +13889,6 @@
<parameter name="updateImmediately" type="boolean">
</parameter>
</method>
-<method name="blockingAddAccountExplicitly"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="password" type="java.lang.String">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
-<method name="blockingClearPassword"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-</method>
-<method name="blockingGetAccounts"
- return="android.accounts.Account[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="blockingGetAccountsByType"
- return="android.accounts.Account[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="accountType" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingGetAccountsWithTypeAndFeatures"
- return="android.accounts.Account[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="type" type="java.lang.String">
-</parameter>
-<parameter name="features" type="java.lang.String[]">
-</parameter>
-<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
-</exception>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
-</exception>
-</method>
<method name="blockingGetAuthToken"
return="java.lang.String"
abstract="false"
@@ -13941,139 +13912,8 @@
<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
</exception>
</method>
-<method name="blockingGetAuthenticatorTypes"
- return="android.accounts.AuthenticatorDescription[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="blockingGetPassword"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-</method>
-<method name="blockingGetUserData"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="key" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingInvalidateAuthToken"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="accountType" type="java.lang.String">
-</parameter>
-<parameter name="authToken" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingPeekAuthToken"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="authTokenType" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingRemoveAccount"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-</method>
-<method name="blockingSetAuthToken"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="authTokenType" type="java.lang.String">
-</parameter>
-<parameter name="authToken" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingSetPassword"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="password" type="java.lang.String">
-</parameter>
-</method>
-<method name="blockingSetUserData"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="account" type="android.accounts.Account">
-</parameter>
-<parameter name="key" type="java.lang.String">
-</parameter>
-<parameter name="value" type="java.lang.String">
-</parameter>
-</method>
<method name="clearPassword"
- return="android.accounts.Future1<java.lang.Void>"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -14082,15 +13922,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="confirmCredentials"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -14103,13 +13939,13 @@
</parameter>
<parameter name="activity" type="android.app.Activity">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="confirmPassword"
- return="android.accounts.Future1<java.lang.Boolean>"
+ return="android.accounts.AccountManagerFuture<java.lang.Boolean>"
abstract="false"
native="false"
synchronized="false"
@@ -14122,13 +13958,13 @@
</parameter>
<parameter name="password" type="java.lang.String">
</parameter>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Boolean>">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<java.lang.Boolean>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="editProperties"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -14141,7 +13977,7 @@
</parameter>
<parameter name="activity" type="android.app.Activity">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
@@ -14160,7 +13996,7 @@
</parameter>
</method>
<method name="getAccounts"
- return="android.accounts.Future1<android.accounts.Account[]>"
+ return="android.accounts.Account[]"
abstract="false"
native="false"
synchronized="false"
@@ -14169,13 +14005,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.Account[]>">
-</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="getAccountsByType"
- return="android.accounts.Future1<android.accounts.Account[]>"
+ return="android.accounts.Account[]"
abstract="false"
native="false"
synchronized="false"
@@ -14184,15 +14016,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.Account[]>">
-</parameter>
<parameter name="type" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
-<method name="getAccountsWithTypeAndFeatures"
- return="android.accounts.Future2"
+<method name="getAccountsByTypeAndFeatures"
+ return="android.accounts.AccountManagerFuture<android.accounts.Account[]>"
abstract="false"
native="false"
synchronized="false"
@@ -14205,13 +14033,13 @@
</parameter>
<parameter name="features" type="java.lang.String[]">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.accounts.Account[]>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="getAuthToken"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -14228,13 +14056,13 @@
</parameter>
<parameter name="activity" type="android.app.Activity">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="getAuthToken"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -14249,7 +14077,7 @@
</parameter>
<parameter name="notifyAuthFailure" type="boolean">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
@@ -14276,13 +14104,13 @@
</parameter>
<parameter name="loginOptions" type="android.os.Bundle">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="getAuthenticatorTypes"
- return="android.accounts.Future1<android.accounts.AuthenticatorDescription[]>"
+ return="android.accounts.AuthenticatorDescription[]"
abstract="false"
native="false"
synchronized="false"
@@ -14291,13 +14119,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.AuthenticatorDescription[]>">
-</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="getPassword"
- return="android.accounts.Future1<java.lang.String>"
+ return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
@@ -14306,15 +14130,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="getUserData"
- return="android.accounts.Future1<java.lang.String>"
+ return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
@@ -14323,17 +14143,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="key" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="invalidateAuthToken"
- return="android.accounts.Future1<java.lang.Void>"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -14342,17 +14158,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="accountType" type="java.lang.String">
</parameter>
<parameter name="authToken" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="peekAuthToken"
- return="android.accounts.Future1<java.lang.String>"
+ return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
@@ -14361,17 +14173,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="authTokenType" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="removeAccount"
- return="android.accounts.Future1<java.lang.Void>"
+ return="android.accounts.AccountManagerFuture<java.lang.Boolean>"
abstract="false"
native="false"
synchronized="false"
@@ -14380,10 +14188,10 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
+<parameter name="callback" type="android.accounts.AccountManagerCallback<java.lang.Boolean>">
+</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
@@ -14401,7 +14209,7 @@
</parameter>
</method>
<method name="setAuthToken"
- return="android.accounts.Future1<java.lang.Void>"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -14410,19 +14218,15 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="authTokenType" type="java.lang.String">
</parameter>
<parameter name="authToken" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="setPassword"
- return="android.accounts.Future1<java.lang.Void>"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -14431,17 +14235,13 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="password" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="setUserData"
- return="android.accounts.Future1<java.lang.Void>"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -14450,19 +14250,15 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>">
-</parameter>
<parameter name="account" type="android.accounts.Account">
</parameter>
<parameter name="key" type="java.lang.String">
</parameter>
<parameter name="value" type="java.lang.String">
</parameter>
-<parameter name="handler" type="android.os.Handler">
-</parameter>
</method>
<method name="updateCredentials"
- return="android.accounts.Future2"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
abstract="false"
native="false"
synchronized="false"
@@ -14479,12 +14275,117 @@
</parameter>
<parameter name="activity" type="android.app.Activity">
</parameter>
-<parameter name="callback" type="android.accounts.Future2Callback">
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
</class>
+<interface name="AccountManagerCallback"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="future" type="android.accounts.AccountManagerFuture<V>">
+</parameter>
+</method>
+</interface>
+<interface name="AccountManagerFuture"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.Future">
+</implements>
+<method name="get"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
+</exception>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="get"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
+</exception>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+<exception name="TimeoutException" type="java.util.concurrent.TimeoutException">
+</exception>
+</method>
+<method name="getResult"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+<method name="getResult"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+</interface>
<class name="AuthenticatorDescription"
extends="java.lang.Object"
abstract="false"
@@ -14952,6 +14853,17 @@
visibility="public"
>
</field>
+<field name="PASSWORD_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""password""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="USERDATA_KEY"
type="java.lang.String"
transient="false"
@@ -14964,136 +14876,6 @@
>
</field>
</class>
-<interface name="Future1"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="java.util.concurrent.Future">
-</implements>
-<method name="getResult"
- return="V"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
-</exception>
-</method>
-<method name="getResult"
- return="V"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="timeout" type="long">
-</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
-</parameter>
-<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
-</exception>
-</method>
-</interface>
-<interface name="Future1Callback"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="run"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="future" type="android.accounts.Future1<V>">
-</parameter>
-</method>
-</interface>
-<interface name="Future2"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="java.util.concurrent.Future">
-</implements>
-<method name="getResult"
- return="android.os.Bundle"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
-</exception>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
-</exception>
-</method>
-<method name="getResult"
- return="android.os.Bundle"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="timeout" type="long">
-</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
-</parameter>
-<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
-</exception>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
-</exception>
-</method>
-</interface>
-<interface name="Future2Callback"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="run"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="future" type="android.accounts.Future2">
-</parameter>
-</method>
-</interface>
<interface name="IAccountAuthenticator"
abstract="true"
static="false"
@@ -15150,7 +14932,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="deprecated"
+ deprecated="not deprecated"
visibility="public"
>
<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
@@ -15179,6 +14961,23 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="getAccountRemovalAllowed"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="getAuthToken"
return="void"
abstract="true"
@@ -16101,6 +15900,17 @@
<parameter name="data" type="android.content.Intent">
</parameter>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onChildTitleChanged"
return="void"
abstract="false"
@@ -16304,6 +16114,17 @@
visibility="protected"
>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -17225,6 +17046,23 @@
<parameter name="get" type="boolean">
</parameter>
</method>
+<method name="triggerSearch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="query" type="java.lang.String">
+</parameter>
+<parameter name="appSearchData" type="android.os.Bundle">
+</parameter>
+<parameter name="globalSearch" type="boolean">
+</parameter>
+</method>
<method name="unregisterForContextMenu"
return="void"
abstract="false"
@@ -19817,6 +19655,17 @@
visibility="public"
>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onContentChanged"
return="void"
abstract="false"
@@ -19925,6 +19774,17 @@
<parameter name="featureId" type="int">
</parameter>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -21708,6 +21568,19 @@
<parameter name="intent" type="android.content.Intent">
</parameter>
</method>
+<method name="setIntentRedelivery"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
</class>
<class name="KeyguardManager"
extends="java.lang.Object"
@@ -21871,6 +21744,30 @@
visibility="public"
>
</method>
+<method name="onQueryPackageManager"
+ return="java.util.List<android.content.pm.ResolveInfo>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="queryIntent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onSetContentView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
</class>
<class name="LauncherActivity.IconResizer"
extends="java.lang.Object"
@@ -22406,6 +22303,17 @@
visibility="public"
>
</field>
+<field name="FLAG_FOREGROUND_SERVICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_INSISTENT"
type="int"
transient="false"
@@ -23447,6 +23355,25 @@
visibility="public"
>
</method>
+<method name="triggerSearch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="query" type="java.lang.String">
+</parameter>
+<parameter name="launchActivity" type="android.content.ComponentName">
+</parameter>
+<parameter name="appSearchData" type="android.os.Bundle">
+</parameter>
+<parameter name="globalSearch" type="boolean">
+</parameter>
+</method>
<field name="ACTION_KEY"
type="java.lang.String"
transient="false"
@@ -23513,17 +23440,6 @@
visibility="public"
>
</field>
-<field name="INTENT_ACTION_WEB_SEARCH_SETTINGS"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.search.action.WEB_SEARCH_SETTINGS""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="MENU_KEY"
type="char"
transient="false"
@@ -23557,17 +23473,6 @@
visibility="public"
>
</field>
-<field name="SHORTCUT_MIME_TYPE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""vnd.android.cursor.item/vnd.android.search.suggest""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SUGGEST_COLUMN_FORMAT"
type="java.lang.String"
transient="false"
@@ -23656,28 +23561,6 @@
visibility="public"
>
</field>
-<field name="SUGGEST_COLUMN_SHORTCUT_ID"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""suggest_shortcut_id""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""suggest_spinner_while_refreshing""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SUGGEST_COLUMN_TEXT_1"
type="java.lang.String"
transient="false"
@@ -23711,17 +23594,6 @@
visibility="public"
>
</field>
-<field name="SUGGEST_NEVER_MAKE_SHORTCUT"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""_-1""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="SUGGEST_URI_PATH_QUERY"
type="java.lang.String"
transient="false"
@@ -23733,17 +23605,6 @@
visibility="public"
>
</field>
-<field name="SUGGEST_URI_PATH_SHORTCUT"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""search_suggest_shortcut""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="USER_QUERY"
type="java.lang.String"
transient="false"
@@ -23919,11 +23780,28 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="startId" type="int">
+</parameter>
+</method>
+<method name="onStartCommand"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="intent" type="android.content.Intent">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
<parameter name="startId" type="int">
</parameter>
</method>
@@ -23947,12 +23825,40 @@
synchronized="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="isForeground" type="boolean">
</parameter>
</method>
+<method name="startForeground"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="notification" type="android.app.Notification">
+</parameter>
+</method>
+<method name="stopForeground"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="removeNotification" type="boolean">
+</parameter>
+</method>
<method name="stopSelf"
return="void"
abstract="false"
@@ -23990,6 +23896,83 @@
<parameter name="startId" type="int">
</parameter>
</method>
+<field name="START_CONTINUATION_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_FLAG_REDELIVERY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_FLAG_RETRY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_NOT_STICKY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_REDELIVER_INTENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_STICKY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_STICKY_COMPATIBILITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="TabActivity"
extends="android.app.ActivityGroup"
@@ -25094,6 +25077,235 @@
</field>
</class>
</package>
+<package name="android.bluetooth"
+>
+<class name="BluetoothAdapter"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getRemoteDevice"
+ return="android.bluetooth.BluetoothDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.lang.String">
+</parameter>
+</method>
+<method name="listenUsingRfcommOn"
+ return="android.bluetooth.BluetoothServerSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="channel" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="BluetoothDevice"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="createRfcommSocket"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="channel" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+</class>
+<class name="BluetoothServerSocket"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Closeable">
+</implements>
+<method name="accept"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="accept"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="BluetoothSocket"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Closeable">
+</implements>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="connect"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getInputStream"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getOutputStream"
+ return="java.io.OutputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getRemoteDevice"
+ return="android.bluetooth.BluetoothDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
<package name="android.content"
>
<class name="AbstractCursorEntityIterator"
@@ -25164,6 +25376,19 @@
visibility="public"
>
</method>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
</class>
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
@@ -27266,6 +27491,21 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="getIsSyncable"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
<method name="getMasterSyncAutomatically"
return="boolean"
abstract="false"
@@ -27563,6 +27803,23 @@
<parameter name="extras" type="android.os.Bundle">
</parameter>
</method>
+<method name="setIsSyncable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="syncable" type="int">
+</parameter>
+</method>
<method name="setMasterSyncAutomatically"
return="void"
abstract="false"
@@ -27752,6 +28009,17 @@
visibility="public"
>
</field>
+<field name="SYNC_EXTRAS_INITIALIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""initialize""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SYNC_EXTRAS_MANUAL"
type="java.lang.String"
transient="false"
@@ -29409,6 +29677,17 @@
visibility="public"
>
</field>
+<field name="BLUETOOTH_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""bluetooth""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CLIPBOARD_SERVICE"
type="java.lang.String"
transient="false"
@@ -31025,6 +31304,19 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="reset"
+ 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>
</interface>
<class name="Intent"
extends="java.lang.Object"
@@ -35932,6 +36224,10 @@
</parameter>
<parameter name="accountType" type="java.lang.String">
</parameter>
+<parameter name="userVisible" type="boolean">
+</parameter>
+<parameter name="supportsUploading" type="boolean">
+</parameter>
</constructor>
<constructor name="SyncAdapterType"
type="android.content.SyncAdapterType"
@@ -35954,6 +36250,43 @@
visibility="public"
>
</method>
+<method name="isUserVisible"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newKey"
+ return="android.content.SyncAdapterType"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</method>
+<method name="supportsUploading"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="writeToParcel"
return="void"
abstract="false"
@@ -35999,6 +36332,16 @@
visibility="public"
>
</field>
+<field name="isKey"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<interface name="SyncStatusObserver"
abstract="true"
@@ -60164,6 +60507,21 @@
visibility="public"
>
</method>
+<method name="setGammaForText"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="blackGamma" type="float">
+</parameter>
+<parameter name="whiteGamma" type="float">
+</parameter>
+</method>
<field name="BOLD"
type="int"
transient="false"
@@ -61065,6 +61423,27 @@
<parameter name="srcName" type="java.lang.String">
</parameter>
</method>
+<method name="createFromResourceStream"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="value" type="android.util.TypedValue">
+</parameter>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+<parameter name="srcName" type="java.lang.String">
+</parameter>
+<parameter name="opts" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
<method name="createFromStream"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -94752,6 +95131,17 @@
visibility="public"
>
</field>
+<field name="ECLAIR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Bundle"
extends="java.lang.Object"
@@ -105179,7 +105569,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="AUTHORITY"
@@ -105189,7 +105579,7 @@
value=""contacts""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105199,7 +105589,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105210,7 +105600,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105221,7 +105611,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105232,7 +105622,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105243,7 +105633,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105254,7 +105644,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105264,7 +105654,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -105280,7 +105670,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -105299,7 +105689,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="encodedString" type="java.lang.String">
@@ -105312,7 +105702,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="protocolString" type="java.lang.String">
@@ -105325,7 +105715,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="protocol" type="int">
@@ -105338,7 +105728,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -105357,7 +105747,7 @@
value=""vnd.android.cursor.item/email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105368,7 +105758,7 @@
value=""vnd.android.cursor.dir/email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105378,7 +105768,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105389,7 +105779,7 @@
value=""vnd.android.cursor.item/jabber-im""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105400,7 +105790,7 @@
value=""vnd.android.cursor.item/postal-address""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105411,7 +105801,7 @@
value=""vnd.android.cursor.dir/postal-address""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105422,7 +105812,7 @@
value=""vnd.android.cursor.dir/contact-methods""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105432,7 +105822,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105443,7 +105833,7 @@
value=""name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105454,7 +105844,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105465,7 +105855,7 @@
value=""data""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105476,7 +105866,7 @@
value=""aux_data""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105487,7 +105877,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105498,7 +105888,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105509,7 +105899,7 @@
value="6"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105520,7 +105910,7 @@
value="7"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105531,7 +105921,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105542,7 +105932,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105553,7 +105943,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105564,7 +105954,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105573,7 +105963,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="AUX_DATA"
@@ -105583,7 +105973,7 @@
value=""aux_data""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105594,7 +105984,7 @@
value=""data""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105605,7 +105995,7 @@
value=""isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105616,7 +106006,7 @@
value=""kind""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105627,7 +106017,7 @@
value=""label""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105638,7 +106028,7 @@
value=""type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105649,7 +106039,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105660,7 +106050,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105671,7 +106061,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105682,7 +106072,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105692,7 +106082,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -105706,7 +106096,7 @@
value=""vnd.android.cursor.item/contact_extensions""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105717,7 +106107,7 @@
value=""vnd.android.cursor.dir/contact_extensions""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105727,7 +106117,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105738,7 +106128,7 @@
value=""person, name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105749,7 +106139,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105758,7 +106148,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="NAME"
@@ -105768,7 +106158,7 @@
value=""name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105779,7 +106169,7 @@
value=""value""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105789,7 +106179,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -105803,7 +106193,7 @@
value=""groupmembership""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105814,7 +106204,7 @@
value=""vnd.android.cursor.item/contactsgroupmembership""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105825,7 +106215,7 @@
value=""vnd.android.cursor.dir/contactsgroupmembership""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105835,7 +106225,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105846,7 +106236,7 @@
value=""group_id ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105857,7 +106247,7 @@
value=""group_id""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105868,7 +106258,7 @@
value=""group_sync_account""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105879,7 +106269,7 @@
value=""group_sync_account_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105890,7 +106280,7 @@
value=""group_sync_id""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105901,7 +106291,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105911,7 +106301,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105921,7 +106311,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -105935,7 +106325,7 @@
value=""vnd.android.cursor.item/contactsgroup""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105946,7 +106336,7 @@
value=""vnd.android.cursor.dir/contactsgroup""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105956,7 +106346,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105967,7 +106357,7 @@
value=""name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105977,7 +106367,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105988,7 +106378,7 @@
value=""Starred in Android""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -105999,7 +106389,7 @@
value=""Contacts""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106008,7 +106398,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="NAME"
@@ -106018,7 +106408,7 @@
value=""name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106029,7 +106419,7 @@
value=""notes""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106040,7 +106430,7 @@
value=""should_sync""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106051,7 +106441,7 @@
value=""system_id""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106061,14 +106451,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents"
type="android.provider.Contacts.Intents"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -106079,7 +106469,7 @@
value=""com.android.contacts.action.ATTACH_IMAGE""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106090,7 +106480,7 @@
value=""com.android.contacts.action.CREATE_DESCRIPTION""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106101,7 +106491,7 @@
value=""com.android.contacts.action.FORCE_CREATE""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106112,7 +106502,7 @@
value=""android.provider.Contacts.SEARCH_SUGGESTION_CLICKED""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106123,7 +106513,7 @@
value=""android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106134,7 +106524,7 @@
value=""android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106145,7 +106535,7 @@
value=""com.android.contacts.action.SHOW_OR_CREATE_CONTACT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106155,14 +106545,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents.Insert"
type="android.provider.Contacts.Intents.Insert"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -106173,7 +106563,7 @@
value=""android.intent.action.INSERT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106184,7 +106574,7 @@
value=""company""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106195,7 +106585,7 @@
value=""email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106206,7 +106596,7 @@
value=""email_isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106217,7 +106607,7 @@
value=""email_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106228,7 +106618,7 @@
value=""full_mode""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106239,7 +106629,7 @@
value=""im_handle""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106250,7 +106640,7 @@
value=""im_isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106261,7 +106651,7 @@
value=""im_protocol""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106272,7 +106662,7 @@
value=""job_title""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106283,7 +106673,7 @@
value=""name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106294,7 +106684,7 @@
value=""notes""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106305,7 +106695,7 @@
value=""phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106316,7 +106706,7 @@
value=""phonetic_name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106327,7 +106717,7 @@
value=""phone_isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106338,7 +106728,7 @@
value=""phone_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106349,7 +106739,7 @@
value=""postal""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106360,7 +106750,7 @@
value=""postal_isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106371,7 +106761,7 @@
value=""postal_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106382,7 +106772,7 @@
value=""secondary_email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106393,7 +106783,7 @@
value=""secondary_email_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106404,7 +106794,7 @@
value=""secondary_phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106415,7 +106805,7 @@
value=""secondary_phone_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106426,7 +106816,7 @@
value=""tertiary_email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106437,7 +106827,7 @@
value=""tertiary_email_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106448,7 +106838,7 @@
value=""tertiary_phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106459,7 +106849,7 @@
value=""tertiary_phone_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106469,14 +106859,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents.UI"
type="android.provider.Contacts.Intents.UI"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -106487,7 +106877,7 @@
value=""com.android.contacts.action.FILTER_CONTACTS""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106498,7 +106888,7 @@
value=""com.android.contacts.extra.FILTER_TEXT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106509,7 +106899,7 @@
value=""com.android.contacts.extra.GROUP""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106520,7 +106910,7 @@
value=""com.android.contacts.action.LIST_ALL_CONTACTS""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106531,7 +106921,7 @@
value=""com.android.contacts.action.LIST_CONTACTS_WITH_PHONES""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106542,7 +106932,7 @@
value=""com.android.contacts.action.LIST_DEFAULT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106553,7 +106943,7 @@
value=""com.android.contacts.action.LIST_FREQUENT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106564,7 +106954,7 @@
value=""com.android.contacts.action.LIST_GROUP""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106575,7 +106965,7 @@
value=""com.android.contacts.action.LIST_STARRED""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106586,7 +106976,7 @@
value=""com.android.contacts.action.LIST_STREQUENT""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106597,7 +106987,7 @@
value=""com.android.contacts.extra.TITLE_EXTRA""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106606,7 +106996,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="COMPANY"
@@ -106616,7 +107006,7 @@
value=""company""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106627,7 +107017,7 @@
value=""isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106638,7 +107028,7 @@
value=""label""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106649,7 +107039,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106660,7 +107050,7 @@
value=""title""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106671,7 +107061,7 @@
value=""type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106682,7 +107072,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106693,7 +107083,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106704,7 +107094,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106714,7 +107104,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -106728,7 +107118,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -106745,7 +107135,7 @@
value=""organizations""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106755,7 +107145,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106766,7 +107156,7 @@
value=""company, title, isprimary ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106776,7 +107166,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -106794,7 +107184,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106811,7 +107201,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106828,7 +107218,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106843,7 +107233,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106858,7 +107248,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -106877,7 +107267,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106892,7 +107282,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -106907,7 +107297,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -106922,7 +107312,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -106938,7 +107328,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106949,7 +107339,7 @@
value=""vnd.android.cursor.item/person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106960,7 +107350,7 @@
value=""vnd.android.cursor.dir/person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106970,7 +107360,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106981,7 +107371,7 @@
value=""name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -106991,7 +107381,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107002,7 +107392,7 @@
value=""primary_email""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107013,7 +107403,7 @@
value=""primary_organization""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107024,7 +107414,7 @@
value=""primary_phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107034,7 +107424,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107050,7 +107440,7 @@
value=""contact_methods""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107061,7 +107451,7 @@
value=""data ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107071,7 +107461,7 @@
abstract="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107085,7 +107475,7 @@
value=""extensions""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107096,7 +107486,7 @@
value=""name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107107,7 +107497,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107117,7 +107507,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107133,7 +107523,7 @@
value=""phones""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107144,7 +107534,7 @@
value=""number ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107153,7 +107543,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="CUSTOM_RINGTONE"
@@ -107163,7 +107553,7 @@
value=""custom_ringtone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107174,7 +107564,7 @@
value=""display_name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107185,7 +107575,7 @@
value=""last_time_contacted""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107196,7 +107586,7 @@
value=""name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107207,7 +107597,7 @@
value=""notes""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107218,7 +107608,7 @@
value=""phonetic_name""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107229,7 +107619,7 @@
value=""photo_version""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107240,7 +107630,7 @@
value=""send_to_voicemail""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107251,7 +107641,7 @@
value=""starred""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107262,7 +107652,7 @@
value=""times_contacted""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107272,7 +107662,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107288,7 +107678,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -107307,7 +107697,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -107323,7 +107713,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107334,7 +107724,7 @@
value=""vnd.android.cursor.item/phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107345,7 +107735,7 @@
value=""vnd.android.cursor.dir/phone""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107355,7 +107745,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107366,7 +107756,7 @@
value=""name ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107377,7 +107767,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107386,7 +107776,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="ISPRIMARY"
@@ -107396,7 +107786,7 @@
value=""isprimary""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107407,7 +107797,7 @@
value=""label""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107418,7 +107808,7 @@
value=""number""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107429,7 +107819,7 @@
value=""number_key""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107440,7 +107830,7 @@
value=""type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107451,7 +107841,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107462,7 +107852,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107473,7 +107863,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107484,7 +107874,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107495,7 +107885,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107506,7 +107896,7 @@
value="7"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107517,7 +107907,7 @@
value="6"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107528,7 +107918,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107538,7 +107928,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107552,7 +107942,7 @@
value=""photo""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107562,7 +107952,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107573,7 +107963,7 @@
value=""person ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107582,7 +107972,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="DATA"
@@ -107592,7 +107982,7 @@
value=""data""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107603,7 +107993,7 @@
value=""download_required""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107614,7 +108004,7 @@
value=""exists_on_server""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107625,7 +108015,7 @@
value=""local_version""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107636,7 +108026,7 @@
value=""person""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107647,7 +108037,7 @@
value=""sync_error""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107656,7 +108046,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="IM_ACCOUNT"
@@ -107666,7 +108056,7 @@
value=""im_account""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107677,7 +108067,7 @@
value=""im_handle""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107688,7 +108078,7 @@
value=""im_protocol""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107698,7 +108088,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -107712,7 +108102,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -107729,7 +108119,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -107748,7 +108138,7 @@
value=""settings""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107758,7 +108148,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107769,7 +108159,7 @@
value=""key ASC""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107780,7 +108170,7 @@
value=""syncEverything""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107789,7 +108179,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="KEY"
@@ -107799,7 +108189,7 @@
value=""key""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107810,7 +108200,7 @@
value=""value""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107821,7 +108211,7 @@
value=""_sync_account""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -107832,7 +108222,7 @@
value=""_sync_account_type""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -114128,6 +114518,17 @@
visibility="public"
>
</field>
+<field name="ACTION_TTS_DATA_INSTALLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.speech.tts.engine.TTS_DATA_INSTALLED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CHECK_VOICE_DATA_BAD_DATA"
type="int"
transient="false"
@@ -114194,6 +114595,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_TTS_DATA_INSTALLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""dataInstalled""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_VOICE_DATA_FILES"
type="java.lang.String"
transient="false"
@@ -115165,7 +115577,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="asu" type="int">
@@ -118252,6 +118664,19 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="instrumentation" type="android.app.Instrumentation">
+</parameter>
+</method>
+<method name="setInstrumentation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -118501,6 +118926,19 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="instrumentation" type="android.app.Instrumentation">
+</parameter>
+</method>
+<method name="injectInstrumentation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -144220,6 +144658,19 @@
<parameter name="o" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="obtainNoHistory"
+ return="android.view.MotionEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="android.view.MotionEvent">
+</parameter>
+</method>
<method name="offsetLocation"
return="void"
abstract="false"
@@ -144996,6 +145447,8 @@
>
<parameter name="dirty" type="android.graphics.Rect">
</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
<exception name="Surface.OutOfResourcesException" type="android.view.Surface.OutOfResourcesException">
</exception>
</method>
@@ -154281,6 +154734,17 @@
<parameter name="event" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onContentChanged"
return="void"
abstract="true"
@@ -154320,6 +154784,17 @@
<parameter name="featureId" type="int">
</parameter>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onMenuItemSelected"
return="boolean"
abstract="true"
@@ -161972,6 +162447,8 @@
</parameter>
<parameter name="currentQuota" type="long">
</parameter>
+<parameter name="estimatedSize" type="long">
+</parameter>
<parameter name="totalUsedQuota" type="long">
</parameter>
<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
@@ -163634,6 +164111,8 @@
</parameter>
<parameter name="currentQuota" type="long">
</parameter>
+<parameter name="estimatedSize" type="long">
+</parameter>
<parameter name="totalUsedQuota" type="long">
</parameter>
<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
@@ -175218,6 +175697,39 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="canPause"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBufferPercentage"
return="int"
abstract="true"
@@ -183546,6 +184058,39 @@
<parameter name="defStyle" type="int">
</parameter>
</constructor>
+<method name="canPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBufferPercentage"
return="int"
abstract="false"
@@ -263557,7 +264102,7 @@
</parameter>
<parameter name="buffer" type="java.lang.StringBuffer">
</parameter>
-<parameter name="field" type="java.text.FieldPosition">
+<parameter name="fieldPos" type="java.text.FieldPosition">
</parameter>
</method>
<method name="get2DigitYearStart"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index cc951c1..18713e9 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -102,7 +102,7 @@
PRINT("------ PACKAGE UID ERRORS ------");
DUMP("/data/system/uiderrors.txt");
PRINT("------ LAST KERNEL LOG ------");
- DUMP("/proc/last_kmsg");
+ DUMP("/data/last_kmsg");
}
PRINT("========================================================");
PRINT("== build.prop");
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e6d0503..697d67a 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -2,7 +2,8 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES:= \
+ JPEGSource.cpp \
stagefright.cpp
LOCAL_SHARED_LIBRARIES := \
@@ -10,8 +11,7 @@
LOCAL_C_INCLUDES:= \
frameworks/base/media/libstagefright \
- $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/external/opencore/android
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
LOCAL_CFLAGS += -Wno-multichar
@@ -31,8 +31,7 @@
LOCAL_C_INCLUDES:= \
frameworks/base/media/libstagefright \
- $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/external/opencore/android
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
LOCAL_CFLAGS += -Wno-multichar
@@ -52,8 +51,7 @@
#
# LOCAL_C_INCLUDES:= \
# frameworks/base/media/libstagefright \
-# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-# $(TOP)/external/opencore/android
+# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
#
# LOCAL_CFLAGS += -Wno-multichar
#
diff --git a/cmds/stagefright/JPEGSource.cpp b/cmds/stagefright/JPEGSource.cpp
new file mode 100644
index 0000000..a7994ed
--- /dev/null
+++ b/cmds/stagefright/JPEGSource.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "JPEGSource"
+#include <utils/Log.h>
+
+#include "JPEGSource.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+#define JPEG_SOF0 0xC0 /* nStart Of Frame N*/
+#define JPEG_SOF1 0xC1 /* N indicates which compression process*/
+#define JPEG_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use*/
+#define JPEG_SOF3 0xC3
+#define JPEG_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers*/
+#define JPEG_SOF6 0xC6
+#define JPEG_SOF7 0xC7
+#define JPEG_SOF9 0xC9
+#define JPEG_SOF10 0xCA
+#define JPEG_SOF11 0xCB
+#define JPEG_SOF13 0xCD
+#define JPEG_SOF14 0xCE
+#define JPEG_SOF15 0xCF
+#define JPEG_SOI 0xD8 /* nStart Of Image (beginning of datastream)*/
+#define JPEG_EOI 0xD9 /* End Of Image (end of datastream)*/
+#define JPEG_SOS 0xDA /* nStart Of Scan (begins compressed data)*/
+#define JPEG_JFIF 0xE0 /* Jfif marker*/
+#define JPEG_EXIF 0xE1 /* Exif marker*/
+#define JPEG_COM 0xFE /* COMment */
+#define JPEG_DQT 0xDB
+#define JPEG_DHT 0xC4
+#define JPEG_DRI 0xDD
+
+namespace android {
+
+JPEGSource::JPEGSource(const sp<DataSource> &source)
+ : mSource(source),
+ mGroup(NULL),
+ mStarted(false),
+ mSize(0),
+ mWidth(0),
+ mHeight(0),
+ mOffset(0) {
+ CHECK_EQ(parseJPEG(), OK);
+ CHECK(mSource->getSize(&mSize) == OK);
+}
+
+JPEGSource::~JPEGSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t JPEGSource::start(MetaData *) {
+ if (mStarted) {
+ return UNKNOWN_ERROR;
+ }
+
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(mSize));
+
+ mOffset = 0;
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t JPEGSource::stop() {
+ if (!mStarted) {
+ return UNKNOWN_ERROR;
+ }
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> JPEGSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "image/jpeg");
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setInt32(kKeyCompressedSize, mSize);
+
+ return meta;
+}
+
+status_t JPEGSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ return UNKNOWN_ERROR;
+ }
+
+ MediaBuffer *buffer;
+ mGroup->acquire_buffer(&buffer);
+
+ ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
+
+ if (n <= 0) {
+ buffer->release();
+ buffer = NULL;
+
+ return UNKNOWN_ERROR;
+ }
+
+ buffer->set_range(0, n);
+
+ mOffset += n;
+
+ *out = buffer;
+
+ return OK;
+}
+
+status_t JPEGSource::parseJPEG() {
+ mWidth = 0;
+ mHeight = 0;
+
+ off_t i = 0;
+
+ uint16_t soi;
+ if (!mSource->getUInt16(i, &soi)) {
+ return ERROR_IO;
+ }
+
+ i += 2;
+
+ if (soi != 0xffd8) {
+ return UNKNOWN_ERROR;
+ }
+
+ for (;;) {
+ uint8_t marker;
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK_EQ(marker, 0xff);
+
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK(marker != 0xff);
+
+ uint16_t chunkSize;
+ if (!mSource->getUInt16(i, &chunkSize)) {
+ return ERROR_IO;
+ }
+
+ i += 2;
+
+ if (chunkSize < 2) {
+ return UNKNOWN_ERROR;
+ }
+
+ switch (marker) {
+ case JPEG_SOS:
+ {
+ return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR;
+ }
+
+ case JPEG_EOI:
+ {
+ return UNKNOWN_ERROR;
+ }
+
+ case JPEG_SOF0:
+ case JPEG_SOF1:
+ case JPEG_SOF3:
+ case JPEG_SOF5:
+ case JPEG_SOF6:
+ case JPEG_SOF7:
+ case JPEG_SOF9:
+ case JPEG_SOF10:
+ case JPEG_SOF11:
+ case JPEG_SOF13:
+ case JPEG_SOF14:
+ case JPEG_SOF15:
+ {
+ uint16_t width, height;
+ if (!mSource->getUInt16(i + 1, &height)
+ || !mSource->getUInt16(i + 3, &width)) {
+ return ERROR_IO;
+ }
+
+ mWidth = width;
+ mHeight = height;
+
+ i += chunkSize - 2;
+ break;
+ }
+
+ default:
+ {
+ // Skip chunk
+
+ i += chunkSize - 2;
+
+ break;
+ }
+ }
+ }
+
+ return OK;
+}
+
+} // namespace android
diff --git a/cmds/stagefright/JPEGSource.h b/cmds/stagefright/JPEGSource.h
new file mode 100644
index 0000000..051c034
--- /dev/null
+++ b/cmds/stagefright/JPEGSource.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JPEG_SOURCE_H_
+
+#define JPEG_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class DataSource;
+class MediaBufferGroup;
+
+struct JPEGSource : public MediaSource {
+ // Assumes ownership of "source".
+ JPEGSource(const sp<DataSource> &source);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~JPEGSource();
+
+private:
+ sp<DataSource> mSource;
+ MediaBufferGroup *mGroup;
+ bool mStarted;
+ off_t mSize;
+ int32_t mWidth, mHeight;
+ off_t mOffset;
+
+ status_t parseJPEG();
+
+ JPEGSource(const JPEGSource &);
+ JPEGSource &operator=(const JPEGSource &);
+};
+
+} // namespace android
+
+#endif // JPEG_SOURCE_H_
+
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index cd54958..cf2962b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -25,6 +25,7 @@
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
using namespace android;
@@ -32,18 +33,38 @@
class DummySource : public MediaSource {
public:
DummySource(int width, int height)
- : mSize((width * height * 3) / 2) {
+ : mWidth(width),
+ mHeight(height),
+ mSize((width * height * 3) / 2) {
mGroup.add_buffer(new MediaBuffer(mSize));
}
- virtual ::status_t getMaxSampleSize(size_t *max_size) {
- *max_size = mSize;
- return ::OK;
+ virtual sp<MetaData> getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setCString(kKeyMIMEType, "video/raw");
+
+ return meta;
}
- virtual ::status_t read(MediaBuffer **buffer) {
- ::status_t err = mGroup.acquire_buffer(buffer);
- if (err != ::OK) {
+ virtual status_t getMaxSampleSize(size_t *max_size) {
+ *max_size = mSize;
+ return OK;
+ }
+
+ virtual status_t start(MetaData *params) {
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(
+ MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+ status_t err = mGroup.acquire_buffer(buffer);
+ if (err != OK) {
return err;
}
@@ -51,34 +72,34 @@
memset((*buffer)->data(), x, mSize);
(*buffer)->set_range(0, mSize);
- return ::OK;
+ return OK;
}
+protected:
+ virtual ~DummySource() {}
+
private:
MediaBufferGroup mGroup;
+ int mWidth, mHeight;
size_t mSize;
DummySource(const DummySource &);
DummySource &operator=(const DummySource &);
};
-int main(int argc, char **argv) {
- android::ProcessState::self()->startThreadPool();
+#define USE_OMX_CODEC 1
-#if 1
- if (argc != 2) {
- fprintf(stderr, "usage: %s filename\n", argv[0]);
- return 1;
- }
+sp<MediaSource> createSource(const char *filename) {
+ sp<MediaSource> source;
- MPEG4Extractor extractor(new MmapSource(argv[1]));
- int num_tracks;
- assert(extractor.countTracks(&num_tracks) == ::OK);
+ sp<MPEG4Extractor> extractor =
+ new MPEG4Extractor(new MmapSource(filename));
- MediaSource *source = NULL;
+ size_t num_tracks = extractor->countTracks();
+
sp<MetaData> meta;
- for (int i = 0; i < num_tracks; ++i) {
- meta = extractor.getTrackMetaData(i);
+ for (size_t i = 0; i < num_tracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
assert(meta.get() != NULL);
const char *mime;
@@ -90,48 +111,75 @@
continue;
}
- if (extractor.getTrack(i, &source) != ::OK) {
- source = NULL;
- continue;
- }
+ source = extractor->getTrack(i);
break;
}
- if (source == NULL) {
- fprintf(stderr, "Unable to find a suitable video track.\n");
+ return source;
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+#if 1
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
return 1;
}
OMXClient client;
assert(client.connect() == android::OK);
- OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
- decoder->setSource(source);
+#if 0
+ sp<MediaSource> source = createSource(argv[1]);
+
+ if (source == NULL) {
+ fprintf(stderr, "Unable to find a suitable video track.\n");
+ return 1;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+#if USE_OMX_CODEC
+ sp<OMXCodec> decoder = OMXCodec::Create(
+ client.interface(), meta, false /* createEncoder */, source);
+#else
+ sp<OMXDecoder> decoder = OMXDecoder::Create(
+ &client, meta, false /* createEncoder */, source);
+#endif
int width, height;
bool success = meta->findInt32(kKeyWidth, &width);
success = success && meta->findInt32(kKeyHeight, &height);
assert(success);
+#else
+ int width = 320;
+ int height = 240;
+ sp<MediaSource> decoder = new DummySource(width, height);
+#endif
sp<MetaData> enc_meta = new MetaData;
- enc_meta->setCString(kKeyMIMEType, "video/3gpp");
- // enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+ // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
+ enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
- OMXDecoder *encoder =
- OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
-
- encoder->setSource(decoder);
- // encoder->setSource(meta, new DummySource(width, height));
+#if USE_OMX_CODEC
+ sp<OMXCodec> encoder =
+ OMXCodec::Create(
+ client.interface(), enc_meta, true /* createEncoder */, decoder);
+#else
+ sp<OMXDecoder> encoder = OMXDecoder::Create(
+ &client, enc_meta, true /* createEncoder */, decoder);
+#endif
#if 1
- MPEG4Writer writer("/sdcard/output.mp4");
- writer.addSource(enc_meta, encoder);
- writer.start();
+ sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
+ writer->addSource(enc_meta, encoder);
+ writer->start();
sleep(20);
printf("stopping now.\n");
- writer.stop();
+ writer->stop();
#else
encoder->start();
@@ -146,16 +194,7 @@
encoder->stop();
#endif
- delete encoder;
- encoder = NULL;
-
- delete decoder;
- decoder = NULL;
-
client.disconnect();
-
- delete source;
- source = NULL;
#endif
#if 0
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 7e23574..ac6fb36 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -16,81 +16,31 @@
#include <sys/time.h>
-#undef NDEBUG
-#include <assert.h>
-
-#include <pthread.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CachingDataSource.h>
-#include <media/stagefright/ESDS.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
-#include "WaveWriter.h"
+#include "JPEGSource.h"
using namespace android;
-////////////////////////////////////////////////////////////////////////////////
-
-static bool convertToWav(
- OMXClient *client, const sp<MetaData> &meta, MediaSource *source) {
- printf("convertToWav\n");
-
- OMXDecoder *decoder = OMXDecoder::Create(client, meta);
-
- int32_t sampleRate;
- bool success = meta->findInt32(kKeySampleRate, &sampleRate);
- assert(success);
-
- int32_t numChannels;
- success = meta->findInt32(kKeyChannelCount, &numChannels);
- assert(success);
-
- const char *mime;
- success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
-
- if (!strcasecmp("audio/3gpp", mime)) {
- numChannels = 1; // XXX
- }
-
- WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate);
-
- decoder->setSource(source);
- for (int i = 0; i < 100; ++i) {
- MediaBuffer *buffer;
-
- ::status_t err = decoder->read(&buffer);
- if (err != ::OK) {
- break;
- }
-
- writer.Append((const char *)buffer->data() + buffer->range_offset(),
- buffer->range_length());
-
- buffer->release();
- buffer = NULL;
- }
-
- delete decoder;
- decoder = NULL;
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
+static long gNumRepetitions;
+static long gMaxNumFrames; // 0 means decode all available.
static int64_t getNowUs() {
struct timeval tv;
@@ -99,19 +49,147 @@
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
}
+#define USE_OMX_CODEC 1
+
+static void playSource(OMXClient *client, const sp<MediaSource> &source) {
+ sp<MetaData> meta = source->getFormat();
+
+#if !USE_OMX_CODEC
+ sp<OMXDecoder> decoder = OMXDecoder::Create(
+ client, meta, false /* createEncoder */, source);
+#else
+ sp<OMXCodec> decoder = OMXCodec::Create(
+ client->interface(), meta, false /* createEncoder */, source);
+#endif
+
+ if (decoder == NULL) {
+ return;
+ }
+
+ decoder->start();
+
+ int n = 0;
+ int64_t startTime = getNowUs();
+
+ long numIterationsLeft = gNumRepetitions;
+ MediaSource::ReadOptions options;
+
+ while (numIterationsLeft-- > 0) {
+ long numFrames = 0;
+
+ MediaBuffer *buffer;
+
+ for (;;) {
+ status_t err = decoder->read(&buffer, &options);
+ options.clearSeekTo();
+
+ if (err != OK) {
+ CHECK_EQ(buffer, NULL);
+ break;
+ }
+
+ if ((n++ % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+
+ buffer->release();
+ buffer = NULL;
+
+ ++numFrames;
+ if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) {
+ break;
+ }
+ }
+
+ printf("$");
+ fflush(stdout);
+
+ options.setSeekTo(0);
+ }
+
+ decoder->stop();
+ printf("\n");
+
+ int64_t delay = getNowUs() - startTime;
+ printf("avg. %.2f fps\n", n * 1E6 / delay);
+
+ printf("decoded a total of %d frame(s).\n", n);
+}
+
+static void usage(const char *me) {
+ fprintf(stderr, "usage: %s\n", me);
+ fprintf(stderr, " -h(elp)\n");
+ fprintf(stderr, " -a(udio)\n");
+ fprintf(stderr, " -n repetitions\n");
+ fprintf(stderr, " -l(ist) components\n");
+ fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
+}
+
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
bool audioOnly = false;
- if (argc > 1 && !strcmp(argv[1], "--list")) {
+ bool listComponents = false;
+ gNumRepetitions = 1;
+ gMaxNumFrames = 0;
+
+ int res;
+ while ((res = getopt(argc, argv, "han:lm:")) >= 0) {
+ switch (res) {
+ case 'a':
+ {
+ audioOnly = true;
+ break;
+ }
+
+ case 'l':
+ {
+ listComponents = true;
+ break;
+ }
+
+ case 'm':
+ case 'n':
+ {
+ char *end;
+ long x = strtol(optarg, &end, 10);
+
+ if (*end != '\0' || end == optarg || x <= 0) {
+ x = 1;
+ }
+
+ if (res == 'n') {
+ gNumRepetitions = x;
+ } else {
+ gMaxNumFrames = x;
+ }
+ break;
+ }
+
+ case '?':
+ case 'h':
+ default:
+ {
+ usage(argv[0]);
+ exit(1);
+ break;
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (listComponents) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- assert(service.get() != NULL);
+ CHECK(service.get() != NULL);
sp<IOMX> omx = service->createOMX();
- assert(omx.get() != NULL);
+ CHECK(omx.get() != NULL);
List<String8> list;
omx->list_nodes(&list);
@@ -120,90 +198,64 @@
it != list.end(); ++it) {
printf("%s\n", (*it).string());
}
-
- return 0;
- } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
- audioOnly = true;
- ++argv;
- --argc;
}
-#if 0
- MediaPlayerImpl player(argv[1]);
- player.play();
-
- sleep(10000);
-#else
DataSource::RegisterDefaultSniffers();
OMXClient client;
status_t err = client.connect();
- MmapSource *dataSource = new MmapSource(argv[1]);
- MediaExtractor *extractor = MediaExtractor::Create(dataSource);
- dataSource = NULL;
+ for (int k = 0; k < argc; ++k) {
+ const char *filename = argv[k];
- int numTracks;
- err = extractor->countTracks(&numTracks);
-
- sp<MetaData> meta;
- int i;
- for (i = 0; i < numTracks; ++i) {
- meta = extractor->getTrackMetaData(i);
-
- const char *mime;
- meta->findCString(kKeyMIMEType, &mime);
-
- if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
- break;
+ sp<DataSource> dataSource;
+ if (!strncasecmp("http://", filename, 7)) {
+ dataSource = new HTTPDataSource(filename);
+ dataSource = new CachingDataSource(dataSource, 64 * 1024, 10);
+ } else {
+ dataSource = new MmapSource(filename);
}
- if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
- break;
+ bool isJPEG = false;
+
+ size_t len = strlen(filename);
+ if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) {
+ isJPEG = true;
}
- }
- OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
+ sp<MediaSource> mediaSource;
- if (decoder != NULL) {
- MediaSource *source;
- err = extractor->getTrack(i, &source);
+ if (isJPEG) {
+ mediaSource = new JPEGSource(dataSource);
+ } else {
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
- decoder->setSource(source);
+ size_t numTracks = extractor->countTracks();
- decoder->start();
+ sp<MetaData> meta;
+ size_t i;
+ for (i = 0; i < numTracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
- int64_t startTime = getNowUs();
+ const char *mime;
+ meta->findCString(kKeyMIMEType, &mime);
- int n = 0;
- MediaBuffer *buffer;
- while ((err = decoder->read(&buffer)) == OK) {
- if ((++n % 16) == 0) {
- printf(".");
- fflush(stdout);
+ if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+ break;
+ }
+
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
+ break;
+ }
}
- buffer->release();
- buffer = NULL;
+ mediaSource = extractor->getTrack(i);
}
- decoder->stop();
- printf("\n");
- int64_t delay = getNowUs() - startTime;
- printf("avg. %.2f fps\n", n * 1E6 / delay);
-
- delete decoder;
- decoder = NULL;
-
- delete source;
- source = NULL;
+ playSource(&client, mediaSource);
}
- delete extractor;
- extractor = NULL;
-
client.disconnect();
-#endif
return 0;
}
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 2b54f54..e021012 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -16,7 +16,10 @@
package com.android.commands.svc;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.IPowerManager;
+import android.os.PowerManager;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.os.BatteryManager;
@@ -60,7 +63,10 @@
IPowerManager pm
= IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
+ IBinder lock = new Binder();
+ pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power");
pm.setStayOnSetting(val);
+ pm.releaseWakeLock(lock);
}
catch (RemoteException e) {
System.err.println("Faild to set setting: " + e);
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 3ce3ca3..38ae962 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -188,6 +188,25 @@
response.onResult(result);
}
}
+
+ public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
+ Account account) throws RemoteException {
+ checkBinderPermission();
+ try {
+ final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
+ new AccountAuthenticatorResponse(response), account);
+ if (result != null) {
+ response.onResult(result);
+ }
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAccountRemovalAllowed not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ }
}
private void checkBinderPermission() {
@@ -238,4 +257,10 @@
Account account, String authTokenType, Bundle loginOptions);
public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
Account account, String[] features) throws NetworkErrorException;
+ public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
+ Account account) throws NetworkErrorException {
+ final Bundle result = new Bundle();
+ result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true);
+ return result;
+ }
}
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 30c91b0..7b83a30 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -26,20 +26,20 @@
* suitable for use as the key of a {@link java.util.Map}
*/
public class Account implements Parcelable {
- public final String mName;
- public final String mType;
+ public final String name;
+ public final String type;
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Account)) return false;
final Account other = (Account)o;
- return mName.equals(other.mName) && mType.equals(other.mType);
+ return name.equals(other.name) && type.equals(other.type);
}
public int hashCode() {
int result = 17;
- result = 31 * result + mName.hashCode();
- result = 31 * result + mType.hashCode();
+ result = 31 * result + name.hashCode();
+ result = 31 * result + type.hashCode();
return result;
}
@@ -50,13 +50,13 @@
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
- mName = name;
- mType = type;
+ this.name = name;
+ this.type = type;
}
public Account(Parcel in) {
- mName = in.readString();
- mType = in.readString();
+ this.name = in.readString();
+ this.type = in.readString();
}
public int describeContents() {
@@ -64,8 +64,8 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mName);
- dest.writeString(mType);
+ dest.writeString(name);
+ dest.writeString(type);
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
@@ -79,6 +79,6 @@
};
public String toString() {
- return "Account {name=" + mName + ", type=" + mType + "}";
+ return "Account {name=" + name + ", type=" + type + "}";
}
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 502abbb..d04abe5 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -26,8 +26,6 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.Parcelable;
-import android.util.Config;
-import android.util.Log;
import java.io.IOException;
import java.util.concurrent.Callable;
@@ -80,258 +78,132 @@
return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
}
- public String blockingGetPassword(Account account) {
- ensureNotOnMainThread();
+ public String getPassword(final Account account) {
try {
return mService.getPassword(account);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // will never happen
throw new RuntimeException(e);
}
}
- public Future1<String> getPassword(final Future1Callback<String> callback,
- final Account account, final Handler handler) {
- return startAsFuture(callback, handler, new Callable<String>() {
- public String call() throws Exception {
- return blockingGetPassword(account);
- }
- });
- }
-
- public String blockingGetUserData(Account account, String key) {
- ensureNotOnMainThread();
+ public String getUserData(final Account account, final String key) {
try {
return mService.getUserData(account, key);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // will never happen
throw new RuntimeException(e);
}
}
- public Future1<String> getUserData(Future1Callback<String> callback,
- final Account account, final String key, Handler handler) {
- return startAsFuture(callback, handler, new Callable<String>() {
- public String call() throws Exception {
- return blockingGetUserData(account, key);
- }
- });
- }
-
- public AuthenticatorDescription[] blockingGetAuthenticatorTypes() {
- ensureNotOnMainThread();
+ public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
return mService.getAuthenticatorTypes();
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // will never happen
throw new RuntimeException(e);
}
}
- public Future1<AuthenticatorDescription[]> getAuthenticatorTypes(
- Future1Callback<AuthenticatorDescription[]> callback, Handler handler) {
- return startAsFuture(callback, handler, new Callable<AuthenticatorDescription[]>() {
- public AuthenticatorDescription[] call() throws Exception {
- return blockingGetAuthenticatorTypes();
- }
- });
- }
-
- public Account[] blockingGetAccounts() {
- ensureNotOnMainThread();
+ public Account[] getAccounts() {
try {
- return mService.getAccounts();
+ return mService.getAccounts(null);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
throw new RuntimeException(e);
}
}
- public Account[] blockingGetAccountsByType(String accountType) {
- ensureNotOnMainThread();
+ public Account[] getAccountsByType(String type) {
try {
- return mService.getAccountsByType(accountType);
+ return mService.getAccounts(type);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
throw new RuntimeException(e);
}
}
- public Future1<Account[]> getAccounts(Future1Callback<Account[]> callback, Handler handler) {
- return startAsFuture(callback, handler, new Callable<Account[]>() {
- public Account[] call() throws Exception {
- return blockingGetAccounts();
- }
- });
- }
-
- public Future1<Account[]> getAccountsByType(Future1Callback<Account[]> callback,
- final String type, Handler handler) {
- return startAsFuture(callback, handler, new Callable<Account[]>() {
- public Account[] call() throws Exception {
- return blockingGetAccountsByType(type);
- }
- });
- }
-
- public boolean blockingAddAccountExplicitly(Account account, String password, Bundle extras) {
- ensureNotOnMainThread();
+ public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
try {
return mService.addAccount(account, password, extras);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
throw new RuntimeException(e);
}
}
- public Future1<Boolean> addAccountExplicitly(final Future1Callback<Boolean> callback,
- final Account account, final String password, final Bundle extras,
- final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Boolean>() {
- public Boolean call() throws Exception {
- return blockingAddAccountExplicitly(account, password, extras);
+ public AccountManagerFuture<Boolean> removeAccount(final Account account,
+ AccountManagerCallback<Boolean> callback, Handler handler) {
+ return new Future2Task<Boolean>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.removeAccount(mResponse, account);
}
- });
- }
-
- public void blockingRemoveAccount(Account account) {
- ensureNotOnMainThread();
- try {
- mService.removeAccount(account);
- } catch (RemoteException e) {
- // if this happens the entire runtime will restart
- }
- }
-
- public Future1<Void> removeAccount(Future1Callback<Void> callback, final Account account,
- final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingRemoveAccount(account);
- return null;
+ public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
}
- });
+ }.start();
}
- public void blockingInvalidateAuthToken(String accountType, String authToken) {
- ensureNotOnMainThread();
+ public void invalidateAuthToken(final String accountType, final String authToken) {
try {
mService.invalidateAuthToken(accountType, authToken);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
- }
- }
-
- public Future1<Void> invalidateAuthToken(Future1Callback<Void> callback,
- final String accountType, final String authToken, final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingInvalidateAuthToken(accountType, authToken);
- return null;
- }
- });
- }
-
- public String blockingPeekAuthToken(Account account, String authTokenType) {
- ensureNotOnMainThread();
- try {
- return mService.peekAuthToken(account, authTokenType);
- } catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
throw new RuntimeException(e);
}
}
- public Future1<String> peekAuthToken(Future1Callback<String> callback,
- final Account account, final String authTokenType, final Handler handler) {
- return startAsFuture(callback, handler, new Callable<String>() {
- public String call() throws Exception {
- return blockingPeekAuthToken(account, authTokenType);
- }
- });
+ public String peekAuthToken(final Account account, final String authTokenType) {
+ try {
+ return mService.peekAuthToken(account, authTokenType);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
}
- public void blockingSetPassword(Account account, String password) {
- ensureNotOnMainThread();
+ public void setPassword(final Account account, final String password) {
try {
mService.setPassword(account, password);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
+ throw new RuntimeException(e);
}
}
- public Future1<Void> setPassword(Future1Callback<Void> callback,
- final Account account, final String password, final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingSetPassword(account, password);
- return null;
- }
- });
- }
-
- public void blockingClearPassword(Account account) {
- ensureNotOnMainThread();
+ public void clearPassword(final Account account) {
try {
mService.clearPassword(account);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
+ throw new RuntimeException(e);
}
}
- public Future1<Void> clearPassword(final Future1Callback<Void> callback, final Account account,
- final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingClearPassword(account);
- return null;
- }
- });
- }
-
- public void blockingSetUserData(Account account, String key, String value) {
- ensureNotOnMainThread();
+ public void setUserData(final Account account, final String key, final String value) {
try {
mService.setUserData(account, key, value);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
+ throw new RuntimeException(e);
}
}
- public Future1<Void> setUserData(Future1Callback<Void> callback,
- final Account account, final String key, final String value, final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingSetUserData(account, key, value);
- return null;
- }
- });
- }
-
- public void blockingSetAuthToken(Account account, String authTokenType, String authToken) {
- ensureNotOnMainThread();
+ public void setAuthToken(Account account, final String authTokenType, final String authToken) {
try {
mService.setAuthToken(account, authTokenType, authToken);
} catch (RemoteException e) {
- // if this happens the entire runtime will restart
+ // won't ever happen
+ throw new RuntimeException(e);
}
}
- public Future1<Void> setAuthToken(Future1Callback<Void> callback,
- final Account account, final String authTokenType, final String authToken,
- final Handler handler) {
- return startAsFuture(callback, handler, new Callable<Void>() {
- public Void call() throws Exception {
- blockingSetAuthToken(account, authTokenType, authToken);
- return null;
- }
- });
- }
-
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
throws OperationCanceledException, IOException, AuthenticatorException {
- ensureNotOnMainThread();
Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
null /* handler */).getResult();
return bundle.getString(Constants.AUTHTOKEN_KEY);
@@ -349,9 +221,9 @@
* @param loginOptions
* @param activity the activity to launch the login intent, if necessary, and to which
*/
- public Future2 getAuthToken(
+ public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle loginOptions,
- final Activity activity, Future2Callback callback, Handler handler) {
+ final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (activity == null) throw new IllegalArgumentException("activity is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
return new AmsTask(activity, handler, callback) {
@@ -363,9 +235,9 @@
}.start();
}
- public Future2 getAuthToken(
+ public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final boolean notifyAuthFailure,
- Future2Callback callback, Handler handler) {
+ AccountManagerCallback<Bundle> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
return new AmsTask(null, handler, callback) {
@@ -376,10 +248,10 @@
}.start();
}
- public Future2 addAccount(final String accountType,
+ public AccountManagerFuture<Bundle> addAccount(final String accountType,
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
- final Activity activity, Future2Callback callback, Handler handler) {
+ final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
mService.addAcount(mResponse, accountType, authTokenType,
@@ -389,44 +261,46 @@
}
/** @deprecated use {@link #confirmCredentials} instead */
- public Future1<Boolean> confirmPassword(final Account account, final String password,
- Future1Callback<Boolean> callback, Handler handler) {
- return new AMSTaskBoolean(handler, callback) {
+ @Deprecated
+ public AccountManagerFuture<Boolean> confirmPassword(final Account account, final String password,
+ AccountManagerCallback<Boolean> callback, Handler handler) {
+ return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
- mService.confirmPassword(response, account, password);
+ mService.confirmPassword(mResponse, account, password);
}
- };
- }
-
- public Account[] blockingGetAccountsWithTypeAndFeatures(String type, String[] features)
- throws AuthenticatorException, IOException, OperationCanceledException {
- Future2 future = getAccountsWithTypeAndFeatures(type, features,
- null /* callback */, null /* handler */);
- Bundle result = future.getResult();
- Parcelable[] accountsTemp = result.getParcelableArray(Constants.ACCOUNTS_KEY);
- if (accountsTemp == null) {
- throw new AuthenticatorException("accounts should not be null");
- }
- Account[] accounts = new Account[accountsTemp.length];
- for (int i = 0; i < accountsTemp.length; i++) {
- accounts[i] = (Account) accountsTemp[i];
- }
- return accounts;
- }
-
- public Future2 getAccountsWithTypeAndFeatures(
- final String type, final String[] features,
- Future2Callback callback, Handler handler) {
- if (type == null) throw new IllegalArgumentException("type is null");
- return new AmsTask(null /* activity */, handler, callback) {
- public void doWork() throws RemoteException {
- mService.getAccountsByTypeAndFeatures(mResponse, type, features);
+ public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
}
}.start();
}
- public Future2 confirmCredentials(final Account account, final Activity activity,
- final Future2Callback callback,
+ public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+ final String type, final String[] features,
+ AccountManagerCallback<Account[]> callback, Handler handler) {
+ if (type == null) throw new IllegalArgumentException("type is null");
+ return new Future2Task<Account[]>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAccountsByFeatures(mResponse, type, features);
+ }
+ public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.ACCOUNTS_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ final Parcelable[] parcelables = bundle.getParcelableArray(Constants.ACCOUNTS_KEY);
+ Account[] descs = new Account[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ descs[i] = (Account) parcelables[i];
+ }
+ return descs;
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Activity activity,
+ final AccountManagerCallback<Bundle> callback,
final Handler handler) {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
@@ -435,9 +309,9 @@
}.start();
}
- public Future2 updateCredentials(final Account account, final String authTokenType,
+ public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType,
final Bundle loginOptions, final Activity activity,
- final Future2Callback callback,
+ final AccountManagerCallback<Bundle> callback,
final Handler handler) {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
@@ -447,8 +321,8 @@
}.start();
}
- public Future2 editProperties(final String accountType, final Activity activity,
- final Future2Callback callback,
+ public AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity,
+ final AccountManagerCallback<Bundle> callback,
final Handler handler) {
return new AmsTask(activity, handler, callback) {
public void doWork() throws RemoteException {
@@ -471,8 +345,8 @@
}
}
- private void postToHandler(Handler handler, final Future2Callback callback,
- final Future2 future) {
+ private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
+ final AccountManagerFuture<Bundle> future) {
handler = handler == null ? mMainHandler : handler;
handler.post(new Runnable() {
public void run() {
@@ -483,87 +357,24 @@
private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
final Account[] accounts) {
- handler = handler == null ? mMainHandler : handler;
+ final Account[] accountsCopy = new Account[accounts.length];
+ // send a copy to make sure that one doesn't
+ // change what another sees
+ System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
+ handler = (handler == null) ? mMainHandler : handler;
handler.post(new Runnable() {
public void run() {
- listener.onAccountsUpdated(accounts);
+ listener.onAccountsUpdated(accountsCopy);
}
});
}
- private <V> void postToHandler(Handler handler, final Future1Callback<V> callback,
- final Future1<V> future) {
- handler = handler == null ? mMainHandler : handler;
- handler.post(new Runnable() {
- public void run() {
- callback.run(future);
- }
- });
- }
-
- private <V> Future1<V> startAsFuture(Future1Callback<V> callback, Handler handler,
- Callable<V> callable) {
- final FutureTaskWithCallback<V> task =
- new FutureTaskWithCallback<V>(callback, callable, handler);
- new Thread(task).start();
- return task;
- }
-
- private class FutureTaskWithCallback<V> extends FutureTask<V> implements Future1<V> {
- final Future1Callback<V> mCallback;
- final Handler mHandler;
-
- public FutureTaskWithCallback(Future1Callback<V> callback, Callable<V> callable,
- Handler handler) {
- super(callable);
- mCallback = callback;
- mHandler = handler;
- }
-
- protected void done() {
- if (mCallback != null) {
- postToHandler(mHandler, mCallback, this);
- }
- }
-
- public V internalGetResult(Long timeout, TimeUnit unit) throws OperationCanceledException {
- try {
- if (timeout == null) {
- return get();
- } else {
- return get(timeout, unit);
- }
- } catch (InterruptedException e) {
- // we will cancel the task below
- } catch (CancellationException e) {
- // we will cancel the task below
- } catch (TimeoutException e) {
- // we will cancel the task below
- } catch (ExecutionException e) {
- // this should never happen
- throw new IllegalStateException(e.getCause());
- } finally {
- cancel(true /* interruptIfRunning */);
- }
- throw new OperationCanceledException();
- }
-
- public V getResult() throws OperationCanceledException {
- return internalGetResult(null, null);
- }
-
- public V getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
- return internalGetResult(null, null);
- }
- }
-
- private abstract class AmsTask extends FutureTask<Bundle> implements Future2 {
+ private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
final IAccountManagerResponse mResponse;
final Handler mHandler;
- final Future2Callback mCallback;
+ final AccountManagerCallback<Bundle> mCallback;
final Activity mActivity;
- final Thread mThread;
- public AmsTask(Activity activity, Handler handler, Future2Callback callback) {
+ public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
super(new Callable<Bundle>() {
public Bundle call() throws Exception {
throw new IllegalStateException("this should never be called");
@@ -574,19 +385,14 @@
mCallback = callback;
mActivity = activity;
mResponse = new Response();
- mThread = new Thread(new Runnable() {
- public void run() {
- try {
- doWork();
- } catch (RemoteException e) {
- // never happens
- }
- }
- }, "AmsTask");
}
- public final Future2 start() {
- mThread.start();
+ public final AccountManagerFuture<Bundle> start() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
+ }
return this;
}
@@ -594,6 +400,7 @@
private Bundle internalGetResult(Long timeout, TimeUnit unit)
throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
try {
if (timeout == null) {
return get();
@@ -676,92 +483,50 @@
}
- private abstract class AMSTaskBoolean extends FutureTask<Boolean> implements Future1<Boolean> {
- final IAccountManagerResponse response;
+ private abstract class BaseFutureTask<T> extends FutureTask<T> {
+ final public IAccountManagerResponse mResponse;
final Handler mHandler;
- final Future1Callback<Boolean> mCallback;
- public AMSTaskBoolean(Handler handler, Future1Callback<Boolean> callback) {
- super(new Callable<Boolean>() {
- public Boolean call() throws Exception {
+
+ public BaseFutureTask(Handler handler) {
+ super(new Callable<T>() {
+ public T call() throws Exception {
throw new IllegalStateException("this should never be called");
}
});
-
mHandler = handler;
- mCallback = callback;
- response = new Response();
-
- new Thread(new Runnable() {
- public void run() {
- try {
- doWork();
- } catch (RemoteException e) {
- // never happens
- }
- }
- }).start();
+ mResponse = new Response();
}
public abstract void doWork() throws RemoteException;
+ public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
- protected void done() {
- if (mCallback != null) {
- postToHandler(mHandler, mCallback, this);
- }
+ protected void postRunnableToHandler(Runnable runnable) {
+ Handler handler = (mHandler == null) ? mMainHandler : mHandler;
+ handler.post(runnable);
}
- private Boolean internalGetResult(Long timeout, TimeUnit unit) {
+ protected void startTask() {
try {
- if (timeout == null) {
- return get();
- } else {
- return get(timeout, unit);
- }
- } catch (InterruptedException e) {
- // fall through and cancel
- } catch (TimeoutException e) {
- // fall through and cancel
- } catch (CancellationException e) {
- return false;
- } catch (ExecutionException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof IOException) {
- return false;
- } else if (cause instanceof UnsupportedOperationException) {
- return false;
- } else if (cause instanceof AuthenticatorException) {
- return false;
- } else if (cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- } else if (cause instanceof Error) {
- throw (Error) cause;
- } else {
- throw new IllegalStateException(cause);
- }
- } finally {
- cancel(true /* interrupt if running */);
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
}
- return false;
}
- public Boolean getResult() throws OperationCanceledException {
- return internalGetResult(null, null);
- }
-
- public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
- return internalGetResult(timeout, unit);
- }
-
- private class Response extends IAccountManagerResponse.Stub {
+ protected class Response extends IAccountManagerResponse.Stub {
public void onResult(Bundle bundle) {
try {
- if (bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
- set(bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY));
+ T result = bundleToResult(bundle);
+ if (result == null) {
return;
}
+ set(result);
+ return;
} catch (ClassCastException e) {
// we will set the exception below
+ } catch (AuthenticatorException e) {
+ // we will set the exception below
}
onError(Constants.ERROR_CODE_INVALID_RESPONSE, "no result in response");
}
@@ -774,6 +539,76 @@
setException(convertErrorToException(code, message));
}
}
+ }
+
+ private abstract class Future2Task<T>
+ extends BaseFutureTask<T> implements AccountManagerFuture<T> {
+ final AccountManagerCallback<T> mCallback;
+ public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
+ super(handler);
+ mCallback = callback;
+ }
+
+ protected void done() {
+ if (mCallback != null) {
+ postRunnableToHandler(new Runnable() {
+ public void run() {
+ mCallback.run(Future2Task.this);
+ }
+ });
+ }
+ }
+
+ public Future2Task<T> start() {
+ startTask();
+ return this;
+ }
+
+ private T internalGetResult(Long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
+ try {
+ if (timeout == null) {
+ return get();
+ } else {
+ return get(timeout, unit);
+ }
+ } catch (InterruptedException e) {
+ // fall through and cancel
+ } catch (TimeoutException e) {
+ // fall through and cancel
+ } catch (CancellationException e) {
+ // fall through and cancel
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof IOException) {
+ throw (IOException) cause;
+ } else if (cause instanceof UnsupportedOperationException) {
+ throw new AuthenticatorException(cause);
+ } else if (cause instanceof AuthenticatorException) {
+ throw (AuthenticatorException) cause;
+ } else if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new IllegalStateException(cause);
+ }
+ } finally {
+ cancel(true /* interrupt if running */);
+ }
+ throw new OperationCanceledException();
+ }
+
+ public T getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(null, null);
+ }
+
+ public T getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(timeout, unit);
+ }
}
@@ -797,11 +632,12 @@
return new AuthenticatorException(message);
}
- private class GetAuthTokenByTypeAndFeaturesTask extends AmsTask implements Future2Callback {
+ private class GetAuthTokenByTypeAndFeaturesTask
+ extends AmsTask implements AccountManagerCallback<Bundle> {
GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
final String[] features, Activity activityForPrompting,
final Bundle addAccountOptions, final Bundle loginOptions,
- Future2Callback callback, Handler handler) {
+ AccountManagerCallback<Bundle> callback, Handler handler) {
super(activityForPrompting, handler, callback);
if (accountType == null) throw new IllegalArgumentException("account type is null");
mAccountType = accountType;
@@ -811,101 +647,100 @@
mLoginOptions = loginOptions;
mMyCallback = this;
}
- volatile Future2 mFuture = null;
+ volatile AccountManagerFuture<Bundle> mFuture = null;
final String mAccountType;
final String mAuthTokenType;
final String[] mFeatures;
final Bundle mAddAccountOptions;
final Bundle mLoginOptions;
- final Future2Callback mMyCallback;
+ final AccountManagerCallback<Bundle> mMyCallback;
public void doWork() throws RemoteException {
- getAccountsWithTypeAndFeatures(mAccountType, mFeatures, new Future2Callback() {
- public void run(Future2 future) {
- Bundle getAccountsResult;
- try {
- getAccountsResult = future.getResult();
- } catch (OperationCanceledException e) {
- setException(e);
- return;
- } catch (IOException e) {
- setException(e);
- return;
- } catch (AuthenticatorException e) {
- setException(e);
- return;
- }
-
- Parcelable[] accounts =
- getAccountsResult.getParcelableArray(Constants.ACCOUNTS_KEY);
- if (accounts.length == 0) {
- if (mActivity != null) {
- // no accounts, add one now. pretend that the user directly
- // made this request
- mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
- mAddAccountOptions, mActivity, mMyCallback, mHandler);
- } else {
- // send result since we can't prompt to add an account
- Bundle result = new Bundle();
- result.putString(Constants.ACCOUNT_NAME_KEY, null);
- result.putString(Constants.ACCOUNT_TYPE_KEY, null);
- result.putString(Constants.AUTHTOKEN_KEY, null);
+ getAccountsByTypeAndFeatures(mAccountType, mFeatures,
+ new AccountManagerCallback<Account[]>() {
+ public void run(AccountManagerFuture<Account[]> future) {
+ Account[] accounts;
try {
- mResponse.onResult(result);
- } catch (RemoteException e) {
- // this will never happen
+ accounts = future.getResult();
+ } catch (OperationCanceledException e) {
+ setException(e);
+ return;
+ } catch (IOException e) {
+ setException(e);
+ return;
+ } catch (AuthenticatorException e) {
+ setException(e);
+ return;
}
- // we are done
- }
- } else if (accounts.length == 1) {
- // have a single account, return an authtoken for it
- if (mActivity == null) {
- mFuture = getAuthToken((Account) accounts[0], mAuthTokenType,
- false /* notifyAuthFailure */, mMyCallback, mHandler);
- } else {
- mFuture = getAuthToken((Account) accounts[0],
- mAuthTokenType, mLoginOptions,
- mActivity, mMyCallback, mHandler);
- }
- } else {
- if (mActivity != null) {
- IAccountManagerResponse chooseResponse =
- new IAccountManagerResponse.Stub() {
- public void onResult(Bundle value) throws RemoteException {
- Account account = new Account(
- value.getString(Constants.ACCOUNT_NAME_KEY),
- value.getString(Constants.ACCOUNT_TYPE_KEY));
- mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
+
+ if (accounts.length == 0) {
+ if (mActivity != null) {
+ // no accounts, add one now. pretend that the user directly
+ // made this request
+ mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
+ mAddAccountOptions, mActivity, mMyCallback, mHandler);
+ } else {
+ // send result since we can't prompt to add an account
+ Bundle result = new Bundle();
+ result.putString(Constants.ACCOUNT_NAME_KEY, null);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, null);
+ result.putString(Constants.AUTHTOKEN_KEY, null);
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this will never happen
+ }
+ // we are done
+ }
+ } else if (accounts.length == 1) {
+ // have a single account, return an authtoken for it
+ if (mActivity == null) {
+ mFuture = getAuthToken(accounts[0], mAuthTokenType,
+ false /* notifyAuthFailure */, mMyCallback, mHandler);
+ } else {
+ mFuture = getAuthToken(accounts[0],
+ mAuthTokenType, mLoginOptions,
mActivity, mMyCallback, mHandler);
}
+ } else {
+ if (mActivity != null) {
+ IAccountManagerResponse chooseResponse =
+ new IAccountManagerResponse.Stub() {
+ public void onResult(Bundle value) throws RemoteException {
+ Account account = new Account(
+ value.getString(Constants.ACCOUNT_NAME_KEY),
+ value.getString(Constants.ACCOUNT_TYPE_KEY));
+ mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
+ mActivity, mMyCallback, mHandler);
+ }
- public void onError(int errorCode, String errorMessage)
- throws RemoteException {
- mResponse.onError(errorCode, errorMessage);
+ public void onError(int errorCode, String errorMessage)
+ throws RemoteException {
+ mResponse.onError(errorCode, errorMessage);
+ }
+ };
+ // have many accounts, launch the chooser
+ Intent intent = new Intent();
+ intent.setClassName("android",
+ "android.accounts.ChooseAccountActivity");
+ intent.putExtra(Constants.ACCOUNTS_KEY, accounts);
+ intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY,
+ new AccountManagerResponse(chooseResponse));
+ mActivity.startActivity(intent);
+ // the result will arrive via the IAccountManagerResponse
+ } else {
+ // send result since we can't prompt to select an account
+ Bundle result = new Bundle();
+ result.putString(Constants.ACCOUNTS_KEY, null);
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this will never happen
+ }
+ // we are done
}
- };
- // have many accounts, launch the chooser
- Intent intent = new Intent();
- intent.setClassName("android",
- "android.accounts.ChooseAccountActivity");
- intent.putExtra(Constants.ACCOUNTS_KEY, accounts);
- intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY,
- new AccountManagerResponse(chooseResponse));
- mActivity.startActivity(intent);
- // the result will arrive via the IAccountManagerResponse
- } else {
- // send result since we can't prompt to select an account
- Bundle result = new Bundle();
- result.putString(Constants.ACCOUNTS_KEY, null);
- try {
- mResponse.onResult(result);
- } catch (RemoteException e) {
- // this will never happen
}
- // we are done
- }
- }
- }}, mHandler);
+ }}, mHandler);
}
@@ -915,7 +750,7 @@
// or to cause this to be canceled if mFuture isn't set.
// Once this is done then getAuthTokenByFeatures can be changed to return a Future2.
- public void run(Future2 future) {
+ public void run(AccountManagerFuture<Bundle> future) {
try {
set(future.get());
} catch (InterruptedException e) {
@@ -932,7 +767,7 @@
final String accountType, final String authTokenType, final String[] features,
final Activity activityForPrompting, final Bundle addAccountOptions,
final Bundle loginOptions,
- final Future2Callback callback, final Handler handler) {
+ final AccountManagerCallback<Bundle> callback, final Handler handler) {
if (accountType == null) throw new IllegalArgumentException("account type is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
@@ -942,13 +777,6 @@
private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
Maps.newHashMap();
- // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver
- // and its getAccounts() callback which are both invoked only on the main thread. As a
- // result we don't need to protect against concurrent accesses and any changes are guaranteed
- // to be visible when used. Basically, these two variables are thread-confined.
- private Future1<Account[]> mAccountsLookupFuture = null;
- private boolean mAccountLookupPending = false;
-
/**
* BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
* so that it can read the updated list of accounts and send them to the listener
@@ -956,58 +784,14 @@
*/
private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(final Context context, final Intent intent) {
- if (mAccountsLookupFuture != null) {
- // an accounts lookup is already in progress,
- // don't bother starting another request
- mAccountLookupPending = true;
- return;
- }
- // initiate a read of the accounts
- mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() {
- public void run(Future1<Account[]> future) {
- // clear the future so that future receives will try the lookup again
- mAccountsLookupFuture = null;
-
- // get the accounts array
- Account[] accounts;
- try {
- accounts = future.getResult();
- } catch (OperationCanceledException e) {
- // this should never happen, but if it does pretend we got another
- // accounts changed broadcast
- if (Config.LOGD) {
- Log.d(TAG, "the accounts lookup for listener notifications was "
- + "canceled, try again by simulating the receipt of "
- + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast");
- }
- onReceive(context, intent);
- return;
- }
-
- // send the result to the listeners
- synchronized (mAccountsUpdatedListeners) {
- for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
- mAccountsUpdatedListeners.entrySet()) {
- Account[] accountsCopy = new Account[accounts.length];
- // send the listeners a copy to make sure that one doesn't
- // change what another sees
- System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
- postToHandler(entry.getValue(), entry.getKey(), accountsCopy);
- }
- }
-
- // If mAccountLookupPending was set when the account lookup finished it
- // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION
- // intent because a lookup was already in progress. Now that we are done
- // with this lookup and notification pretend that another intent
- // was received by calling onReceive() directly.
- if (mAccountLookupPending) {
- mAccountLookupPending = false;
- onReceive(context, intent);
- return;
- }
+ final Account[] accounts = getAccounts();
+ // send the result to the listeners
+ synchronized (mAccountsUpdatedListeners) {
+ for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
+ mAccountsUpdatedListeners.entrySet()) {
+ postToHandler(entry.getValue(), entry.getKey(), accounts);
}
- }, mMainHandler);
+ }
}
};
@@ -1045,15 +829,7 @@
}
if (updateImmediately) {
- getAccounts(new Future1Callback<Account[]>() {
- public void run(Future1<Account[]> future) {
- try {
- listener.onAccountsUpdated(future.getResult());
- } catch (OperationCanceledException e) {
- // ignore
- }
- }
- }, handler);
+ postToHandler(handler, listener, getAccounts());
}
}
diff --git a/core/java/android/accounts/Future1Callback.java b/core/java/android/accounts/AccountManagerCallback.java
similarity index 87%
rename from core/java/android/accounts/Future1Callback.java
rename to core/java/android/accounts/AccountManagerCallback.java
index 886671b..4aa7169 100644
--- a/core/java/android/accounts/Future1Callback.java
+++ b/core/java/android/accounts/AccountManagerCallback.java
@@ -15,6 +15,6 @@
*/
package android.accounts;
-public interface Future1Callback<V> {
- void run(Future1<V> future);
-}
+public interface AccountManagerCallback<V> {
+ void run(AccountManagerFuture<V> future);
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java
new file mode 100644
index 0000000..74d83eb
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerFuture.java
@@ -0,0 +1,67 @@
+/*
+ * 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.accounts;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.io.IOException;
+
+/**
+ * An extension of {@link java.util.concurrent.Future} that provides wrappers for {@link #get()}
+ * that handle the various
+ * exceptions that {@link #get()} may return and rethrows them as exceptions specific to
+ * {@link android.accounts.AccountManager}.
+ */
+public interface AccountManagerFuture<V> extends Future<V> {
+ /**
+ * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+ * {@link InterruptedException} then the
+ * {@link AccountManagerFuture} is canceled and
+ * {@link android.accounts.OperationCanceledException} is thrown.
+ * @return the {@link android.os.Bundle} that is returned by get()
+ * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+ * CancellationException
+ * or if the Future was interrupted.
+ */
+ V getResult() throws OperationCanceledException, IOException, AuthenticatorException;
+
+ /**
+ * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+ * {@link InterruptedException} then the
+ * {@link AccountManagerFuture} is canceled and
+ * {@link android.accounts.OperationCanceledException} is thrown.
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return the {@link android.os.Bundle} that is returned by
+ * {@link java.util.concurrent.Future#get()}
+ * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+ * {@link java.util.concurrent.CancellationException} or if the {@link AccountManagerFuture}
+ * was interrupted.
+ */
+ V getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException;
+
+ /** @deprecated Use {@link #getResult} */
+ @Deprecated
+ V get() throws InterruptedException, ExecutionException;
+
+ /** @deprecated Use {@link #getResult} */
+ @Deprecated
+ V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException;
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 0c941be..5ed8941 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -23,6 +23,8 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.RegisteredServicesCache;
+import android.content.pm.PackageInfo;
+import android.content.pm.ApplicationInfo;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -44,6 +46,7 @@
import android.app.PendingIntent;
import android.app.NotificationManager;
import android.app.Notification;
+import android.app.Activity;
import android.Manifest;
import java.io.FileDescriptor;
@@ -118,8 +121,7 @@
private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
- private static final Intent ACCOUNTS_CHANGED_INTENT =
- new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ private static final Intent ACCOUNTS_CHANGED_INTENT;
private static final String COUNT_OF_MATCHING_GRANTS = ""
+ "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
@@ -143,6 +145,12 @@
private static final boolean isDebuggableMonkeyBuild =
SystemProperties.getBoolean("ro.monkey", false)
&& SystemProperties.getBoolean("ro.debuggable", false);
+
+ static {
+ ACCOUNTS_CHANGED_INTENT = new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ }
+
/**
* This should only be called by system code. One should only call this after the service
* has started.
@@ -214,10 +222,48 @@
long identityToken = clearCallingIdentity();
try {
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.mName, account.mType}, null, null, null);
+ return readPasswordFromDatabase(account);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private String readPasswordFromDatabase(Account account) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ public String getUserData(Account account, String key) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ return readUserDataFromDatabase(account, key);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private String readUserDataFromDatabase(Account account, String key) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return null;
+ }
+ Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
try {
if (cursor.moveToNext()) {
return cursor.getString(0);
@@ -227,37 +273,7 @@
cursor.close();
}
} finally {
- restoreCallingIdentity(identityToken);
- }
- }
-
- public String getUserData(Account account, String key) {
- checkAuthenticateAccountsPermission(account);
- long identityToken = clearCallingIdentity();
- try {
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId < 0) {
- return null;
- }
- Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
- EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
- new String[]{key}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- return null;
- } finally {
- cursor.close();
- }
- } finally {
- db.endTransaction();
- }
- } finally {
- restoreCallingIdentity(identityToken);
+ db.endTransaction();
}
}
@@ -280,39 +296,23 @@
}
}
- public Account[] getAccounts() {
- checkReadAccountsPermission();
- long identityToken = clearCallingIdentity();
- try {
- return getAccountsByType(null);
- } finally {
- restoreCallingIdentity(identityToken);
- }
- }
-
public Account[] getAccountsByType(String accountType) {
- checkReadAccountsPermission();
- long identityToken = clearCallingIdentity();
- try {
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
- final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
- Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
- selection, selectionArgs, null, null, null);
- try {
- int i = 0;
- Account[] accounts = new Account[cursor.getCount()];
- while (cursor.moveToNext()) {
- accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
- i++;
- }
- return accounts;
- } finally {
- cursor.close();
+ final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
+ final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
+ Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
+ selection, selectionArgs, null, null, null);
+ try {
+ int i = 0;
+ Account[] accounts = new Account[cursor.getCount()];
+ while (cursor.moveToNext()) {
+ accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
+ i++;
}
+ return accounts;
} finally {
- restoreCallingIdentity(identityToken);
+ cursor.close();
}
}
@@ -322,43 +322,47 @@
// fails if the account already exists
long identityToken = clearCallingIdentity();
try {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long numMatches = DatabaseUtils.longForQuery(db,
- "select count(*) from " + TABLE_ACCOUNTS
- + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.mName, account.mType});
- if (numMatches > 0) {
- return false;
- }
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.mName);
- values.put(ACCOUNTS_TYPE, account.mType);
- values.put(ACCOUNTS_PASSWORD, password);
- long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
- if (accountId < 0) {
- return false;
- }
- if (extras != null) {
- for (String key : extras.keySet()) {
- final String value = extras.getString(key);
- if (insertExtra(db, accountId, key, value) < 0) {
- return false;
- }
- }
- }
- db.setTransactionSuccessful();
- sendAccountsChangedBroadcast();
- return true;
- } finally {
- db.endTransaction();
- }
+ return insertAccountIntoDatabase(account, password, extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
+ private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long numMatches = DatabaseUtils.longForQuery(db,
+ "select count(*) from " + TABLE_ACCOUNTS
+ + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ if (numMatches > 0) {
+ return false;
+ }
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_PASSWORD, password);
+ long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ if (accountId < 0) {
+ return false;
+ }
+ if (extras != null) {
+ for (String key : extras.keySet()) {
+ final String value = extras.getString(key);
+ if (insertExtra(db, accountId, key, value) < 0) {
+ return false;
+ }
+ }
+ }
+ db.setTransactionSuccessful();
+ sendAccountsChangedBroadcast();
+ return true;
+ } finally {
+ db.endTransaction();
+ }
+ }
+
private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
ContentValues values = new ContentValues();
values.put(EXTRAS_KEY, key);
@@ -367,19 +371,61 @@
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
}
- public void removeAccount(Account account) {
+ public void removeAccount(IAccountManagerResponse response, Account account) {
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.mName, account.mType});
- sendAccountsChangedBroadcast();
+ new RemoveAccountSession(response, account).bind();
} finally {
restoreCallingIdentity(identityToken);
}
}
+ private class RemoveAccountSession extends Session {
+ final Account mAccount;
+ public RemoveAccountSession(IAccountManagerResponse response, Account account) {
+ super(response, account.type, false /* expectActivityLaunch */);
+ mAccount = account;
+ }
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", removeAccount"
+ + ", account " + mAccount;
+ }
+
+ public void run() throws RemoteException {
+ mAuthenticator.getAccountRemovalAllowed(this, mAccount);
+ }
+
+ public void onResult(Bundle result) {
+ if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY)
+ && !result.containsKey(Constants.INTENT_KEY)) {
+ final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY);
+ if (removalAllowed) {
+ removeAccount(mAccount);
+ }
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ Bundle result2 = new Bundle();
+ result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed);
+ try {
+ response.onResult(result2);
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ }
+ super.onResult(result);
+ }
+ }
+
+ private void removeAccount(Account account) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ sendAccountsChangedBroadcast();
+ }
+
public void invalidateAuthToken(String accountType, String authToken) {
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
@@ -398,6 +444,9 @@
}
private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
+ if (authToken == null || accountType == null) {
+ return;
+ }
Cursor cursor = db.rawQuery(
"SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
@@ -488,7 +537,7 @@
values.put(ACCOUNTS_PASSWORD, password);
mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
- new String[]{account.mName, account.mType});
+ new String[]{account.name, account.type});
sendAccountsChangedBroadcast();
} finally {
restoreCallingIdentity(identityToken);
@@ -509,40 +558,58 @@
}
}
+ private void sendResult(IAccountManagerResponse response, Bundle bundle) {
+ if (response != null) {
+ try {
+ response.onResult(bundle);
+ } catch (RemoteException e) {
+ // if the caller is dead then there is no one to care about remote
+ // exceptions
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "failure while notifying response", e);
+ }
+ }
+ }
+ }
+
public void setUserData(Account account, String key, String value) {
checkAuthenticateAccountsPermission(account);
long identityToken = clearCallingIdentity();
try {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountId(db, account);
- if (accountId < 0) {
- return;
- }
- long extrasId = getExtrasId(db, accountId, key);
- if (extrasId < 0 ) {
- extrasId = insertExtra(db, accountId, key, value);
- if (extrasId < 0) {
- return;
- }
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
- return;
- }
-
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
+ writeUserdataIntoDatabase(account, key, value);
} finally {
restoreCallingIdentity(identityToken);
}
}
+ private void writeUserdataIntoDatabase(Account account, String key, String value) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return;
+ }
+ long extrasId = getExtrasId(db, accountId, key);
+ if (extrasId < 0 ) {
+ extrasId = insertExtra(db, accountId, key, value);
+ if (extrasId < 0) {
+ return;
+ }
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
+ }
+
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
private void onResult(IAccountManagerResponse response, Bundle result) {
try {
response.onResult(result);
@@ -571,14 +638,14 @@
if (authToken != null) {
Bundle result = new Bundle();
result.putString(Constants.AUTHTOKEN_KEY, authToken);
- result.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
- result.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+ result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
onResult(response, result);
return;
}
}
- new Session(response, account.mType, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch) {
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", getAuthToken"
@@ -651,7 +718,7 @@
mContext.getText(R.string.permission_request_notification_subtitle);
n.setLatestEventInfo(mContext,
mContext.getText(R.string.permission_request_notification_title),
- String.format(subtitleFormatString.toString(), account.mName),
+ String.format(subtitleFormatString.toString(), account.name),
PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
@@ -661,9 +728,9 @@
AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(account.mType));
+ AuthenticatorDescription.newKey(account.type));
if (serviceInfo == null) {
- throw new IllegalArgumentException("unknown account type: " + account.mType);
+ throw new IllegalArgumentException("unknown account type: " + account.type);
}
final Context authContext;
@@ -671,7 +738,7 @@
authContext = mContext.createPackageContext(
serviceInfo.type.packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
- throw new IllegalArgumentException("unknown account type: " + account.mType);
+ throw new IllegalArgumentException("unknown account type: " + account.type);
}
Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
@@ -750,7 +817,7 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, account.mType, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch) {
public void run() throws RemoteException {
mAuthenticator.confirmCredentials(this, account);
}
@@ -769,7 +836,7 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, account.mType, false /* expectActivityLaunch */) {
+ new Session(response, account.type, false /* expectActivityLaunch */) {
public void run() throws RemoteException {
mAuthenticator.confirmPassword(this, account, password);
}
@@ -789,7 +856,7 @@
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
try {
- new Session(response, account.mType, expectActivityLaunch) {
+ new Session(response, account.type, expectActivityLaunch) {
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
}
@@ -898,10 +965,21 @@
+ ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
}
}
- public void getAccountsByTypeAndFeatures(IAccountManagerResponse response,
+
+ public Account[] getAccounts(String type) {
+ checkReadAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ return getAccountsByType(type);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void getAccountsByFeatures(IAccountManagerResponse response,
String type, String[] features) {
checkReadAccountsPermission();
- if (type == null) {
+ if (features != null && type == null) {
if (response != null) {
try {
response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
@@ -913,6 +991,10 @@
}
long identityToken = clearCallingIdentity();
try {
+ if (features == null || features.length == 0) {
+ getAccountsByType(type);
+ return;
+ }
new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
} finally {
restoreCallingIdentity(identityToken);
@@ -925,7 +1007,7 @@
private long getAccountId(SQLiteDatabase db, Account account) {
Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.mName, account.mType}, null, null, null);
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
try {
if (cursor.moveToNext()) {
return cursor.getLong(0);
@@ -1400,8 +1482,24 @@
}
}
+ private boolean inSystemImage(int callerUid) {
+ String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
+ for (String name : packages) {
+ try {
+ PackageInfo packageInfo =
+ mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
+ if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
- final boolean fromAuthenticator = hasAuthenticatorUid(account.mType, callerUid);
+ final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
@@ -1409,14 +1507,16 @@
+ ": is authenticator? " + fromAuthenticator
+ ", has explicit permission? " + hasExplicitGrants);
}
- return fromAuthenticator || hasExplicitGrants;
+ return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
}
private boolean hasAuthenticatorUid(String accountType, int callingUid) {
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
mAuthenticatorCache.getAllServices()) {
if (serviceInfo.type.type.equals(accountType)) {
- return serviceInfo.uid == callingUid;
+ return (serviceInfo.uid == callingUid) ||
+ (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
+ == PackageManager.SIGNATURE_MATCH);
}
}
return false;
@@ -1428,7 +1528,7 @@
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
- account.mName, account.mType};
+ account.name, account.type};
final boolean permissionGranted =
DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
if (!permissionGranted && isDebuggableMonkeyBuild) {
@@ -1444,7 +1544,7 @@
private void checkCallingUidAgainstAuthenticator(Account account) {
final int uid = Binder.getCallingUid();
- if (!hasAuthenticatorUid(account.mType, uid)) {
+ if (!hasAuthenticatorUid(account.type, uid)) {
String msg = "caller uid " + uid + " is different than the authenticator's uid";
Log.w(TAG, msg);
throw new SecurityException(msg);
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 83377f3..bd6f205 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -45,7 +45,7 @@
String[] mAccountNames = new String[mAccounts.length];
for (int i = 0; i < mAccounts.length; i++) {
- mAccountNames[i] = ((Account) mAccounts[i]).mName;
+ mAccountNames[i] = ((Account) mAccounts[i]).name;
}
// Use an existing ListAdapter that will map an array
@@ -59,8 +59,8 @@
Account account = (Account) mAccounts[position];
Log.d(TAG, "selected account " + account);
Bundle bundle = new Bundle();
- bundle.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
- bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+ bundle.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+ bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
mResult = bundle;
finish();
}
diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java
index da8173f..8736f41 100644
--- a/core/java/android/accounts/Constants.java
+++ b/core/java/android/accounts/Constants.java
@@ -31,6 +31,7 @@
public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types";
public static final String USERDATA_KEY = "userdata";
public static final String AUTHTOKEN_KEY = "authtoken";
+ public static final String PASSWORD_KEY = "password";
public static final String ACCOUNT_NAME_KEY = "authAccount";
public static final String ACCOUNT_TYPE_KEY = "accountType";
public static final String ERROR_CODE_KEY = "errorCode";
diff --git a/core/java/android/accounts/Future1.java b/core/java/android/accounts/Future1.java
deleted file mode 100644
index 386cb6e..0000000
--- a/core/java/android/accounts/Future1.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.accounts;
-
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
- * exceptions that {@link #get()} may return and rethrows them as exceptions specific to
- * {@link AccountManager}.
- */
-public interface Future1<V> extends Future<V> {
- /**
- * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
- * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
- * @return the {@link android.os.Bundle} that is returned by get()
- * @throws OperationCanceledException if get() throws the unchecked CancellationException
- * or if the Future was interrupted.
- */
- V getResult() throws OperationCanceledException;
-
- /**
- * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
- * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
- * @throws OperationCanceledException if get() throws the unchecked
- * {@link java.util.concurrent.CancellationException} or if the {@link Future1} was interrupted.
- */
- V getResult(long timeout, TimeUnit unit) throws OperationCanceledException;
-}
\ No newline at end of file
diff --git a/core/java/android/accounts/Future2.java b/core/java/android/accounts/Future2.java
deleted file mode 100644
index b2ea84f..0000000
--- a/core/java/android/accounts/Future2.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.accounts;
-
-import android.os.Bundle;
-
-import java.io.IOException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
- * exceptions that {@link #get()} may return and rethrows them as exceptions specific to
- * {@link AccountManager}.
- */
-public interface Future2 extends Future<Bundle> {
- /**
- * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
- * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
- * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
- * @throws OperationCanceledException if get() throws the unchecked
- * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
- * @throws IOException if the request was unable to complete due to a network error
- * @throws AuthenticatorException if there was an error communicating with the
- * {@link AbstractAccountAuthenticator}.
- */
- Bundle getResult()
- throws OperationCanceledException, IOException, AuthenticatorException;
-
- /**
- * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
- * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
- * @throws OperationCanceledException if get() throws the unchecked
- * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
- * @throws IOException if the request was unable to complete due to a network error
- * @throws AuthenticatorException if there was an error communicating with the
- * {@link AbstractAccountAuthenticator}.
- */
- Bundle getResult(long timeout, TimeUnit unit)
- throws OperationCanceledException, IOException, AuthenticatorException;
-}
diff --git a/core/java/android/accounts/Future2Callback.java b/core/java/android/accounts/Future2Callback.java
deleted file mode 100644
index 7ef0c94..0000000
--- a/core/java/android/accounts/Future2Callback.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.accounts;
-
-public interface Future2Callback {
- void run(Future2 future);
-}
\ No newline at end of file
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index f92d43f..e06afb4 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -63,12 +63,12 @@
CharSequence grantCredentialsPermissionFormat = getResources().getText(
R.string.grant_credentials_permission_message_desc);
messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
- mAccount.mName, accountTypeLabel));
+ mAccount.name, accountTypeLabel));
} else {
CharSequence grantCredentialsPermissionFormat = getResources().getText(
R.string.grant_credentials_permission_message_with_authtokenlabel_desc);
messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
- authTokenLabel, mAccount.mName, accountTypeLabel));
+ authTokenLabel, mAccount.name, accountTypeLabel));
}
String[] packageLabels = new String[packages.length];
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 7d4de39..1592eea 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -32,7 +32,7 @@
/**
* Checks that the account/password combination is valid.
- * @deprecated
+ * note -- deprecated
*/
void confirmPassword(in IAccountAuthenticatorResponse response,
in Account account, String password);
@@ -70,4 +70,9 @@
*/
void hasFeatures(in IAccountAuthenticatorResponse response, in Account account,
in String[] features);
+
+ /**
+ * Gets whether or not the account is allowed to be removed.
+ */
+ void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 15ab4e8..411952b 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -21,6 +21,7 @@
import android.accounts.AuthenticatorDescription;
import android.os.Bundle;
+
/**
* Central application service that provides account management.
* @hide
@@ -29,10 +30,10 @@
String getPassword(in Account account);
String getUserData(in Account account, String key);
AuthenticatorDescription[] getAuthenticatorTypes();
- Account[] getAccounts();
- Account[] getAccountsByType(String accountType);
+ Account[] getAccounts(String accountType);
+ void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
boolean addAccount(in Account account, String password, in Bundle extras);
- void removeAccount(in Account account);
+ void removeAccount(in IAccountManagerResponse response, in Account account);
void invalidateAuthToken(String accountType, String authToken);
String peekAuthToken(in Account account, String authTokenType);
void setAuthToken(in Account account, String authTokenType, String authToken);
@@ -52,8 +53,6 @@
boolean expectActivityLaunch);
void confirmCredentials(in IAccountManagerResponse response, in Account account,
boolean expectActivityLaunch);
- void getAccountsByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
- in String[] features);
/*
* @deprecated
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2f79fe9..80d7285 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1930,11 +1930,32 @@
*
* @see #hasWindowFocus()
* @see #onResume
+ * @see View#onWindowFocusChanged(boolean)
*/
public void onWindowFocusChanged(boolean hasFocus) {
}
/**
+ * Called when the main window associated with the activity has been
+ * attached to the window manager.
+ * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
+ * for more information.
+ * @see View#onAttachedToWindow
+ */
+ public void onAttachedToWindow() {
+ }
+
+ /**
+ * Called when the main window associated with the activity has been
+ * detached from the window manager.
+ * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}
+ * for more information.
+ * @see View#onDetachedFromWindow
+ */
+ public void onDetachedFromWindow() {
+ }
+
+ /**
* Returns true if this activity's <em>main</em> window currently has window focus.
* Note that this is not the same as the view itself having focus.
*
@@ -2522,7 +2543,7 @@
* no extra data is required.
* @param globalSearch If false, this will only launch the search that has been specifically
* defined by the application (which is usually defined as a local search). If no default
- * search is defined in the current application or activity, no search will be launched.
+ * search is defined in the current application or activity, global search will be launched.
* If true, this will always launch a platform-global (e.g. web-based) search instead.
*
* @see android.app.SearchManager
@@ -2536,6 +2557,25 @@
}
/**
+ * Similar to {@link #startSearch}, but actually fires off the search query after invoking
+ * the search dialog. Made available for testing purposes.
+ *
+ * @param query The query to trigger. If empty, the request will be ignored.
+ * @param appSearchData An application can insert application-specific
+ * context here, in order to improve quality or specificity of its own
+ * searches. This data will be returned with SEARCH intent(s). Null if
+ * no extra data is required.
+ * @param globalSearch If false, this will only launch the search that has been specifically
+ * defined by the application (which is usually defined as a local search). If no default
+ * search is defined in the current application or activity, no search will be launched.
+ * If true, this will always launch a platform-global (e.g. web-based) search instead.
+ */
+ public void triggerSearch(String query, Bundle appSearchData, boolean globalSearch) {
+ ensureSearchManager();
+ mSearchManager.triggerSearch(query, getComponentName(), appSearchData, globalSearch);
+ }
+
+ /**
* Request that key events come to this activity. Use this if your
* activity has no views with focus, but the activity still wants
* a chance to process key events.
@@ -3256,7 +3296,7 @@
throw new IllegalArgumentException("no ident");
}
}
- mSearchManager.setIdent(ident);
+ mSearchManager.setIdent(ident, getComponentName());
}
@Override
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 447512a..d14ec15 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -39,9 +39,6 @@
import android.util.Config;
import android.util.Log;
-import java.io.FileNotFoundException;
-import java.io.FileDescriptor;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -551,8 +548,13 @@
data.enforceInterface(IActivityManager.descriptor);
ComponentName className = ComponentName.readFromParcel(data);
IBinder token = data.readStrongBinder();
- boolean isForeground = data.readInt() != 0;
- setServiceForeground(className, token, isForeground);
+ int id = data.readInt();
+ Notification notification = null;
+ if (data.readInt() != 0) {
+ notification = Notification.CREATOR.createFromParcel(data);
+ }
+ boolean removeNotification = data.readInt() != 0;
+ setServiceForeground(className, token, id, notification, removeNotification);
reply.writeNoException();
return true;
}
@@ -606,7 +608,10 @@
case SERVICE_DONE_EXECUTING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- serviceDoneExecuting(token);
+ int type = data.readInt();
+ int startId = data.readInt();
+ int res = data.readInt();
+ serviceDoneExecuting(token, type, startId, res);
reply.writeNoException();
return true;
}
@@ -1664,13 +1669,20 @@
return res;
}
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) throws RemoteException {
+ int id, Notification notification, boolean removeNotification) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
ComponentName.writeToParcel(className, data);
data.writeStrongBinder(token);
- data.writeInt(isForeground ? 1 : 0);
+ data.writeInt(id);
+ if (notification != null) {
+ data.writeInt(1);
+ notification.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ data.writeInt(removeNotification ? 1 : 0);
mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -1737,11 +1749,15 @@
reply.recycle();
}
- public void serviceDoneExecuting(IBinder token) throws RemoteException {
+ public void serviceDoneExecuting(IBinder token, int type, int startId,
+ int res) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
+ data.writeInt(type);
+ data.writeInt(startId);
+ data.writeInt(res);
mRemote.transact(SERVICE_DONE_EXECUTING_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e045105..1e915b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1215,6 +1215,7 @@
private static final class ServiceArgsData {
IBinder token;
int startId;
+ int flags;
Intent args;
public String toString() {
return "ServiceArgsData{token=" + token + " startId=" + startId
@@ -1417,10 +1418,11 @@
}
public final void scheduleServiceArgs(IBinder token, int startId,
- Intent args) {
+ int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.startId = startId;
+ s.flags = flags;
s.args = args;
queueOrSendMessage(H.SERVICE_ARGS, s);
@@ -2684,7 +2686,8 @@
service.onCreate();
mServices.put(data.token, service);
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ data.token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
@@ -2710,7 +2713,7 @@
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token);
+ data.token, 0, 0, 0);
}
} catch (RemoteException ex) {
}
@@ -2736,7 +2739,7 @@
data.token, data.intent, doRebind);
} else {
ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token);
+ data.token, 0, 0, 0);
}
} catch (RemoteException ex) {
}
@@ -2773,9 +2776,10 @@
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
- s.onStart(data.args, data.startId);
+ int res = s.onStartCommand(data.args, data.flags, data.startId);
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ data.token, 1, data.startId, res);
} catch (RemoteException e) {
// nothing to do.
}
@@ -2801,7 +2805,8 @@
((ApplicationContext) context).scheduleFinalCleanup(who, "Service");
}
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index a74fbe4..7c0d1d3 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -22,8 +22,8 @@
import org.xmlpull.v1.XmlPullParserException;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -158,8 +158,6 @@
private static ConnectivityManager sConnectivityManager;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
- private static boolean sIsBluetoothDeviceCached = false;
- private static BluetoothDevice sBluetoothDevice;
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
new HashMap<File, SharedPreferencesImpl>();
@@ -184,6 +182,8 @@
private StatusBarManager mStatusBarManager = null;
private TelephonyManager mTelephonyManager = null;
private ClipboardManager mClipboardManager = null;
+ private boolean mIsBluetoothAdapterCached = false;
+ private BluetoothAdapter mBluetoothAdapter;
private boolean mRestricted;
private final Object mSync = new Object();
@@ -830,7 +830,7 @@
} else if (SENSOR_SERVICE.equals(name)) {
return getSensorManager();
} else if (BLUETOOTH_SERVICE.equals(name)) {
- return getBluetoothDevice();
+ return getBluetoothAdapter();
} else if (VIBRATOR_SERVICE.equals(name)) {
return getVibrator();
} else if (STATUS_BAR_SERVICE.equals(name)) {
@@ -980,21 +980,16 @@
return mSearchManager;
}
- private BluetoothDevice getBluetoothDevice() {
- if (sIsBluetoothDeviceCached) {
- return sBluetoothDevice;
- }
- synchronized (sSync) {
+ private synchronized BluetoothAdapter getBluetoothAdapter() {
+ if (!mIsBluetoothAdapterCached) {
+ mIsBluetoothAdapterCached = true;
IBinder b = ServiceManager.getService(BLUETOOTH_SERVICE);
- if (b == null) {
- sBluetoothDevice = null;
- } else {
- IBluetoothDevice service = IBluetoothDevice.Stub.asInterface(b);
- sBluetoothDevice = new BluetoothDevice(service);
+ if (b != null) {
+ IBluetooth service = IBluetooth.Stub.asInterface(b);
+ mBluetoothAdapter = new BluetoothAdapter(service);
}
- sIsBluetoothDeviceCached = true;
}
- return sBluetoothDevice;
+ return mBluetoothAdapter;
}
private SensorManager getSensorManager() {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 5335239..ad64465 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -206,8 +206,14 @@
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
int startId = data.readInt();
- Intent args = Intent.CREATOR.createFromParcel(data);
- scheduleServiceArgs(token, startId, args);
+ int fl = data.readInt();
+ Intent args;
+ if (data.readInt() != 0) {
+ args = Intent.CREATOR.createFromParcel(data);
+ } else {
+ args = null;
+ }
+ scheduleServiceArgs(token, startId, fl, args);
return true;
}
@@ -573,12 +579,18 @@
}
public final void scheduleServiceArgs(IBinder token, int startId,
- Intent args) throws RemoteException {
+ int flags, Intent args) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(startId);
- args.writeToParcel(data, 0);
+ data.writeInt(flags);
+ if (args != null) {
+ data.writeInt(1);
+ args.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(SCHEDULE_SERVICE_ARGS_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 9432755..35d1004 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -576,6 +576,12 @@
public void onWindowFocusChanged(boolean hasFocus) {
}
+ public void onAttachedToWindow() {
+ }
+
+ public void onDetachedFromWindow() {
+ }
+
/**
* Called to process key events. You can override this to intercept all
* key events before they are dispatched to the window. Be sure to call
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f6ef549..c3e7224 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -139,7 +139,7 @@
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) throws RemoteException;
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) throws RemoteException;
+ int id, Notification notification, boolean keepNotification) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags) throws RemoteException;
@@ -149,7 +149,8 @@
public void unbindFinished(IBinder token, Intent service,
boolean doRebind) throws RemoteException;
/* oneway */
- public void serviceDoneExecuting(IBinder token) throws RemoteException;
+ public void serviceDoneExecuting(IBinder token, int type, int startId,
+ int res) throws RemoteException;
public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index c915770..6faaa34 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -71,7 +71,8 @@
Intent intent, boolean rebind) throws RemoteException;
void scheduleUnbindService(IBinder token,
Intent intent) throws RemoteException;
- void scheduleServiceArgs(IBinder token, int startId, Intent args) throws RemoteException;
+ void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args)
+ throws RemoteException;
void scheduleStopService(IBinder token) throws RemoteException;
static final int DEBUG_OFF = 0;
static final int DEBUG_ON = 1;
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index bd72544..ed5dd3d 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -36,6 +36,17 @@
boolean globalSearch,
ISearchManagerCallback searchManagerCallback,
int ident);
+
+ void triggerSearch(in String query,
+ in ComponentName launchActivity,
+ in Bundle appSearchData,
+ ISearchManagerCallback searchManagerCallback,
+ boolean globalSearch,
+ int ident);
+
void stopSearch();
+
+
boolean isVisible();
+
}
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 2b12a2a..804c8eb 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -18,6 +18,7 @@
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
+ private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
@@ -36,6 +37,19 @@
mName = name;
}
+ /**
+ * Control redelivery of intents. If called with true,
+ * {@link #onStartCommand(Intent, int, int)} will return
+ * {@link Service#START_REDELIVER_INTENT} instead of
+ * {@link Service#START_NOT_STICKY}, so that if this service's process
+ * is called while it is executing the Intent in
+ * {@link #onHandleIntent(Intent)}, then when later restarted the same Intent
+ * will be re-delivered to it, to retry its execution.
+ */
+ public void setIntentRedelivery(boolean enabled) {
+ mRedelivery = enabled;
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -48,7 +62,6 @@
@Override
public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
@@ -56,6 +69,12 @@
}
@Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ onStart(intent, startId);
+ return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
+ }
+
+ @Override
public void onDestroy() {
mServiceLooper.quit();
}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index d788c43..a83f4e8 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -70,13 +71,15 @@
ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
this.resolveInfo = resolveInfo;
label = resolveInfo.loadLabel(pm);
- if (label == null && resolveInfo.activityInfo != null) {
+ ComponentInfo ci = resolveInfo.activityInfo;
+ if (ci == null) ci = resolveInfo.serviceInfo;
+ if (label == null && ci != null) {
label = resolveInfo.activityInfo.name;
}
icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
- packageName = resolveInfo.activityInfo.applicationInfo.packageName;
- className = resolveInfo.activityInfo.name;
+ packageName = ci.applicationInfo.packageName;
+ className = ci.name;
}
public ListItem() {
@@ -325,8 +328,7 @@
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(true);
- setContentView(com.android.internal.R.layout.activity_list);
-
+ onSetContentView();
mIntent = new Intent(getTargetIntent());
mIntent.setComponent(null);
@@ -338,10 +340,17 @@
setProgressBarIndeterminateVisibility(false);
}
+ /**
+ * Override to call setContentView() with your own content view to
+ * customize the list layout.
+ */
+ protected void onSetContentView() {
+ setContentView(com.android.internal.R.layout.activity_list);
+ }
+
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
- Intent intent = ((ActivityAdapter)mAdapter).intentForPosition(position);
-
+ Intent intent = intentForPosition(position);
startActivity(intent);
}
@@ -374,12 +383,19 @@
}
/**
+ * Perform query on package manager for list items. The default
+ * implementation queries for activities.
+ */
+ protected List<ResolveInfo> onQueryPackageManager(Intent queryIntent) {
+ return mPackageManager.queryIntentActivities(queryIntent, /* no flags */ 0);
+ }
+
+ /**
* Perform the query to determine which results to show and return a list of them.
*/
public List<ListItem> makeListItems() {
// Load all matching activities and sort correctly
- List<ResolveInfo> list = mPackageManager.queryIntentActivities(mIntent,
- /* no flags */ 0);
+ List<ResolveInfo> list = onQueryPackageManager(mIntent);
Collections.sort(list, new ResolveInfo.DisplayNameComparator(mPackageManager));
IconResizer resizer = new IconResizer();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a67e60b..be5a7d3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -257,6 +257,13 @@
*/
public static final int FLAG_NO_CLEAR = 0x00000020;
+ /**
+ * Bit to be bitwise-ored into the {@link #flags} field that should be
+ * set if this notification represents a currently running service. This
+ * will normally be set for you by {@link Service#startForeground}.
+ */
+ public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
+
public int flags;
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 39edab7..7b51fdf 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -61,7 +61,8 @@
private static INotificationManager sService;
- static private INotificationManager getService()
+ /** @hide */
+ static public INotificationManager getService()
{
if (sService != null) {
return sService;
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index b75bec2..f776452 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -428,7 +428,7 @@
mSearchAutoComplete.setAdapter((SuggestionsAdapter)null);
// close any leftover cursor
if (mSuggestionsAdapter != null) {
- mSuggestionsAdapter.changeCursor(null);
+ mSuggestionsAdapter.close();
}
mSuggestionsAdapter = null;
}
@@ -1120,7 +1120,7 @@
/**
* Launch a search for the text in the query text field.
*/
- protected void launchQuerySearch() {
+ public void launchQuerySearch() {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 97d46f8..e43834a 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -29,6 +29,7 @@
import android.server.search.SearchableInfo;
import android.util.Log;
import android.view.KeyEvent;
+import android.text.TextUtils;
import java.util.List;
@@ -51,8 +52,6 @@
* <li><a href="#HowSearchIsInvoked">How Search Is Invoked</a>
* <li><a href="#ImplementingSearchForYourApp">Implementing Search for Your App</a>
* <li><a href="#Suggestions">Search Suggestions</a>
- * <li><a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to
- * Quick Search Box</a></li>
* <li><a href="#ActionKeys">Action Keys</a>
* <li><a href="#SearchabilityMetadata">Searchability Metadata</a>
* <li><a href="#PassingSearchContext">Passing Search Context</a>
@@ -248,12 +247,6 @@
* <li>Summaries of possible results</li>
* </ul>
*
- * <p>Once an application is configured to provide search suggestions, those same suggestions can
- * easily be made available to the system-wide Quick Search Box, providing faster access to its
- * content from on central prominent place. See
- * <a href="#ExposingSearchSuggestionsToQuickSearchBox">Exposing Search Suggestions to Quick Search
- * Box</a> for more details.
- *
* <p>The primary form of suggestions is known as <i>queried suggestions</i> and is based on query
* text that the user has already typed. This would generally be based on partial matches in
* the available data. In certain situations - for example, when no query text has been typed yet -
@@ -488,26 +481,6 @@
* {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}, optional otherwise.</td>
* </tr>
*
- * <tr><th>{@link #SUGGEST_COLUMN_SHORTCUT_ID}</th>
- * <td>This column is used to indicate whether a search suggestion should be stored as a
- * shortcut, and whether it should be validated. Shortcuts are usually formed when the
- * user clicks a suggestion from Quick Search Box. If missing, the result will be
- * stored as a shortcut and never refreshed. If set to
- * {@link #SUGGEST_NEVER_MAKE_SHORTCUT}, the result will not be stored as a shortcut.
- * Otherwise, the shortcut id will be used to check back for for an up to date
- * suggestion using {@link #SUGGEST_URI_PATH_SHORTCUT}. Read more about shortcut
- * refreshing in the section about
- * <a href="#ExposingSearchSuggestionsToQuickSearchBox">exposing search suggestions to
- * Quick Search Box</a>.</td>
- * <td align="center">No. Only applicable to sources included in Quick Search Box.</td>
- * </tr>
- *
- * <tr><th>{@link #SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING}</th>
- * <td>This column is used to specify that a spinner should be shown in lieu of an icon2
- * while the shortcut of this suggestion is being refreshed.</td>
- * <td align="center">No. Only applicable to sources included in Quick Search Box.</td>
- * </tr>
- *
* <tr><th><i>Other Columns</i></th>
* <td>Finally, if you have defined any <a href="#ActionKeys">Action Keys</a> and you wish
* for them to have suggestion-specific definitions, you'll need to define one
@@ -581,59 +554,6 @@
* query text is provided and the SUGGEST_COLUMN_INTENT_DATA values are not suitable for user
* inspection and editing.</li></ul>
*
- * <a name="ExposingSearchSuggestionsToQuickSearchBox"></a>
- * <h3>Exposing Search Suggestions to Quick Search Box</h3>
- *
- * <p>Once your application is setup to provide search suggestions, making them available to the
- * globally accessable Quick Search Box is as easy as setting android:includeInGlobalSearch to
- * "true" in your searchable metadata file. Beyond that, here are some more details of how
- * suggestions interact with Quick Search Box, and optional ways that you may customize suggestions
- * for your application.
- *
- * <p><b>Source Ranking:</b> Once your application's search results are made available to Quick
- * Search Box, how they surface to the user for a particular query will depend on how many
- * other apps have results for that query, and how often the user has clicked on your results
- * compared to the other apps'. The apps with the best track record within Quick Search
- * Box will get queried earlier and have a better chance of showing their results in the top few
- * slots. If there are more results than can be displayed to the user within a screen or two, the
- * results may spill into a "more results" section that groups the remaining results by
- * source. The newest apps with little usage information are given middle of the road positioning
- * until enough usage information is available to rank it as usual. The exact formula for ranking
- * the results is not set in stone, but suffice it is to say that providing quality results will
- * increase the likelihood that your app's suggestions are provided in a prominent position, and
- * apps that provide lower quality suggestions will be more likely to be pushed into the spillover
- * area.
- *
- * <p><b>Search Settings:</b> Each app that is available to Quick Search Box has an entry in the
- * system settings where the user can enable or disable the inclusion of its results. Below the
- * name of the application, each application may provide a brief description of what kind of
- * information will be made available via a search settings description string pointed to by the
- * android:searchSettingsDescription attribute in the searchable metadata.
- *
- * <p><b>Shortcuts:</b> Suggestions that are clicked on by the user are automatically made into
- * shortcuts, or, copied so they can quickly be displayed to the user before querying any of
- * the sources. Thereafter, the shortcutted suggestion will be displayed for the query that yielded
- * the suggestion and for any prefixes of that query. When multiple shortcuts are made available
- * for a given query, they are ranked based on recency and the number of clicks they have received.
- * You can control how your suggestions are made into shortcuts, and whether they are refreshed,
- * using the {@link #SUGGEST_COLUMN_SHORTCUT_ID} column:
- * <ul><li>Suggestions that do not include a shortcut id column will be made into shortcuts and
- * never refreshed. This makes sense for suggestions that refer to data that will never be changed
- * or removed.</li>
- * <li>Suggestions that include a shortcut id will be re-queried for a fresh version of the
- * suggestion each time the shortcut is displayed. The shortcut will be quickly displayed with
- * whatever data was most recently available until the refresh query returns, after which the
- * suggestion will be dynamically refreshed with the up to date information. The shortcut refresh
- * query will be sent to your suggestion provider with a uri of {@link #SUGGEST_URI_PATH_SHORTCUT}.
- * The result should contain one suggestion using the same columns as the suggestion query, or be
- * empty, indicating that the shortcut is no longer valid. Shortcut ids make sense when referring
- * to data that may change over time, such as a contact's presence status. If a suggestion refers
- * to data that could take longer to refresh, such as a network based refresh of a stock quote, you
- * may include {@link #SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING} to show a progress spinner for the
- * right hand icon until the refresh is complete.</li>
- * <li>Finally, to prevent a suggestion from being copied into a shortcut, you may provide a
- * shortcut id with a value of {@link #SUGGEST_NEVER_MAKE_SHORTCUT}.</li></ul>
- *
* <a name="ActionKeys"></a>
* <h3>Action Keys</h3>
*
@@ -950,47 +870,6 @@
* </tbody>
* </table>
*
- * <p>Elements of search metadata that configure search suggestions being available to Quick Search
- * Box:
- * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
- *
- * <thead>
- * <tr><th>Attribute</th> <th>Description</th> <th>Required?</th></tr>
- * </thead>
- *
- * <tr><th>android:includeInGlobalSearch</th>
- * <td>If true, indicates the search suggestions provided by your application should be
- * included in the globally accessible Quick Search Box. The attributes below are only
- * applicable if this is set to true.</td>
- * <td align="center">Yes</td>
- * </tr>
- *
- * <tr><th>android:searchSettingsDescription</th>
- * <td>If provided, provides a brief description of the search suggestions that are provided
- * by your application to Quick Search Box, and will be displayed in the search settings
- * entry for your application.</td>
- * <td align="center">No</td>
- * </tr>
- *
- * <tr><th>android:queryAfterZeroResults</th>
- * <td>Indicates whether a source should be invoked for supersets of queries it has
- * returned zero results for in the past. For example, if a source returned zero
- * results for "bo", it would be ignored for "bob". If set to false, this source
- * will only be ignored for a single session; the next time the search dialog is
- * invoked, all sources will be queried. The default value is false.</td>
- * <td align="center">No</td>
- * </tr>
- *
- * <tr><th>android:searchSuggestThreshold</th>
- * <td>Indicates the minimum number of characters needed to trigger a source from Quick
- * Search Box. Only guarantees that a source will not be queried for anything shorter
- * than the threshold. The default value is 0.</td>
- * <td align="center">No</td>
- * </tr>
- *
- * </tbody>
- * </table>
- *
* <p><b>Additional metadata for search action keys.</b> For each action key that you would like to
* define, you'll need to add an additional element defining that key, and using the attributes
* discussed in <a href="#ActionKeys">Action Keys</a>. A simple example is shown here:
@@ -1368,12 +1247,16 @@
* result indicates the shortcut refers to a no longer valid sugggestion.
*
* @see #SUGGEST_COLUMN_SHORTCUT_ID
+ *
+ * @hide pending enabling of global search for third parties
*/
public final static String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut";
/**
* MIME type for shortcut validation. You'll use this in your suggestions content provider
* in the getType() function.
+ *
+ * @hide pending enabling of global search for third parties
*/
public final static String SHORTCUT_MIME_TYPE =
"vnd.android.cursor.item/vnd.android.search.suggest";
@@ -1386,7 +1269,7 @@
* In addition to the columns below, the suggestion columns are used to pass along the full
* suggestion so it can be shortcutted.
*
- * @hide
+ * @hide an implementation detail not part of the public api
*/
public final static String SEARCH_CLICK_REPORT_AUTHORITY =
"com.android.globalsearch.stats";
@@ -1394,21 +1277,21 @@
/**
* The path the write goes to.
*
- * @hide
+ * @hide an implementation detail not part of the public api
*/
public final static String SEARCH_CLICK_REPORT_URI_PATH = "click";
/**
* The column storing the query for the click.
*
- * @hide
+ * @hide an implementation detail not part of the public api
*/
public final static String SEARCH_CLICK_REPORT_COLUMN_QUERY = "query";
/**
* The column storing the component name of the application that was pivoted into.
*
- * @hide
+ * @hide an implementation detail not part of the public api
*/
public final static String SEARCH_CLICK_REPORT_COLUMN_COMPONENT = "component";
@@ -1493,7 +1376,7 @@
* {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
* attempt to use this column, the value will be overwritten by global search.
*
- * @hide
+ * @hide an implementation detail not part of the public api
*/
public final static String SUGGEST_COLUMN_INTENT_COMPONENT_NAME = "suggest_intent_component";
/**
@@ -1518,6 +1401,8 @@
* {@link #SUGGEST_NEVER_MAKE_SHORTCUT}, the result will not be stored as a shortcut.
* Otherwise, the shortcut id will be used to check back for an up to date suggestion using
* {@link #SUGGEST_URI_PATH_SHORTCUT}.
+ *
+ * @hide pending reenabling of global search for third parties
*/
public final static String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
@@ -1526,7 +1411,7 @@
* cursor item's background color if it needs a non-default background color. A non-zero value
* indicates a valid background color to override the default.
*
- * @hide For internal use, not part of the public API.
+ * @hide an implementation detail not part of the public api
*/
public final static String SUGGEST_COLUMN_BACKGROUND_COLOR = "suggest_background_color";
@@ -1534,6 +1419,8 @@
* Column name for suggestions cursor. <i>Optional.</i> This column is used to specify
* that a spinner should be shown in lieu of an icon2 while the shortcut of this suggestion
* is being refreshed.
+ *
+ * @hide pending reenabling of global search for third parties
*/
public final static String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING =
"suggest_spinner_while_refreshing";
@@ -1541,6 +1428,8 @@
/**
* Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion
* should not be stored as a shortcut in global search.
+ *
+ * @hide pending reenabling of global search for third parties
*/
public final static String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1";
@@ -1587,6 +1476,8 @@
* Intent action for starting a web search provider's settings activity.
* Web search providers should handle this intent if they have provider-specific
* settings to implement.
+ *
+ * @hide implementation detail only relevent to web search providers
*/
public final static String INTENT_ACTION_WEB_SEARCH_SETTINGS
= "android.search.action.WEB_SEARCH_SETTINGS";
@@ -1601,8 +1492,7 @@
/**
* Intent action broadcasted to inform that the search settings have changed in some way.
- * Either searchables have been enabled or disabled, or a different web search provider
- * has been chosen.
+ * Either searchables have been enabled or disabled.
*/
public final static String INTENT_ACTION_SEARCH_SETTINGS_CHANGED
= "android.search.action.SETTINGS_CHANGED";
@@ -1611,7 +1501,7 @@
* If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
* the search dialog will take no action.
*
- * @hide
+ * @hide an implentation detail not part of the public api
*/
public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
@@ -1622,7 +1512,17 @@
private final Context mContext;
+ /**
+ * compact representation of the activity associated with this search manager so
+ * we can say who we are when starting search. the search managerservice, in turn,
+ * uses this to properly handle the back stack.
+ */
private int mIdent;
+
+ /**
+ * The package associated with this seach manager.
+ */
+ private String mAssociatedPackage;
// package private since they are used by the inner class SearchManagerCallback
/* package */ final Handler mHandler;
@@ -1642,11 +1542,15 @@
return mIdent != 0;
}
- /*package*/ void setIdent(int ident) {
+ /*package*/ void setIdent(int ident, ComponentName component) {
if (mIdent != 0) {
throw new IllegalStateException("mIdent already set");
}
+ if (component == null) {
+ throw new IllegalArgumentException("component must be non-null");
+ }
mIdent = ident;
+ mAssociatedPackage = component.getPackageName();
}
/**
@@ -1683,7 +1587,7 @@
* no extra data is required.
* @param globalSearch If false, this will only launch the search that has been specifically
* defined by the application (which is usually defined as a local search). If no default
- * search is defined in the current application or activity, no search will be launched.
+ * search is defined in the current application or activity, global search will be launched.
* If true, this will always launch a platform-global (e.g. web-based) search instead.
*
* @see android.app.Activity#onSearchRequested
@@ -1696,12 +1600,55 @@
boolean globalSearch) {
if (mIdent == 0) throw new IllegalArgumentException(
"Called from outside of an Activity context");
+ if (!globalSearch && !mAssociatedPackage.equals(launchActivity.getPackageName())) {
+ Log.w(TAG, "invoking app search on a different package " +
+ "not associated with this search manager");
+ }
try {
// activate the search manager and start it up!
mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
globalSearch, mSearchManagerCallback, mIdent);
} catch (RemoteException ex) {
- Log.e(TAG, "startSearch() failed: " + ex);
+ Log.e(TAG, "startSearch() failed.", ex);
+ }
+ }
+
+ /**
+ * Similar to {@link #startSearch} but actually fires off the search query after invoking
+ * the search dialog. Made available for testing purposes.
+ *
+ * @param query The query to trigger. If empty, request will be ignored.
+ * @param launchActivity The ComponentName of the activity that has launched this search.
+ * @param appSearchData An application can insert application-specific
+ * context here, in order to improve quality or specificity of its own
+ * searches. This data will be returned with SEARCH intent(s). Null if
+ * no extra data is required.
+ * @param globalSearch If false, this will only launch the search that has been specifically
+ * defined by the application (which is usually defined as a local search). If no default
+ * search is defined in the current application or activity, no search will be launched.
+ * If true, this will always launch a platform-global (e.g. web-based) search instead.
+ *
+ * @see #startSearch
+ */
+ public void triggerSearch(String query,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ boolean globalSearch) {
+ if (mIdent == 0) throw new IllegalArgumentException(
+ "Called from outside of an Activity context");
+ if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
+ throw new IllegalArgumentException("invoking app search on a different package " +
+ "not associated with this search manager");
+ }
+ if (query == null || TextUtils.getTrimmedLength(query) == 0) {
+ Log.w(TAG, "triggerSearch called with empty query, ignoring.");
+ return;
+ }
+ try {
+ mService.triggerSearch(query, launchActivity, appSearchData, mSearchManagerCallback,
+ globalSearch, mIdent);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "triggerSearch() failed.", ex);
}
}
@@ -1822,6 +1769,7 @@
/**
* @deprecated This method is an obsolete internal implementation detail. Do not use.
*/
+ @Deprecated
public void onCancel(DialogInterface dialog) {
throw new UnsupportedOperationException();
}
@@ -1829,6 +1777,7 @@
/**
* @deprecated This method is an obsolete internal implementation detail. Do not use.
*/
+ @Deprecated
public void onDismiss(DialogInterface dialog) {
throw new UnsupportedOperationException();
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index d2fb605..60c756b 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -22,8 +22,10 @@
import android.content.ContextWrapper;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.RemoteException;
import android.os.IBinder;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -168,21 +170,120 @@
}
/**
- * Called by the system every time a client explicitly starts the service by calling
- * {@link android.content.Context#startService}, providing the arguments it supplied and a
- * unique integer token representing the start request. Do not call this method directly.
- *
- * @param intent The Intent supplied to {@link android.content.Context#startService},
- * as given.
- * @param startId A unique integer representing this specific request to
- * start. Use with {@link #stopSelfResult(int)}.
- *
- * @see #stopSelfResult(int)
+ * @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead.
*/
+ @Deprecated
public void onStart(Intent intent, int startId) {
}
/**
+ * Bits returned by {@link #onStartCommand} describing how to continue
+ * the service if it is killed. May be {@link #START_STICKY},
+ * {@link #START_NOT_STICKY}, {@link #START_REDELIVER_INTENT},
+ * or {@link #START_STICKY_COMPATIBILITY}.
+ */
+ public static final int START_CONTINUATION_MASK = 0xf;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: compatibility
+ * version of {@link #START_STICKY} that does not guarantee that
+ * {@link #onStartCommand} will be called again after being killed.
+ */
+ public static final int START_STICKY_COMPATIBILITY = 0;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), then leave it in the started state but
+ * don't retain this delivered intent. Later the system will try to
+ * re-create the service, but it will <em>not</em> call
+ * {@link #onStartCommand} unless there has been a new call to
+ * {@link Context#startService Context.startService(Intent)} with a new
+ * Intent to deliver.
+ *
+ * <p>This mode makes sense for things that will be explicitly started
+ * and stopped to run for arbitrary periods of time, such as a service
+ * performing background music playback.
+ */
+ public static final int START_STICKY = 1;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), and there are no new start intents to
+ * deliver to it, then take the service out of the started state and
+ * don't recreate until a future explicit call to
+ * {@link Context#startService Context.startService(Intent)}.
+ *
+ * <p>This mode makes sense for things that want to do some work as a
+ * result of being started, but can be stopped when under memory pressure
+ * and will explicit start themselves again later to do more work. An
+ * example of such a service would be one that polls for data from
+ * a server: it could schedule an alarm to poll every N minutes by having
+ * the alarm start its service. When its {@link #onStartCommand} is
+ * called from the alarm, it schedules a new alarm for N minutes later,
+ * and spawns a thread to do its networking. If its process is killed
+ * while doing that check, the service will not be restarted until the
+ * alarm goes off.
+ */
+ public static final int START_NOT_STICKY = 2;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), then it will be scheduled for a restart
+ * and the last delivered Intent re-delivered to it again via
+ * {@link #onStartCommand}. This Intent will remain scheduled for
+ * redelivery until the service calls {@link #stopSelf(int)} with the
+ * start ID provided to {@link #onStartCommand}.
+ */
+ public static final int START_REDELIVER_INTENT = 3;
+
+ /**
+ * This flag is set in {@link #onStartCommand} if the Intent is a
+ * re-delivery of a previously delivered intent, because the service
+ * had previously returned {@link #START_REDELIVER_INTENT} but had been
+ * killed before calling {@link #stopSelf(int)} for that Intent.
+ */
+ public static final int START_FLAG_REDELIVERY = 0x0001;
+
+ /**
+ * This flag is set in {@link #onStartCommand} if the Intent is a
+ * a retry because the original attempt never got to or returned from
+ * {@link #onStartCommand(Intent, int, int)}.
+ */
+ public static final int START_FLAG_RETRY = 0x0002;
+
+ /**
+ * Called by the system every time a client explicitly starts the service by calling
+ * {@link android.content.Context#startService}, providing the arguments it supplied and a
+ * unique integer token representing the start request. Do not call this method directly.
+ *
+ * <p>For backwards compatibility, the default implementation calls
+ * {@link #onStart} and returns either {@link #START_STICKY}
+ * or {@link #START_STICKY_COMPATIBILITY}.
+ *
+ * @param intent The Intent supplied to {@link android.content.Context#startService},
+ * as given. This may be null if the service is being restarted after
+ * its process has gone away, and it had previously returned anything
+ * except {@link #START_STICKY_COMPATIBILITY}.
+ * @param flags Additional data about this start request. Currently either
+ * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
+ * @param startId A unique integer representing this specific request to
+ * start. Use with {@link #stopSelfResult(int)}.
+ *
+ * @return The return value indicates what semantics the system should
+ * use for the service's current started state. It may be one of the
+ * constants associated with the {@link #START_CONTINUATION_MASK} bits.
+ *
+ * @see #stopSelfResult(int)
+ */
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ onStart(intent, startId);
+ return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
+ }
+
+ /**
* Called by the system to notify a Service that it is no longer used and is being removed. The
* service should clean up an resources it holds (threads, registered
* receivers, etc) at this point. Upon return, there will be no more calls
@@ -304,24 +405,53 @@
}
/**
- * Control whether this service is considered to be a foreground service.
+ * @deprecated This is a now a no-op, use
+ * {@link #startForeground(int, Notification)} instead.
+ */
+ @Deprecated
+ public final void setForeground(boolean isForeground) {
+ Log.w(TAG, "setForeground: ignoring old API call on " + getClass().getName());
+ }
+
+ /**
+ * Make this service run in the foreground, supplying the ongoing
+ * notification to be shown to the user while in this state.
* By default services are background, meaning that if the system needs to
* kill them to reclaim more memory (such as to display a large page in a
* web browser), they can be killed without too much harm. You can set this
- * flag if killing your service would be disruptive to the user: such as
+ * flag if killing your service would be disruptive to the user, such as
* if your service is performing background music playback, so the user
* would notice if their music stopped playing.
*
- * @param isForeground Determines whether this service is considered to
- * be foreground (true) or background (false).
+ * @param id The identifier for this notification as per
+ * {@link NotificationManager#notify(int, Notification)
+ * NotificationManager.notify(int, Notification)}.
+ * @param notification The Notification to be displayed.
+ *
+ * @see #stopForeground(boolean)
*/
- public final void setForeground(boolean isForeground) {
- if (mActivityManager == null) {
- return;
- }
+ public final void startForeground(int id, Notification notification) {
try {
mActivityManager.setServiceForeground(
- new ComponentName(this, mClassName), mToken, isForeground);
+ new ComponentName(this, mClassName), mToken, id,
+ notification, true);
+ } catch (RemoteException ex) {
+ }
+ }
+
+ /**
+ * Remove this service from foreground state, allowing it to be killed if
+ * more memory is needed.
+ * @param removeNotification If true, the notification previously provided
+ * to {@link #startForeground} will be removed. Otherwise it will remain
+ * until a later call removes it (or the service is destroyed).
+ * @see #startForeground(int, Notification)
+ */
+ public final void stopForeground(boolean removeNotification) {
+ try {
+ mActivityManager.setServiceForeground(
+ new ComponentName(this, mClassName), mToken, 0, null,
+ removeNotification);
} catch (RemoteException ex) {
}
}
@@ -363,6 +493,8 @@
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
+ mStartCompatibility = getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.ECLAIR;
}
final String getClassName() {
@@ -375,4 +507,5 @@
private IBinder mToken = null;
private Application mApplication = null;
private IActivityManager mActivityManager = null;
+ private boolean mStartCompatibility = false;
}
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 52e4a1f..90f8c50 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -65,6 +65,7 @@
private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
private SparseArray<Drawable.ConstantState> mBackgroundsCache;
private boolean mGlobalSearchMode;
+ private boolean mClosed = false;
// Cached column indexes, updated when the cursor changes.
private int mFormatCol;
@@ -199,6 +200,12 @@
}
}
+ public void close() {
+ if (DBG) Log.d(LOG_TAG, "close()");
+ changeCursor(null);
+ mClosed = true;
+ }
+
/**
* Cache columns.
*/
@@ -206,6 +213,12 @@
public void changeCursor(Cursor c) {
if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
+ if (mClosed) {
+ Log.w(LOG_TAG, "Tried to change cursor after adapter was closed.");
+ if (c != null) c.close();
+ return;
+ }
+
try {
Cursor oldCursor = getCursor();
super.changeCursor(c);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index fd8776f..c5ca0a3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -28,6 +28,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.Log;
import android.view.ViewRoot;
import java.io.FileOutputStream;
@@ -82,7 +83,8 @@
try {
ParcelFileDescriptor fd = mService.getWallpaper(this);
if (fd != null) {
- Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, null);
if (bm != null) {
// For now clear the density until we figure out how
// to deal with it for wallpapers.
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index cced338..a4c141e 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -322,6 +322,7 @@
if (mInfo != null) {
Context theirContext = mContext.createPackageContext(
mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED);
+ mRemoteContext = theirContext;
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater = inflater.cloneInContext(theirContext);
@@ -336,8 +337,8 @@
exception = e;
}
- if (exception != null && LOGD) {
- Log.w(TAG, "Error inflating AppWidget " + mInfo, exception);
+ if (exception != null) {
+ Log.w(TAG, "Error inflating AppWidget " + mInfo + ": " + exception.toString());
}
if (defaultView == null) {
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 2ea45d5..b531a50 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,7 +25,10 @@
import android.os.IBinder;
import android.util.Log;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
/**
* Public API for controlling the Bluetooth A2DP Profile Service.
@@ -47,7 +50,7 @@
*
* @hide
*/
-public class BluetoothA2dp {
+public final class BluetoothA2dp {
private static final String TAG = "BluetoothA2dp";
private static final boolean DBG = false;
@@ -79,6 +82,7 @@
/** Default priority for a2dp devices that should not allow incoming
* connections */
public static final int PRIORITY_OFF = 0;
+
private final IBluetoothA2dp mService;
private final Context mContext;
@@ -89,6 +93,7 @@
*/
public BluetoothA2dp(Context c) {
mContext = c;
+
IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
if (b == null) {
throw new RuntimeException("Bluetooth A2DP service not available!");
@@ -99,14 +104,14 @@
/** Initiate a connection to an A2DP sink.
* Listen for SINK_STATE_CHANGED_ACTION to find out when the
* connection is completed.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return Result code, negative indicates an immediate error.
* @hide
*/
- public int connectSink(String address) {
- if (DBG) log("connectSink(" + address + ")");
+ public int connectSink(BluetoothDevice device) {
+ if (DBG) log("connectSink(" + device + ")");
try {
- return mService.connectSink(address);
+ return mService.connectSink(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -116,14 +121,14 @@
/** Initiate disconnect from an A2DP sink.
* Listen for SINK_STATE_CHANGED_ACTION to find out when
* disconnect is completed.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return Result code, negative indicates an immediate error.
* @hide
*/
- public int disconnectSink(String address) {
- if (DBG) log("disconnectSink(" + address + ")");
+ public int disconnectSink(BluetoothDevice device) {
+ if (DBG) log("disconnectSink(" + device + ")");
try {
- return mService.disconnectSink(address);
+ return mService.disconnectSink(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -131,24 +136,25 @@
}
/** Check if a specified A2DP sink is connected.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return True if connected (or playing), false otherwise and on error.
* @hide
*/
- public boolean isSinkConnected(String address) {
- if (DBG) log("isSinkConnected(" + address + ")");
- int state = getSinkState(address);
+ public boolean isSinkConnected(BluetoothDevice device) {
+ if (DBG) log("isSinkConnected(" + device + ")");
+ int state = getSinkState(device);
return state == STATE_CONNECTED || state == STATE_PLAYING;
}
/** Check if any A2DP sink is connected.
- * @return a List of connected A2DP sinks, or null on error.
+ * @return a unmodifiable set of connected A2DP sinks, or null on error.
* @hide
*/
- public List<String> listConnectedSinks() {
- if (DBG) log("listConnectedSinks()");
+ public Set<BluetoothDevice> getConnectedSinks() {
+ if (DBG) log("getConnectedSinks()");
try {
- return mService.listConnectedSinks();
+ return Collections.unmodifiableSet(
+ new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
} catch (RemoteException e) {
Log.w(TAG, "", e);
return null;
@@ -156,14 +162,14 @@
}
/** Get the state of an A2DP sink
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return State code, or negative on error
* @hide
*/
- public int getSinkState(String address) {
- if (DBG) log("getSinkState(" + address + ")");
+ public int getSinkState(BluetoothDevice device) {
+ if (DBG) log("getSinkState(" + device + ")");
try {
- return mService.getSinkState(address);
+ return mService.getSinkState(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -177,15 +183,15 @@
* Sinks with priority greater than zero will accept incoming connections
* (if no sink is currently connected).
* Priority for unpaired sink must be PRIORITY_NONE.
- * @param address Paired sink
+ * @param device Paired sink
* @param priority Integer priority, for example PRIORITY_AUTO or
* PRIORITY_NONE
* @return Result code, negative indicates an error
*/
- public int setSinkPriority(String address, int priority) {
- if (DBG) log("setSinkPriority(" + address + ", " + priority + ")");
+ public int setSinkPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
try {
- return mService.setSinkPriority(address, priority);
+ return mService.setSinkPriority(device, priority);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -194,44 +200,19 @@
/**
* Get priority of a2dp sink.
- * @param address Sink
+ * @param device Sink
* @return non-negative priority, or negative error code on error.
*/
- public int getSinkPriority(String address) {
- if (DBG) log("getSinkPriority(" + address + ")");
+ public int getSinkPriority(BluetoothDevice device) {
+ if (DBG) log("getSinkPriority(" + device + ")");
try {
- return mService.getSinkPriority(address);
+ return mService.getSinkPriority(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
}
}
- /**
- * Check class bits for possible A2DP Sink support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might be a A2DP Sink. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- * @return True if this device might be a A2DP sink
- */
- public static boolean doesClassMatchSink(int btClass) {
- if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
- return true;
- }
- // By the A2DP spec, sinks must indicate the RENDER service.
- // However we found some that do not (Chordette). So lets also
- // match on some other class bits.
- switch (BluetoothClass.Device.getDevice(btClass)) {
- case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
- case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- }
-
/** Helper for converting a state to a string.
* For debug use only - strings are not internationalized.
* @hide
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
new file mode 100644
index 0000000..6bd2a5a
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -0,0 +1,376 @@
+/*
+ * 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.bluetooth;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Represents the local Bluetooth adapter.
+ *
+ * <p>Use {@link android.content.Context#getSystemService} with {@link
+ * android.content.Context#BLUETOOTH_SERVICE} to get the default local
+ * Bluetooth adapter. On most Android devices there is only one local
+ * Bluetotoh adapter.
+ *
+ * <p>Use the {@link BluetoothDevice} class for operations on remote Bluetooth
+ * devices.
+ *
+ * <p>TODO: unhide more of this class
+ */
+public final class BluetoothAdapter {
+ private static final String TAG = "BluetoothAdapter";
+
+ /** @hide */
+ public static final int BLUETOOTH_STATE_OFF = 0;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_TURNING_ON = 1;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_ON = 2;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
+
+ /** Inquiry scan and page scan are both off.
+ * Device is neither discoverable nor connectable
+ * @hide */
+ public static final int SCAN_MODE_NONE = 0;
+ /** Page scan is on, inquiry scan is off.
+ * Device is connectable, but not discoverable
+ * @hide*/
+ public static final int SCAN_MODE_CONNECTABLE = 1;
+ /** Page scan and inquiry scan are on.
+ * Device is connectable and discoverable
+ * @hide*/
+ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
+
+ /** @hide */
+ public static final int RESULT_FAILURE = -1;
+ /** @hide */
+ public static final int RESULT_SUCCESS = 0;
+
+ /** The user will be prompted to enter a pin
+ * @hide */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /** The user will be prompted to enter a passkey
+ * @hide */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /** The user will be prompted to confirm the passkey displayed on the screen
+ * @hide */
+ public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+
+ private final IBluetooth mService;
+
+ /**
+ * Do not use this constructor. Use Context.getSystemService() instead.
+ * @hide
+ */
+ public BluetoothAdapter(IBluetooth service) {
+ if (service == null) {
+ throw new IllegalArgumentException("service is null");
+ }
+ mService = service;
+ }
+
+ /**
+ * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
+ * address.
+ * <p>Valid Bluetooth hardware addresses must be upper case, in a format
+ * such as "00:11:22:33:AA:BB".
+ * <p>A {@link BluetoothDevice} will always be returned for a valid
+ * hardware address, even if this adapter has never seen that device.
+ * @param address valid Bluetooth MAC address
+ * @throws IllegalArgumentException if address is invalid
+ */
+ public BluetoothDevice getRemoteDevice(String address) {
+ return new BluetoothDevice(address);
+ }
+
+ /**
+ * Is Bluetooth currently turned on.
+ *
+ * @return true if Bluetooth enabled, false otherwise.
+ * @hide
+ */
+ public boolean isEnabled() {
+ try {
+ return mService.isEnabled();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Get the current state of Bluetooth.
+ *
+ * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
+ * @hide
+ */
+ public int getBluetoothState() {
+ try {
+ return mService.getBluetoothState();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR;
+ }
+
+ /**
+ * Enable the Bluetooth device.
+ * Turn on the underlying hardware.
+ * This is an asynchronous call,
+ * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
+ * and when the device is sucessfully enabled.
+ * @return false if we cannot enable the Bluetooth device. True does not
+ * imply the device was enabled, it only implies that so far there were no
+ * problems.
+ * @hide
+ */
+ public boolean enable() {
+ try {
+ return mService.enable();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Disable the Bluetooth device.
+ * This turns off the underlying hardware.
+ *
+ * @return true if successful, false otherwise.
+ * @hide
+ */
+ public boolean disable() {
+ try {
+ return mService.disable(true);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /** @hide */
+ public String getAddress() {
+ try {
+ return mService.getAddress();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Get the friendly Bluetooth name of this device.
+ *
+ * This name is visible to remote Bluetooth devices. Currently it is only
+ * possible to retrieve the Bluetooth name when Bluetooth is enabled.
+ *
+ * @return the Bluetooth name, or null if there was a problem.
+ * @hide
+ */
+ public String getName() {
+ try {
+ return mService.getName();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Set the friendly Bluetooth name of this device.
+ *
+ * This name is visible to remote Bluetooth devices. The Bluetooth Service
+ * is responsible for persisting this name.
+ *
+ * @param name the name to set
+ * @return true, if the name was successfully set. False otherwise.
+ * @hide
+ */
+ public boolean setName(String name) {
+ try {
+ return mService.setName(name);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Get the current scan mode.
+ * Used to determine if the local device is connectable and/or discoverable
+ * @return Scan mode, one of SCAN_MODE_* or an error code
+ * @hide
+ */
+ public int getScanMode() {
+ try {
+ return mService.getScanMode();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR_IPC;
+ }
+
+ /**
+ * Set the current scan mode.
+ * Used to make the local device connectable and/or discoverable
+ * @param scanMode One of SCAN_MODE_*
+ * @hide
+ */
+ public void setScanMode(int scanMode) {
+ try {
+ mService.setScanMode(scanMode);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public int getDiscoverableTimeout() {
+ try {
+ return mService.getDiscoverableTimeout();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return -1;
+ }
+
+ /** @hide */
+ public void setDiscoverableTimeout(int timeout) {
+ try {
+ mService.setDiscoverableTimeout(timeout);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public boolean startDiscovery() {
+ try {
+ return mService.startDiscovery();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /** @hide */
+ public void cancelDiscovery() {
+ try {
+ mService.cancelDiscovery();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public boolean isDiscovering() {
+ try {
+ return mService.isDiscovering();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * List remote devices that are bonded (paired) to the local adapter.
+ *
+ * Bonding (pairing) is the process by which the user enters a pin code for
+ * the device, which generates a shared link key, allowing for
+ * authentication and encryption of future connections. In Android we
+ * require bonding before RFCOMM or SCO connections can be made to a remote
+ * device.
+ *
+ * This function lists which remote devices we have a link key for. It does
+ * not cause any RF transmission, and does not check if the remote device
+ * still has it's link key with us. If the other side no longer has its
+ * link key then the RFCOMM or SCO connection attempt will result in an
+ * error.
+ *
+ * This function does not check if the remote device is in range.
+ *
+ * Remote devices that have an in-progress bonding attempt are not
+ * returned.
+ *
+ * @return unmodifiable set of bonded devices, or null on error
+ * @hide
+ */
+ public Set<BluetoothDevice> getBondedDevices() {
+ try {
+ return toDeviceSet(mService.listBonds());
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Create a listening, secure RFCOMM Bluetooth socket.
+ * <p>A remote device connecting to this socket will be authenticated and
+ * communication on this socket will be encrypted.
+ * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections to listening {@link BluetoothServerSocket}.
+ * <p>Valid RFCOMM channels are in range 1 to 30.
+ * @param channel RFCOMM channel to listen on
+ * @return a listening RFCOMM BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ */
+ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, true, true, channel);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ /**
+ * Construct an unencrypted, unauthenticated, RFCOMM server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return An RFCOMM BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, false, false, port);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ /**
+ * Construct a SCO server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return A SCO BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public static BluetoothServerSocket listenUsingScoOn() throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_SCO, false, false, -1);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
+ Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
+ for (int i = 0; i < addresses.length; i++) {
+ devices.add(getRemoteDevice(addresses[i]));
+ }
+ return Collections.unmodifiableSet(devices);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAudioGateway.java b/core/java/android/bluetooth/BluetoothAudioGateway.java
index f3afd2a..abd7723 100644
--- a/core/java/android/bluetooth/BluetoothAudioGateway.java
+++ b/core/java/android/bluetooth/BluetoothAudioGateway.java
@@ -9,24 +9,22 @@
/**
* Listen's for incoming RFCOMM connection for the headset / handsfree service.
*
- * This class is planned for deletion, in favor of a generic Rfcomm class.
+ * TODO: Use the new generic BluetoothSocket class instead of this legacy code
*
* @hide
*/
-public class BluetoothAudioGateway {
+public final class BluetoothAudioGateway {
private static final String TAG = "BT Audio Gateway";
private static final boolean DBG = false;
private int mNativeData;
static { classInitNative(); }
- private BluetoothDevice mBluetooth;
-
/* in */
private int mHandsfreeAgRfcommChannel = -1;
private int mHeadsetAgRfcommChannel = -1;
- /* out */
+ /* out - written by native code */
private String mConnectingHeadsetAddress;
private int mConnectingHeadsetRfcommChannel; /* -1 when not connected */
private int mConnectingHeadsetSocketFd;
@@ -35,17 +33,18 @@
private int mConnectingHandsfreeSocketFd;
private int mTimeoutRemainingMs; /* in/out */
+ private final BluetoothAdapter mAdapter;
+
public static final int DEFAULT_HF_AG_CHANNEL = 10;
public static final int DEFAULT_HS_AG_CHANNEL = 11;
- public BluetoothAudioGateway(BluetoothDevice bluetooth) {
- this(bluetooth, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
+ public BluetoothAudioGateway(BluetoothAdapter adapter) {
+ this(adapter, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
}
- public BluetoothAudioGateway(BluetoothDevice bluetooth,
- int handsfreeAgRfcommChannel,
- int headsetAgRfcommChannel) {
- mBluetooth = bluetooth;
+ public BluetoothAudioGateway(BluetoothAdapter adapter, int handsfreeAgRfcommChannel,
+ int headsetAgRfcommChannel) {
+ mAdapter = adapter;
mHandsfreeAgRfcommChannel = handsfreeAgRfcommChannel;
mHeadsetAgRfcommChannel = headsetAgRfcommChannel;
initializeNativeDataNative();
@@ -58,18 +57,17 @@
private Handler mCallback;
public class IncomingConnectionInfo {
- IncomingConnectionInfo(BluetoothDevice bluetooth, String address, int socketFd,
- int rfcommChan) {
- mBluetooth = bluetooth;
- mAddress = address;
+ public BluetoothAdapter mAdapter;
+ public BluetoothDevice mRemoteDevice;
+ public int mSocketFd;
+ public int mRfcommChan;
+ IncomingConnectionInfo(BluetoothAdapter adapter, BluetoothDevice remoteDevice,
+ int socketFd, int rfcommChan) {
+ mAdapter = adapter;
+ mRemoteDevice = remoteDevice;
mSocketFd = socketFd;
mRfcommChan = rfcommChan;
}
-
- public BluetoothDevice mBluetooth;
- public String mAddress;
- public int mSocketFd;
- public int mRfcommChan;
}
public static final int MSG_INCOMING_HEADSET_CONNECTION = 100;
@@ -111,12 +109,11 @@
mConnectingHeadsetRfcommChannel);
Message msg = Message.obtain(mCallback);
msg.what = MSG_INCOMING_HEADSET_CONNECTION;
- msg.obj =
- new IncomingConnectionInfo(
- mBluetooth,
- mConnectingHeadsetAddress,
- mConnectingHeadsetSocketFd,
- mConnectingHeadsetRfcommChannel);
+ msg.obj = new IncomingConnectionInfo(
+ mAdapter,
+ mAdapter.getRemoteDevice(mConnectingHeadsetAddress),
+ mConnectingHeadsetSocketFd,
+ mConnectingHeadsetRfcommChannel);
msg.sendToTarget();
}
if (mConnectingHandsfreeRfcommChannel >= 0) {
@@ -126,12 +123,11 @@
Message msg = Message.obtain();
msg.setTarget(mCallback);
msg.what = MSG_INCOMING_HANDSFREE_CONNECTION;
- msg.obj =
- new IncomingConnectionInfo(
- mBluetooth,
- mConnectingHandsfreeAddress,
- mConnectingHandsfreeSocketFd,
- mConnectingHandsfreeRfcommChannel);
+ msg.obj = new IncomingConnectionInfo(
+ mAdapter,
+ mAdapter.getRemoteDevice(mConnectingHandsfreeAddress),
+ mConnectingHandsfreeSocketFd,
+ mConnectingHandsfreeRfcommChannel);
msg.sendToTarget();
}
}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 88ce18b..0061f10 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -46,6 +46,10 @@
/** Indicates the Bluetooth API could not retrieve the class */
public static final int ERROR = 0xFF000000;
+ public static final int PROFILE_HEADSET = 0;
+ public static final int PROFILE_A2DP = 1;
+ public static final int PROFILE_OPP = 2;
+
/** Every Bluetooth device has zero or more service classes */
public static class Service {
public static final int BITMASK = 0xFFE000;
@@ -187,5 +191,74 @@
return (btClass & Device.BITMASK);
}
}
+
+ /**
+ * Check class bits for possible bluetooth profile support.
+ * This is a simple heuristic that tries to guess if a device with the
+ * given class bits might support specified profile. It is not accurate for all
+ * devices. It tries to err on the side of false positives.
+ * @param btClass The class
+ * @param profile The profile to be checked
+ * @return True if this device might support specified profile.
+ */
+ public static boolean doesClassMatch(int btClass, int profile) {
+ if (profile == PROFILE_A2DP) {
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+ return true;
+ }
+ // By the A2DP spec, sinks must indicate the RENDER service.
+ // However we found some that do not (Chordette). So lets also
+ // match on some other class bits.
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
+ case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
+ case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ return true;
+ default:
+ return false;
+ }
+ } else if (profile == PROFILE_HEADSET) {
+ // The render service class is required by the spec for HFP, so is a
+ // pretty good signal
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+ return true;
+ }
+ // Just in case they forgot the render service class
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+ case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ return true;
+ default:
+ return false;
+ }
+ } else if (profile == PROFILE_OPP) {
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.OBJECT_TRANSFER)) {
+ return true;
+ }
+
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
+ case BluetoothClass.Device.COMPUTER_DESKTOP:
+ case BluetoothClass.Device.COMPUTER_SERVER:
+ case BluetoothClass.Device.COMPUTER_LAPTOP:
+ case BluetoothClass.Device.COMPUTER_HANDHELD_PC_PDA:
+ case BluetoothClass.Device.COMPUTER_PALM_SIZE_PC_PDA:
+ case BluetoothClass.Device.COMPUTER_WEARABLE:
+ case BluetoothClass.Device.PHONE_UNCATEGORIZED:
+ case BluetoothClass.Device.PHONE_CELLULAR:
+ case BluetoothClass.Device.PHONE_CORDLESS:
+ case BluetoothClass.Device.PHONE_SMART:
+ case BluetoothClass.Device.PHONE_MODEM_OR_GATEWAY:
+ case BluetoothClass.Device.PHONE_ISDN:
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
}
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/bluetooth/BluetoothDevice.aidl
similarity index 91%
rename from core/java/android/speech/RecognitionResult.aidl
rename to core/java/android/bluetooth/BluetoothDevice.aidl
index 59e53ab..daae74d 100644
--- a/core/java/android/speech/RecognitionResult.aidl
+++ b/core/java/android/bluetooth/BluetoothDevice.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.speech;
+package android.bluetooth;
-parcelable RecognitionResult;
+parcelable BluetoothDevice;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a64c6d7..0a71961 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -16,249 +16,195 @@
package android.bluetooth;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
+ * Represents a remote Bluetooth device.
*
- * Manages the local Bluetooth device. Scan for devices, create bondings,
- * power up and down the adapter.
+ * <p>Use {@link BluetoothAdapter#getRemoteDevice} to create a {@link
+ * BluetoothDevice}.
*
- * @hide
+ * <p>This class is really just a thin wrapper for a Bluetooth hardware
+ * address. Objects of this class are immutable. Operations on this class
+ * are performed on the remote Bluetooth hardware address, using the
+ * {@link BluetoothAdapter} that was used to create this {@link
+ * BluetoothDevice}.
+ *
+ * TODO: unhide more of this class
*/
-public class BluetoothDevice {
-
- public static final int BLUETOOTH_STATE_OFF = 0;
- public static final int BLUETOOTH_STATE_TURNING_ON = 1;
- public static final int BLUETOOTH_STATE_ON = 2;
- public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
-
- /** Inquiry scan and page scan are both off.
- * Device is neither discoverable nor connectable */
- public static final int SCAN_MODE_NONE = 0;
- /** Page scan is on, inquiry scan is off.
- * Device is connectable, but not discoverable */
- public static final int SCAN_MODE_CONNECTABLE = 1;
- /** Page scan and inquiry scan are on.
- * Device is connectable and discoverable */
- public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
-
- public static final int RESULT_FAILURE = -1;
- public static final int RESULT_SUCCESS = 0;
+public final class BluetoothDevice implements Parcelable {
+ private static final String TAG = "BluetoothDevice";
/** We do not have a link key for the remote device, and are therefore not
- * bonded */
+ * bonded
+ * @hide*/
public static final int BOND_NOT_BONDED = 0;
- /** We have a link key for the remote device, and are probably bonded. */
+ /** We have a link key for the remote device, and are probably bonded.
+ * @hide */
public static final int BOND_BONDED = 1;
- /** We are currently attempting bonding */
+ /** We are currently attempting bonding
+ * @hide */
public static final int BOND_BONDING = 2;
+ /** Ask device picker to show all kinds of BT devices.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_ALL = 0;
+ /** Ask device picker to show BT devices that support AUDIO profiles.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_AUDIO = 1;
+ /** Ask device picker to show BT devices that support Object Transfer.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_TRANSFER = 2;
+
//TODO: Unify these result codes in BluetoothResult or BluetoothError
/** A bond attempt failed because pins did not match, or remote device did
- * not respond to pin request in time */
+ * not respond to pin request in time
+ * @hide */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
/** A bond attempt failed because the other side explicilty rejected
- * bonding */
+ * bonding
+ * @hide */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
- /** A bond attempt failed because we canceled the bonding process */
+ /** A bond attempt failed because we canceled the bonding process
+ * @hide */
public static final int UNBOND_REASON_AUTH_CANCELED = 3;
- /** A bond attempt failed because we could not contact the remote device */
+ /** A bond attempt failed because we could not contact the remote device
+ * @hide */
public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
- /** A bond attempt failed because a discovery is in progress */
+ /** A bond attempt failed because a discovery is in progress
+ * @hide */
public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
- /** An existing bond was explicitly revoked */
+ /** An existing bond was explicitly revoked
+ * @hide */
public static final int UNBOND_REASON_REMOVED = 6;
- /* The user will be prompted to enter a pin */
+ //TODO: Remove duplicates between here and BluetoothAdapter
+ /** The user will be prompted to enter a pin
+ * @hide */
public static final int PAIRING_VARIANT_PIN = 0;
- /* The user will be prompted to enter a passkey */
+ /** The user will be prompted to enter a passkey
+ * @hide */
public static final int PAIRING_VARIANT_PASSKEY = 1;
- /* The user will be prompted to confirm the passkey displayed on the screen */
+ /** The user will be prompted to confirm the passkey displayed on the screen
+ * @hide */
public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+ private static final int ADDRESS_LENGTH = 17;
- private static final String TAG = "BluetoothDevice";
+ private static IBluetooth sService; /* Guarenteed constant after first object constructed */
- private final IBluetoothDevice mService;
+ private final String mAddress;
+
/**
- * @hide - hide this because it takes a parameter of type
- * IBluetoothDevice, which is a System private class.
- * Also note that Context.getSystemService is a factory that
- * returns a BlueToothDevice. That is the right way to get
- * a BluetoothDevice.
+ * Create a new BluetoothDevice
+ * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
+ * and is validated in this constructor.
+ * @param address valid Bluetooth MAC address
+ * @throws RuntimeException Bluetooth is not available on this platform
+ * @throws IllegalArgumentException address is invalid
+ * @hide
*/
- public BluetoothDevice(IBluetoothDevice service) {
- mService = service;
+ /*package*/ BluetoothDevice(String address) {
+ synchronized (BluetoothDevice.class) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.BLUETOOTH_SERVICE);
+ if (b == null) {
+ throw new RuntimeException("Bluetooth service not available");
+ }
+ sService = IBluetooth.Stub.asInterface(b);
+ }
+ }
+
+ if (!checkBluetoothAddress(address)) {
+ throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
+ }
+
+ mAddress = address;
}
- /**
- * Is Bluetooth currently turned on.
- *
- * @return true if Bluetooth enabled, false otherwise.
- */
- public boolean isEnabled() {
- try {
- return mService.isEnabled();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothDevice) {
+ return mAddress.equals(((BluetoothDevice)o).getAddress());
+ }
return false;
}
- /**
- * Get the current state of Bluetooth.
- *
- * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
- */
- public int getBluetoothState() {
- try {
- return mService.getBluetoothState();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR;
+ @Override
+ public int hashCode() {
+ return mAddress.hashCode();
}
/**
- * Enable the Bluetooth device.
- * Turn on the underlying hardware.
- * This is an asynchronous call,
- * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
- * and when the device is sucessfully enabled.
- * @return false if we cannot enable the Bluetooth device. True does not
- * imply the device was enabled, it only implies that so far there were no
- * problems.
+ * Returns a string representation of this BluetoothDevice.
+ * <p>Currently this is the Bluetooth hardware address, for example
+ * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
+ * if you explicitly require the Bluetooth hardware address in case the
+ * {@link #toString} representation changes in the future.
+ * @return string representation of this BluetoothDevice
*/
- public boolean enable() {
- try {
- return mService.enable();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ @Override
+ public String toString() {
+ return mAddress;
+ }
+
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<BluetoothDevice> CREATOR =
+ new Parcelable.Creator<BluetoothDevice>() {
+ public BluetoothDevice createFromParcel(Parcel in) {
+ return new BluetoothDevice(in.readString());
+ }
+ public BluetoothDevice[] newArray(int size) {
+ return new BluetoothDevice[size];
+ }
+ };
+
+ /** @hide */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mAddress);
}
/**
- * Disable the Bluetooth device.
- * This turns off the underlying hardware.
- *
- * @return true if successful, false otherwise.
+ * Returns the hardware address of this BluetoothDevice.
+ * <p> For example, "00:11:22:AA:BB:CC".
+ * @return Bluetooth hardware address as string
*/
- public boolean disable() {
- try {
- return mService.disable(true);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
public String getAddress() {
- try {
- return mService.getAddress();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return mAddress;
}
/**
- * Get the friendly Bluetooth name of this device.
+ * Get the friendly Bluetooth name of the remote device.
*
- * This name is visible to remote Bluetooth devices. Currently it is only
- * possible to retrieve the Bluetooth name when Bluetooth is enabled.
+ * <p>The local adapter will automatically retrieve remote names when
+ * performing a device scan, and will cache them. This method just returns
+ * the name for this device from the cache.
*
* @return the Bluetooth name, or null if there was a problem.
+ * @hide
*/
public String getName() {
try {
- return mService.getName();
+ return sService.getRemoteName(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
/**
- * Set the friendly Bluetooth name of this device.
- *
- * This name is visible to remote Bluetooth devices. The Bluetooth Service
- * is responsible for persisting this name.
- *
- * @param name the name to set
- * @return true, if the name was successfully set. False otherwise.
- */
- public boolean setName(String name) {
- try {
- return mService.setName(name);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- /**
- * Get the current scan mode.
- * Used to determine if the local device is connectable and/or discoverable
- * @return Scan mode, one of SCAN_MODE_* or an error code
- */
- public int getScanMode() {
- try {
- return mService.getScanMode();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR_IPC;
- }
-
- /**
- * Set the current scan mode.
- * Used to make the local device connectable and/or discoverable
- * @param scanMode One of SCAN_MODE_*
- */
- public void setScanMode(int scanMode) {
- try {
- mService.setScanMode(scanMode);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public int getDiscoverableTimeout() {
- try {
- return mService.getDiscoverableTimeout();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return -1;
- }
- public void setDiscoverableTimeout(int timeout) {
- try {
- mService.setDiscoverableTimeout(timeout);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public boolean startDiscovery() {
- try {
- return mService.startDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- public void cancelDiscovery() {
- try {
- mService.cancelDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public boolean isDiscovering() {
- try {
- return mService.isDiscovering();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- /**
- * Removes the remote device and the pairing information associated
- * with it.
- *
- * @param address the Bluetooth hardware address you want to disconnect.
- * @return true if the device was disconnected, false otherwise and on
- * error.
- */
- public boolean removeBond(String address) {
- try {
- return mService.removeBond(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- /**
* Create a bonding with a remote bluetooth device.
*
* This is an asynchronous call. The result of this bonding attempt can be
@@ -267,52 +213,39 @@
* @param address the remote device Bluetooth address.
* @return false If there was an immediate problem creating the bonding,
* true otherwise.
+ * @hide
*/
- public boolean createBond(String address) {
+ public boolean createBond() {
try {
- return mService.createBond(address);
+ return sService.createBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
* Cancel an in-progress bonding request started with createBond.
+ * @hide
*/
- public boolean cancelBondProcess(String address) {
+ public boolean cancelBondProcess() {
try {
- return mService.cancelBondProcess(address);
+ return sService.cancelBondProcess(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * List remote devices that are bonded (paired) to the local device.
+ * Removes the remote device and the pairing information associated
+ * with it.
*
- * Bonding (pairing) is the process by which the user enters a pin code for
- * the device, which generates a shared link key, allowing for
- * authentication and encryption of future connections. In Android we
- * require bonding before RFCOMM or SCO connections can be made to a remote
- * device.
- *
- * This function lists which remote devices we have a link key for. It does
- * not cause any RF transmission, and does not check if the remote device
- * still has it's link key with us. If the other side no longer has its
- * link key then the RFCOMM or SCO connection attempt will result in an
- * error.
- *
- * This function does not check if the remote device is in range.
- *
- * Remote devices that have an in-progress bonding attempt are not
- * returned.
- *
- * @return bluetooth hardware addresses of remote devices that are
- * bonded. Array size is 0 if no devices are bonded. Null on error.
+ * @return true if the device was disconnected, false otherwise and on
+ * error.
+ * @hide
*/
- public String[] listBonds() {
+ public boolean removeBond() {
try {
- return mService.listBonds();
+ return sService.removeBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
/**
@@ -324,77 +257,124 @@
*
* @param address Bluetooth hardware address of the remote device to check.
* @return Result code
+ * @hide
*/
- public int getBondState(String address) {
+ public int getBondState() {
try {
- return mService.getBondState(address);
+ return sService.getBondState(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
- public String getRemoteName(String address) {
+ /** @hide */
+ public int getBluetoothClass() {
try {
- return mService.getRemoteName(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
-
- public int getRemoteClass(String address) {
- try {
- return mService.getRemoteClass(address);
+ return sService.getRemoteClass(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
- public String[] getRemoteUuids(String address) {
+ /** @hide */
+ public String[] getUuids() {
try {
- return mService.getRemoteUuids(address);
+ return sService.getRemoteUuids(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
- public int getRemoteServiceChannel(String address, String uuid) {
+ /** @hide */
+ public int getServiceChannel(String uuid) {
try {
- return mService.getRemoteServiceChannel(address, uuid);
+ return sService.getRemoteServiceChannel(mAddress, uuid);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
- public boolean setPin(String address, byte[] pin) {
+ /** @hide */
+ public boolean setPin(byte[] pin) {
try {
- return mService.setPin(address, pin);
+ return sService.setPin(mAddress, pin);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
- public boolean setPasskey(String address, int passkey) {
+ /** @hide */
+ public boolean setPasskey(int passkey) {
try {
- return mService.setPasskey(address, passkey);
+ return sService.setPasskey(mAddress, passkey);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
- public boolean setPairingConfirmation(String address, boolean confirm) {
+ /** @hide */
+ public boolean setPairingConfirmation(boolean confirm) {
try {
- return mService.setPairingConfirmation(address, confirm);
+ return sService.setPairingConfirmation(mAddress, confirm);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
- public boolean cancelPairingUserInput(String address) {
+ /** @hide */
+ public boolean cancelPairingUserInput() {
try {
- return mService.cancelPairingUserInput(address);
+ return sService.cancelPairingUserInput(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
+ * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
+ * outgoing connection to this remote device.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * connection.
+ * <p>Valid RFCOMM channels are in range 1 to 30.
+ * @param channel RFCOMM channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ */
+ public BluetoothSocket createRfcommSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel);
+ }
+
+ /**
+ * Construct an insecure RFCOMM socket ready to start an outgoing
+ * connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * The remote device will not be authenticated and communication on this
+ * socket will not be encrypted.
+ * @param port remote port
+ * @return An RFCOMM BluetoothSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port);
+ }
+
+ /**
+ * Construct a SCO socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * @return a SCO BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createScoSocket() throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1);
+ }
+
+ /**
* Check that a pin is valid and convert to byte array.
*
* Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
* @param pin pin as java String
* @return the pin code as a UTF8 byte array, or null if it is an invalid
* Bluetooth pin.
+ * @hide
*/
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
@@ -413,8 +393,8 @@
return pinBytes;
}
- private static final int ADDRESS_LENGTH = 17;
- /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
+ /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0"
+ * @hide */
public static boolean checkBluetoothAddress(String address) {
if (address == null || address.length() != ADDRESS_LENGTH) {
return false;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index fe1e09a..d31b6ae 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -49,7 +49,7 @@
*
* @hide
*/
-public class BluetoothHeadset {
+public final class BluetoothHeadset {
private static final String TAG = "BluetoothHeadset";
private static final boolean DBG = false;
@@ -163,16 +163,16 @@
}
/**
- * Get the Bluetooth address of the current headset.
- * @return The Bluetooth address, or null if not in connected or connecting
+ * Get the BluetoothDevice for the current headset.
+ * @return current headset, or null if not in connected or connecting
* state, or if this proxy object is not connected to the Headset
* service.
*/
- public String getHeadsetAddress() {
- if (DBG) log("getHeadsetAddress()");
+ public BluetoothDevice getCurrentHeadset() {
+ if (DBG) log("getCurrentHeadset()");
if (mService != null) {
try {
- return mService.getHeadsetAddress();
+ return mService.getCurrentHeadset();
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -185,19 +185,19 @@
* Request to initiate a connection to a headset.
* This call does not block. Fails if a headset is already connecting
* or connected.
- * Initiates auto-connection if address is null. Tries to connect to all
+ * Initiates auto-connection if device is null. Tries to connect to all
* devices with priority greater than PRIORITY_AUTO in descending order.
- * @param address The Bluetooth Address to connect to, or null to
- * auto-connect to the last connected headset.
- * @return False if there was a problem initiating the connection
- * procedure, and no further HEADSET_STATE_CHANGED intents
- * will be expected.
+ * @param device device to connect to, or null to auto-connect last connected
+ * headset
+ * @return false if there was a problem initiating the connection
+ * procedure, and no further HEADSET_STATE_CHANGED intents
+ * will be expected.
*/
- public boolean connectHeadset(String address) {
- if (DBG) log("connectHeadset(" + address + ")");
+ public boolean connectHeadset(BluetoothDevice device) {
+ if (DBG) log("connectHeadset(" + device + ")");
if (mService != null) {
try {
- if (mService.connectHeadset(address)) {
+ if (mService.connectHeadset(device)) {
return true;
}
} catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -213,11 +213,11 @@
* connecting). Returns false if not connected, or if this proxy object
* if not currently connected to the headset service.
*/
- public boolean isConnected(String address) {
- if (DBG) log("isConnected(" + address + ")");
+ public boolean isConnected(BluetoothDevice device) {
+ if (DBG) log("isConnected(" + device + ")");
if (mService != null) {
try {
- return mService.isConnected(address);
+ return mService.isConnected(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -295,16 +295,16 @@
* auto-connected.
* Incoming connections are ignored regardless of priority if there is
* already a headset connected.
- * @param address Paired headset
+ * @param device paired headset
* @param priority Integer priority, for example PRIORITY_AUTO or
* PRIORITY_NONE
- * @return True if successful, false if there was some error.
+ * @return true if successful, false if there was some error
*/
- public boolean setPriority(String address, int priority) {
- if (DBG) log("setPriority(" + address + ", " + priority + ")");
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
if (mService != null) {
try {
- return mService.setPriority(address, priority);
+ return mService.setPriority(device, priority);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -315,14 +315,14 @@
/**
* Get priority of headset.
- * @param address Headset
- * @return non-negative priority, or negative error code on error.
+ * @param device headset
+ * @return non-negative priority, or negative error code on error
*/
- public int getPriority(String address) {
- if (DBG) log("getPriority(" + address + ")");
+ public int getPriority(BluetoothDevice device) {
+ if (DBG) log("getPriority(" + device + ")");
if (mService != null) {
try {
- return mService.getPriority(address);
+ return mService.getPriority(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -356,30 +356,6 @@
return -1;
}
- /**
- * Check class bits for possible HSP or HFP support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might support HSP or HFP. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- * @return True if this device might support HSP or HFP.
- */
- public static boolean doesClassMatch(int btClass) {
- // The render service class is required by the spec for HFP, so is a
- // pretty good signal
- if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
- return true;
- }
- // Just in case they forgot the render service class
- switch (BluetoothClass.Device.getDevice(btClass)) {
- case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
- case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- }
-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index d6c79b4..c39bc3d 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -31,8 +31,8 @@
public interface BluetoothIntent {
public static final String SCAN_MODE =
"android.bluetooth.intent.SCAN_MODE";
- public static final String ADDRESS =
- "android.bluetooth.intent.ADDRESS";
+ public static final String DEVICE =
+ "android.bluetooth.intent.DEVICE";
public static final String NAME =
"android.bluetooth.intent.NAME";
public static final String ALIAS =
@@ -62,6 +62,35 @@
public static final String PASSKEY =
"android.bluetooth.intent.PASSKEY";
+ public static final String DEVICE_PICKER_NEED_AUTH =
+ "android.bluetooth.intent.DEVICE_PICKER_NEED_AUTH";
+ public static final String DEVICE_PICKER_FILTER_TYPE =
+ "android.bluetooth.intent.DEVICE_PICKER_FILTER_TYPE";
+ public static final String DEVICE_PICKER_LAUNCH_PACKAGE =
+ "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_PACKAGE";
+ public static final String DEVICE_PICKER_LAUNCH_CLASS =
+ "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_CLASS";
+
+ /**
+ * Broadcast when one BT device is selected from BT device picker screen.
+ * Selected BT device address is contained in extra string "BluetoothIntent.ADDRESS".
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String DEVICE_PICKER_DEVICE_SELECTED =
+ "android.bluetooth.intent.action.DEVICE_SELECTED";
+
+ /**
+ * Broadcast when someone want to select one BT device from devices list.
+ * This intent contains below extra data:
+ * - BluetoothIntent.DEVICE_PICKER_NEED_AUTH (boolean): if need authentication
+ * - BluetoothIntent.DEVICE_PICKER_FILTER_TYPE (int): what kinds of device should be listed
+ * - BluetoothIntent.DEVICE_PICKER_LAUNCH_PACKAGE (string): where(which package) this intent come from
+ * - BluetoothIntent.DEVICE_PICKER_LAUNCH_CLASS (string): where(which class) this intent come from
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String DEVICE_PICKER_DEVICE_PICKER =
+ "android.bluetooth.intent.action.DEVICE_PICKER";
+
/** Broadcast when the local Bluetooth device state changes, for example
* when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and
* BLUETOOTH_PREVIOUS_STATE. */
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 5782644..645e241 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -73,11 +73,11 @@
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
- /** No Pce currently connected */
+ /** No client currently connected */
public static final int STATE_DISCONNECTED = 0;
/** Connection attempt in progress */
public static final int STATE_CONNECTING = 1;
- /** A Pce is currently connected */
+ /** Client is currently connected */
public static final int STATE_CONNECTED = 2;
public static final int RESULT_FAILURE = 0;
@@ -159,16 +159,16 @@
}
/**
- * Get the Bluetooth address of the current Pce.
- * @return The Bluetooth address, or null if not in connected or connecting
- * state, or if this proxy object is not connected to the Pbap
- * service.
+ * Get the currently connected remote Bluetooth device (PCE).
+ * @return The remote Bluetooth device, or null if not in connected or
+ * connecting state, or if this proxy object is not connected to
+ * the Pbap service.
*/
- public String getPceAddress() {
- if (DBG) log("getPceAddress()");
+ public BluetoothDevice getClient() {
+ if (DBG) log("getClient()");
if (mService != null) {
try {
- return mService.getPceAddress();
+ return mService.getClient();
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -178,15 +178,15 @@
}
/**
- * Returns true if the specified Pcs is connected (does not include
- * connecting). Returns false if not connected, or if this proxy object
- * if not currently connected to the Pbap service.
+ * Returns true if the specified Bluetooth device is connected (does not
+ * include connecting). Returns false if not connected, or if this proxy
+ * object is not currently connected to the Pbap service.
*/
- public boolean isConnected(String address) {
- if (DBG) log("isConnected(" + address + ")");
+ public boolean isConnected(BluetoothDevice device) {
+ if (DBG) log("isConnected(" + device + ")");
if (mService != null) {
try {
- return mService.isConnected(address);
+ return mService.isConnected(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -196,15 +196,15 @@
}
/**
- * Disconnects the current Pce. Currently this call blocks, it may soon
- * be made asynchornous. Returns false if this proxy object is
+ * Disconnects the current Pbap client (PCE). Currently this call blocks,
+ * it may soon be made asynchornous. Returns false if this proxy object is
* not currently connected to the Pbap service.
*/
- public boolean disconnectPce() {
- if (DBG) log("disconnectPce()");
+ public boolean disconnect() {
+ if (DBG) log("disconnect()");
if (mService != null) {
try {
- mService.disconnectPce();
+ mService.disconnect();
return true;
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index f3baeab..e653c23 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -20,85 +20,34 @@
import java.io.IOException;
/**
- * Server (listening) Bluetooth Socket.
+ * A listening Bluetooth socket.
*
- * Currently only supports RFCOMM sockets.
+ * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
+ * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
+ * side, use a {@link BluetoothServerSocket} to create a listening server
+ * socket. It will return a new, connected {@link BluetoothSocket} on an
+ * accepted connection. On the client side, use the same
+ * {@link BluetoothSocket} object to both intiate the outgoing connection,
+ * and to manage the connected socket.
*
- * RFCOMM is a connection orientated, streaming transport over Bluetooth. It is
- * also known as the Serial Port Profile (SPP).
+ * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
+ * connection orientated, streaming transport over Bluetooth. It is also known
+ * as the Serial Port Profile (SPP).
*
- * TODO: Consider exposing L2CAP sockets.
- * TODO: Clean up javadoc grammer and formatting.
- * TODO: Remove @hide
- * @hide
+ * <p>Use {@link BluetoothDevice#createRfcommSocket} to create a new {@link
+ * BluetoothSocket} ready for an outgoing connection to a remote
+ * {@link BluetoothDevice}.
+ *
+ * <p>Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ * {@link BluetoothServerSocket} ready for incoming connections to the local
+ * {@link BluetoothAdapter}.
+ *
+ * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * safe. In particular, {@link #close} will always immediately abort ongoing
+ * operations and close the socket.
*/
public final class BluetoothServerSocket implements Closeable {
- private final BluetoothSocket mSocket;
-
- /**
- * Construct a listening, secure RFCOMM server socket.
- * The remote device connecting to this socket will be authenticated and
- * communication on this socket will be encrypted.
- * Call #accept to retrieve connections to this socket.
- * @return An RFCOMM BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, true, true, port);
- try {
- socket.mSocket.bindListenNative();
- } catch (IOException e) {
- try {
- socket.close();
- } catch (IOException e2) { }
- throw e;
- }
- return socket;
- }
-
- /**
- * Construct an unencrypted, unauthenticated, RFCOMM server socket.
- * Call #accept to retrieve connections to this socket.
- * @return An RFCOMM BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, false, false, port);
- try {
- socket.mSocket.bindListenNative();
- } catch (IOException e) {
- try {
- socket.close();
- } catch (IOException e2) { }
- throw e;
- }
- return socket;
- }
-
- /**
- * Construct a SCO server socket.
- * Call #accept to retrieve connections to this socket.
- * @return A SCO BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothServerSocket listenUsingScoOn() throws IOException {
- BluetoothServerSocket socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_SCO, false, false, -1);
- try {
- socket.mSocket.bindListenNative();
- } catch (IOException e) {
- try {
- socket.close();
- } catch (IOException e2) { }
- throw e;
- }
- return socket;
- }
+ /*package*/ final BluetoothSocket mSocket;
/**
* Construct a socket for incoming connections.
@@ -109,18 +58,20 @@
* @throws IOException On error, for example Bluetooth not available, or
* insufficient priveleges
*/
- private BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
+ /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
throws IOException {
mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port);
}
/**
* Block until a connection is established.
- * Returns a connected #BluetoothSocket. This server socket can be reused
- * for subsequent incoming connections by calling #accept repeatedly.
- * #close can be used to abort this call from another thread.
- * @return A connected #BluetoothSocket
- * @throws IOException On error, for example this call was aborted
+ * <p>Returns a connected {@link BluetoothSocket} on successful connection.
+ * <p>Once this call returns, it can be called again to accept subsequent
+ * incoming connections.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @return a connected {@link BluetoothSocket}
+ * @throws IOException on error, for example this call was aborted, or
+ * timeout
*/
public BluetoothSocket accept() throws IOException {
return accept(-1);
@@ -128,11 +79,12 @@
/**
* Block until a connection is established, with timeout.
- * Returns a connected #BluetoothSocket. This server socket can be reused
- * for subsequent incoming connections by calling #accept repeatedly.
- * #close can be used to abort this call from another thread.
- * @return A connected #BluetoothSocket
- * @throws IOException On error, for example this call was aborted, or
+ * <p>Returns a connected {@link BluetoothSocket} on successful connection.
+ * <p>Once this call returns, it can be called again to accept subsequent
+ * incoming connections.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @return a connected {@link BluetoothSocket}
+ * @throws IOException on error, for example this call was aborted, or
* timeout
*/
public BluetoothSocket accept(int timeout) throws IOException {
@@ -140,8 +92,8 @@
}
/**
- * Closes this socket.
- * This will cause other blocking calls on this socket to immediately
+ * Immediately close this socket, and release all associated resources.
+ * <p>Causes blocked calls on this socket in other threads to immediately
* throw an IOException.
*/
public void close() throws IOException {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index de1f326..eae0f37 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -22,26 +22,41 @@
import java.io.OutputStream;
/**
- * Represents a connected or connecting Bluetooth Socket.
+ * A connected or connecting Bluetooth socket.
*
- * Currently only supports RFCOMM sockets.
+ * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
+ * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
+ * side, use a {@link BluetoothServerSocket} to create a listening server
+ * socket. It will return a new, connected {@link BluetoothSocket} on an
+ * accepted connection. On the client side, use the same
+ * {@link BluetoothSocket} object to both intiate the outgoing connection,
+ * and to manage the connected socket.
*
- * RFCOMM is a connection orientated, streaming transport over Bluetooth. It is
- * also known as the Serial Port Profile (SPP).
+ * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
+ * connection orientated, streaming transport over Bluetooth. It is also known
+ * as the Serial Port Profile (SPP).
*
- * TODO: Consider exposing L2CAP sockets.
- * TODO: Clean up javadoc grammer and formatting.
- * TODO: Remove @hide
- * @hide
+ * <p>Use {@link BluetoothDevice#createRfcommSocket} to create a new {@link
+ * BluetoothSocket} ready for an outgoing connection to a remote
+ * {@link BluetoothDevice}.
+ *
+ * <p>Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ * {@link BluetoothServerSocket} ready for incoming connections to the local
+ * {@link BluetoothAdapter}.
+ *
+ * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * safe. In particular, {@link #close} will always immediately abort ongoing
+ * operations and close the socket.
*/
public final class BluetoothSocket implements Closeable {
- /** Keep TYPE_RFCOMM etc in sync with BluetoothSocket.cpp */
+ /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
/*package*/ static final int TYPE_RFCOMM = 1;
/*package*/ static final int TYPE_SCO = 2;
/*package*/ static final int TYPE_L2CAP = 3;
private final int mType; /* one of TYPE_RFCOMM etc */
private final int mPort; /* RFCOMM channel or L2CAP psm */
+ private final BluetoothDevice mDevice; /* remote device */
private final String mAddress; /* remote address */
private final boolean mAuth;
private final boolean mEncrypt;
@@ -51,68 +66,27 @@
private int mSocketData; /* used by native code only */
/**
- * Construct a secure RFCOMM socket ready to start an outgoing connection.
- * Call #connect on the returned #BluetoothSocket to begin the connection.
- * The remote device will be authenticated and communication on this socket
- * will be encrypted.
- * @param address remote Bluetooth address that this socket can connect to
- * @param port remote port
- * @return an RFCOMM BluetoothSocket
- * @throws IOException on error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothSocket createRfcommSocket(String address, int port)
- throws IOException {
- return new BluetoothSocket(TYPE_RFCOMM, -1, true, true, address, port);
- }
-
- /**
- * Construct an insecure RFCOMM socket ready to start an outgoing
- * connection.
- * Call #connect on the returned #BluetoothSocket to begin the connection.
- * The remote device will not be authenticated and communication on this
- * socket will not be encrypted.
- * @param address remote Bluetooth address that this socket can connect to
- * @param port remote port
- * @return An RFCOMM BluetoothSocket
- * @throws IOException On error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothSocket createInsecureRfcommSocket(String address, int port)
- throws IOException {
- return new BluetoothSocket(TYPE_RFCOMM, -1, false, false, address, port);
- }
-
- /**
- * Construct a SCO socket ready to start an outgoing connection.
- * Call #connect on the returned #BluetoothSocket to begin the connection.
- * @param address remote Bluetooth address that this socket can connect to
- * @return a SCO BluetoothSocket
- * @throws IOException on error, for example Bluetooth not available, or
- * insufficient permissions.
- */
- public static BluetoothSocket createScoSocket(String address, int port)
- throws IOException {
- return new BluetoothSocket(TYPE_SCO, -1, true, true, address, port);
- }
-
- /**
- * Construct a Bluetooth.
+ * Construct a BluetoothSocket.
* @param type type of socket
* @param fd fd to use for connected socket, or -1 for a new socket
* @param auth require the remote device to be authenticated
* @param encrypt require the connection to be encrypted
- * @param address remote Bluetooth address that this socket can connect to
+ * @param device remote device that this socket can connect to
* @param port remote port
* @throws IOException On error, for example Bluetooth not available, or
* insufficient priveleges
*/
- /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
- int port) throws IOException {
+ /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
+ BluetoothDevice device, int port) throws IOException {
mType = type;
mAuth = auth;
mEncrypt = encrypt;
- mAddress = address;
+ mDevice = device;
+ if (device == null) {
+ mAddress = null;
+ } else {
+ mAddress = device.getAddress();
+ }
mPort = port;
if (fd == -1) {
initSocketNative();
@@ -123,6 +97,23 @@
mOutputStream = new BluetoothOutputStream(this);
}
+ /**
+ * Construct a BluetoothSocket from address.
+ * @param type type of socket
+ * @param fd fd to use for connected socket, or -1 for a new socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param address remote device that this socket can connect to
+ * @param port remote port
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient priveleges
+ */
+ private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
+ int port) throws IOException {
+ this(type, fd, auth, encrypt, new BluetoothDevice(address), port);
+ }
+
+ /** @hide */
@Override
protected void finalize() throws Throwable {
try {
@@ -134,19 +125,19 @@
/**
* Attempt to connect to a remote device.
- * This method will block until a connection is made or the connection
+ * <p>This method will block until a connection is made or the connection
* fails. If this method returns without an exception then this socket
- * is now connected. #close can be used to abort this call from another
- * thread.
- * @throws IOException On error, for example connection failure
+ * is now connected.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @throws IOException on error, for example connection failure
*/
public void connect() throws IOException {
connectNative();
}
/**
- * Closes this socket.
- * This will cause other blocking calls on this socket to immediately
+ * Immediately close this socket, and release all associated resources.
+ * <p>Causes blocked calls on this socket in other threads to immediately
* throw an IOException.
*/
public void close() throws IOException {
@@ -154,17 +145,16 @@
}
/**
- * Return the address we are connecting, or connected, to.
- * @return Bluetooth address, or null if this socket has not yet attempted
- * or established a connection.
+ * Get the remote device this socket is connecting, or connected, to.
+ * @return remote device
*/
- public String getAddress() {
- return mAddress;
+ public BluetoothDevice getRemoteDevice() {
+ return mDevice;
}
/**
* Get the input stream associated with this socket.
- * The input stream will be returned even if the socket is not yet
+ * <p>The input stream will be returned even if the socket is not yet
* connected, but operations on that stream will throw IOException until
* the associated socket is connected.
* @return InputStream
@@ -175,7 +165,7 @@
/**
* Get the output stream associated with this socket.
- * The output stream will be returned even if the socket is not yet
+ * <p>The output stream will be returned even if the socket is not yet
* connected, but operations on that stream will throw IOException until
* the associated socket is connected.
* @return OutputStream
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 1ec7fb38..c15bc20 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -37,6 +37,7 @@
public static final UUID Handsfree = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
public static final UUID AvrcpController =
UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+ public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB");
public static boolean isAudioSource(UUID uuid) {
return uuid.equals(AudioSource);
@@ -61,4 +62,8 @@
public static boolean isAvrcpController(UUID uuid) {
return uuid.equals(AvrcpController);
}
+
+ public static boolean isAvrcpTarget(UUID uuid) {
+ return uuid.equals(AvrcpTarget);
+ }
}
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index f987ffd..29cf41d 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -31,7 +31,7 @@
*
* @hide
*/
-public class HeadsetBase {
+public final class HeadsetBase {
private static final String TAG = "Bluetooth HeadsetBase";
private static final boolean DBG = false;
@@ -42,8 +42,9 @@
private static int sAtInputCount = 0; /* TODO: Consider not using a static variable */
- private final BluetoothDevice mBluetooth;
- private final String mAddress;
+ private final BluetoothAdapter mAdapter;
+ private final BluetoothDevice mRemoteDevice;
+ private final String mAddress; // for native code
private final int mRfcommChannel;
private int mNativeData;
private Thread mEventThread;
@@ -73,12 +74,13 @@
private native void cleanupNativeDataNative();
- public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address,
- int rfcommChannel) {
+ public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+ int rfcommChannel) {
mDirection = DIRECTION_OUTGOING;
mConnectTimestamp = System.currentTimeMillis();
- mBluetooth = bluetooth;
- mAddress = address;
+ mAdapter = adapter;
+ mRemoteDevice = device;
+ mAddress = device.getAddress();
mRfcommChannel = rfcommChannel;
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
mWakeLock.setReferenceCounted(false);
@@ -88,12 +90,13 @@
}
/* Create from an already exisiting rfcomm connection */
- public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, int socketFd,
- int rfcommChannel, Handler handler) {
+ public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+ int socketFd, int rfcommChannel, Handler handler) {
mDirection = DIRECTION_INCOMING;
mConnectTimestamp = System.currentTimeMillis();
- mBluetooth = bluetooth;
- mAddress = address;
+ mAdapter = adapter;
+ mRemoteDevice = device;
+ mAddress = device.getAddress();
mRfcommChannel = rfcommChannel;
mEventThreadHandler = handler;
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
@@ -252,12 +255,8 @@
return mEventThread != null;
}
- public String getAddress() {
- return mAddress;
- }
-
- public String getName() {
- return mBluetooth.getRemoteName(mAddress);
+ public BluetoothDevice getRemoteDevice() {
+ return mRemoteDevice;
}
public int getDirection() {
diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetooth.aidl
similarity index 98%
rename from core/java/android/bluetooth/IBluetoothDevice.aidl
rename to core/java/android/bluetooth/IBluetooth.aidl
index a78752b..9e05a87 100644
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -21,7 +21,7 @@
*
* {@hide}
*/
-interface IBluetoothDevice
+interface IBluetooth
{
boolean isEnabled();
int getBluetoothState();
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 55ff27f..e6c6be2 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -16,16 +16,18 @@
package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+
/**
* System private API for Bluetooth A2DP service
*
* {@hide}
*/
interface IBluetoothA2dp {
- int connectSink(in String address);
- int disconnectSink(in String address);
- List<String> listConnectedSinks();
- int getSinkState(in String address);
- int setSinkPriority(in String address, int priority);
- int getSinkPriority(in String address);
+ int connectSink(in BluetoothDevice device);
+ int disconnectSink(in BluetoothDevice device);
+ BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports
+ int getSinkState(in BluetoothDevice device);
+ int setSinkPriority(in BluetoothDevice device, int priority);
+ int getSinkPriority(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 5f42fd6..6cccd50 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+
/**
* System private API for Bluetooth Headset service
*
@@ -23,13 +25,13 @@
*/
interface IBluetoothHeadset {
int getState();
- String getHeadsetAddress();
- boolean connectHeadset(in String address);
+ BluetoothDevice getCurrentHeadset();
+ boolean connectHeadset(in BluetoothDevice device);
void disconnectHeadset();
- boolean isConnected(in String address);
+ boolean isConnected(in BluetoothDevice device);
boolean startVoiceRecognition();
boolean stopVoiceRecognition();
- boolean setPriority(in String address, int priority);
- int getPriority(in String address);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
int getBatteryUsageHint();
}
diff --git a/core/java/android/bluetooth/IBluetoothPbap.aidl b/core/java/android/bluetooth/IBluetoothPbap.aidl
index 06cdb7b..7cc77d1 100644
--- a/core/java/android/bluetooth/IBluetoothPbap.aidl
+++ b/core/java/android/bluetooth/IBluetoothPbap.aidl
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+
/**
* System private API for Bluetooth pbap service
*
@@ -23,8 +25,8 @@
*/
interface IBluetoothPbap {
int getState();
- String getPceAddress();
- boolean connectPce(in String address);
- void disconnectPce();
- boolean isConnected(in String address);
+ BluetoothDevice getClient();
+ boolean connect(in BluetoothDevice device);
+ void disconnect();
+ boolean isConnected(in BluetoothDevice device);
}
diff --git a/core/java/android/content/AbstractCursorEntityIterator.java b/core/java/android/content/AbstractCursorEntityIterator.java
index bf3c4de..c2b13a4 100644
--- a/core/java/android/content/AbstractCursorEntityIterator.java
+++ b/core/java/android/content/AbstractCursorEntityIterator.java
@@ -87,6 +87,14 @@
}
}
+ public void reset() throws RemoteException {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling reset() when the iterator is closed");
+ }
+ mEntityCursor.moveToPosition(-1);
+ 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.
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index 218f501..808f30c 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -170,7 +170,7 @@
// AbstractGDataSyncAdapter, which will put acore into a crash loop
ArrayList<Account> gaiaAccounts = new ArrayList<Account>();
for (Account acct: accounts) {
- if (acct.mType.equals("com.google.GAIA")) {
+ if (acct.type.equals("com.google.GAIA")) {
gaiaAccounts.add(acct);
}
}
@@ -693,7 +693,7 @@
if (!accounts.containsKey(account)) {
int numDeleted;
numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
- new String[]{account.mName, account.mType});
+ new String[]{account.name, account.type});
if (Config.LOGV) {
Log.v(TAG, "deleted " + numDeleted
+ " records from table " + table
@@ -726,7 +726,7 @@
// remove the data in the synced tables
for (String table : tables) {
db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
- new String[]{account.mName, account.mType});
+ new String[]{account.name, account.type});
}
db.setTransactionSuccessful();
} finally {
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index a3daa01e..9545fd7f 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -174,7 +174,7 @@
Cursor diffsCursor = null;
try {
// load the local database entries, so we can merge them with the server
- final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
+ final String[] accountSelectionArgs = new String[]{account.name, account.type};
localCursor = mDb.query(mTable, syncDirtyProjection,
SELECT_MARKED, accountSelectionArgs, null, null,
mTable + "." + _SYNC_ID);
@@ -487,7 +487,7 @@
try {
if (deleteBySyncId) {
selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
- account.mName, account.mType};
+ account.name, account.type};
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
selectionArgs, null, null, null);
} else {
@@ -534,7 +534,7 @@
SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
- final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
+ final String[] accountSelectionArgs = new String[]{account.name, account.type};
// Generate the client updates and insertions
// Create a cursor for dirty records
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index f15a902..424cb19 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -44,16 +44,23 @@
/** Kernel event log tag. Also listed in data/etc/event-log-tags. */
public static final int LOG_SYNC_DETAILS = 2743;
+ private final boolean mAutoInitialize;
/**
* Creates an {@link AbstractThreadedSyncAdapter}.
- * @param context the {@link Context} that this is running within.
+ * @param context the {@link android.content.Context} that this is running within.
+ * @param autoInitialize if true then sync requests that have
+ * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by
+ * {@link AbstractThreadedSyncAdapter} by calling
+ * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it
+ * is currently set to <0.
*/
- public AbstractThreadedSyncAdapter(Context context) {
+ public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) {
mContext = context;
mISyncAdapterImpl = new ISyncAdapterImpl();
mNumSyncStarts = new AtomicInteger(0);
mSyncThread = null;
+ mAutoInitialize = autoInitialize;
}
class ISyncAdapterImpl extends ISyncAdapter.Stub {
@@ -66,10 +73,18 @@
// check it and when we use it
synchronized (this) {
if (mSyncThread == null) {
+ if (mAutoInitialize
+ && extras != null
+ && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
+ if (ContentResolver.getIsSyncable(account, authority) < 0) {
+ ContentResolver.setIsSyncable(account, authority, 1);
+ }
+ syncContextClient.onFinished(new SyncResult());
+ return;
+ }
mSyncThread = new SyncThread(
"SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(),
syncContextClient, authority, account, extras);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mSyncThread.start();
alreadyInProgress = false;
} else {
@@ -117,6 +132,8 @@
}
public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
if (isCanceled()) {
return;
}
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index a4c217b..e367ceb 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -281,6 +281,10 @@
return mEntityIterator.next();
}
+ public void reset() throws RemoteException {
+ mEntityIterator.reset();
+ }
+
public void close() throws RemoteException {
mEntityIterator.close();
}
@@ -406,6 +410,10 @@
return mEntityIterator.next();
}
+ public void reset() throws RemoteException {
+ mEntityIterator.reset();
+ }
+
public void close() {
try {
mEntityIterator.close();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 98ed098..88a4d02f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -52,18 +52,29 @@
* @deprecated instead use
* {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
*/
+ @Deprecated
public static final String SYNC_EXTRAS_ACCOUNT = "account";
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
/**
* @deprecated instead use
* {@link #SYNC_EXTRAS_MANUAL}
*/
+ @Deprecated
public static final String SYNC_EXTRAS_FORCE = "force";
public static final String SYNC_EXTRAS_MANUAL = "force";
public static final String SYNC_EXTRAS_UPLOAD = "upload";
public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
+ /**
+ * Set by the SyncManager to request that the SyncAdapter initialize itself for
+ * the given account/authority pair. One required initialization step is to
+ * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
+ * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
+ * do a full sync, though it is allowed to do so.
+ */
+ public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
+
public static final String SCHEME_CONTENT = "content";
public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
public static final String SCHEME_FILE = "file";
@@ -233,6 +244,13 @@
return mInner.next();
}
+ public void reset() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ mInner.reset();
+ }
+
public void close() {
mClient.release();
mInner.close();
@@ -869,6 +887,7 @@
* @deprecated instead use
* {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
*/
+ @Deprecated
public void startSync(Uri uri, Bundle extras) {
Account account = null;
if (extras != null) {
@@ -949,6 +968,7 @@
* @param uri the uri of the provider to sync or null to sync all providers.
* @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
*/
+ @Deprecated
public void cancelSync(Uri uri) {
cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
}
@@ -1012,6 +1032,31 @@
}
/**
+ * Check if this account/provider is syncable.
+ * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
+ */
+ public static int getIsSyncable(Account account, String authority) {
+ try {
+ return getContentService().getIsSyncable(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Set whether this account/provider is syncable.
+ * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
+ */
+ public static void setIsSyncable(Account account, String authority, int syncable) {
+ try {
+ getContentService().setIsSyncable(account, authority, syncable);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
* Gets the master auto-sync setting that applies to all the providers and accounts.
* If this is false then the per-provider auto-sync setting is ignored.
*
@@ -1069,8 +1114,7 @@
}
/**
- * Returns the status that matches the authority. If there are multiples accounts for
- * the authority, the one with the latest "lastSuccessTime" status is returned.
+ * Returns the status that matches the authority.
* @param account the account whose setting we are querying
* @param authority the provider whose behavior is being queried
* @return the SyncStatusInfo for the authority, or null if none exists
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 7a1ad2b..f742448 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -197,7 +197,8 @@
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.scheduleSync(account, authority, extras, 0 /* no delay */);
+ syncManager.scheduleSync(account, authority, extras, 0 /* no delay */,
+ false /* onlyThoseWithUnkownSyncableState */);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -272,6 +273,37 @@
}
}
+ public int getIsSyncable(Account account, String providerName) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
+ "no permission to read the sync settings");
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ return syncManager.getSyncStorageEngine().getIsSyncable(
+ account, providerName);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ return -1;
+ }
+
+ public void setIsSyncable(Account account, String providerName, int syncable) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ syncManager.getSyncStorageEngine().setIsSyncable(
+ account, providerName, syncable);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
public boolean getMasterSyncAutomatically() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dbe6fb0..60551b8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -491,42 +491,49 @@
* @deprecated Use {@link android.app.WallpaperManager#getDrawable
* WallpaperManager.get()} instead.
*/
+ @Deprecated
public abstract Drawable getWallpaper();
/**
* @deprecated Use {@link android.app.WallpaperManager#peekDrawable
* WallpaperManager.peek()} instead.
*/
+ @Deprecated
public abstract Drawable peekWallpaper();
/**
* @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumWidth()
* WallpaperManager.getDesiredMinimumWidth()} instead.
*/
+ @Deprecated
public abstract int getWallpaperDesiredMinimumWidth();
/**
* @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumHeight()
* WallpaperManager.getDesiredMinimumHeight()} instead.
*/
+ @Deprecated
public abstract int getWallpaperDesiredMinimumHeight();
/**
* @deprecated Use {@link android.app.WallpaperManager#setBitmap(Bitmap)
* WallpaperManager.set()} instead.
*/
+ @Deprecated
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
/**
* @deprecated Use {@link android.app.WallpaperManager#setStream(InputStream)
* WallpaperManager.set()} instead.
*/
+ @Deprecated
public abstract void setWallpaper(InputStream data) throws IOException;
/**
* @deprecated Use {@link android.app.WallpaperManager#clear
* WallpaperManager.clear()} instead.
*/
+ @Deprecated
public abstract void clearWallpaper() throws IOException;
/**
@@ -1144,11 +1151,10 @@
public static final String SENSOR_SERVICE = "sensor";
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.bluetooth.BluetoothDevice} for interacting with Bluetooth.
+ * android.bluetooth.BluetoothAdapter} for using Bluetooth.
*
* @see #getSystemService
- * @see android.bluetooth.BluetoothDevice
- * @hide
+ * @see android.bluetooth.BluetoothAdapter
*/
public static final String BLUETOOTH_SERVICE = "bluetooth";
/**
diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java
index 5e5f14c..3cc1040 100644
--- a/core/java/android/content/EntityIterator.java
+++ b/core/java/android/content/EntityIterator.java
@@ -41,6 +41,8 @@
*/
public Entity next() throws RemoteException;
+ public void reset() throws RemoteException;
+
/**
* Indicates that this iterator is no longer needed and that any associated resources
* may be released (such as a SQLite cursor).
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 658a5bc..b0f14c1 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -54,6 +54,18 @@
*/
void setSyncAutomatically(in Account account, String providerName, boolean sync);
+ /**
+ * Check if this account/provider is syncable.
+ * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
+ */
+ int getIsSyncable(in Account account, String providerName);
+
+ /**
+ * Set whether this account/provider is syncable.
+ * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown
+ */
+ void setIsSyncable(in Account account, String providerName, int syncable);
+
void setMasterSyncAutomatically(boolean flag);
boolean getMasterSyncAutomatically();
diff --git a/core/java/android/content/IEntityIterator.java b/core/java/android/content/IEntityIterator.java
index 1c478b3..068581e 100644
--- a/core/java/android/content/IEntityIterator.java
+++ b/core/java/android/content/IEntityIterator.java
@@ -98,6 +98,20 @@
return true;
}
+ case TRANSACTION_reset:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ try {
+ this.reset();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in next()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ return true;
+ }
+
case TRANSACTION_close:
{
data.enforceInterface(DESCRIPTOR);
@@ -157,6 +171,19 @@
}
}
+ public void reset() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
public void close() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -174,8 +201,10 @@
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);
+ static final int TRANSACTION_reset = (IBinder.FIRST_CALL_TRANSACTION + 3);
}
public boolean hasNext() throws RemoteException;
public Entity next() throws RemoteException;
+ public void reset() throws RemoteException;
public void close() throws RemoteException;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f9b082f..9dedca6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1696,7 +1696,6 @@
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
-
/**
* Broadcast Action: a remote intent is to be broadcasted.
*
@@ -1711,6 +1710,18 @@
public static final String ACTION_REMOTE_INTENT =
"android.intent.action.REMOTE_INTENT";
+ /**
+ * Broadcast Action: hook for permforming cleanup after a system update.
+ *
+ * The broadcast is sent when the system is booting, before the
+ * BOOT_COMPLETED broadcast. It is only sent to receivers in the system
+ * image. A receiver for this should do its work and then disable itself
+ * so that it does not get run again at the next boot.
+ * @hide
+ */
+ public static final String ACTION_PRE_BOOT_COMPLETED =
+ "android.intent.action.PRE_BOOT_COMPLETED";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -1838,6 +1849,14 @@
*/
public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
"android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+
+ /**
+ * Broadcast Action: The phone was docked or undocked. Includes the extra
+ * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
+ * @hide
+ */
+ public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard extra data keys.
@@ -1960,6 +1979,37 @@
public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
/**
+ * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
+ * intents to request the dock state. Possible values are
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is not in any dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_UNDOCKED = 0;
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a desk dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_DESK = 1;
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a car dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_CAR = 2;
+
+ /**
* Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
* the bug report.
*
@@ -2212,6 +2262,13 @@
* @hide
*/
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000;
+ /**
+ * Set when this broadcast is for a boot upgrade, a special mode that
+ * allows the broadcast to be sent before the system is ready and launches
+ * the app process with no providers running in it.
+ * @hide
+ */
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x10000000;
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 1d5ade1..88dc332 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -32,7 +32,7 @@
class Transport extends ISyncAdapter.Stub {
public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) throws RemoteException {
- SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
+ SyncAdapter.this.startSync(new SyncContext(syncContext), account, authority, extras);
}
public void cancelSync(ISyncContext syncContext) throws RemoteException {
@@ -58,9 +58,11 @@
* @param syncContext the ISyncContext used to indicate the progress of the sync. When
* the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
* @param account the account that should be synced
+ * @param authority the authority if the sync request
* @param extras SyncAdapter-specific parameters
*/
- public abstract void startSync(SyncContext syncContext, Account account, Bundle extras);
+ public abstract void startSync(SyncContext syncContext, Account account, String authority,
+ Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 5a96003..25cbdb1 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -27,8 +27,12 @@
public class SyncAdapterType implements Parcelable {
public final String authority;
public final String accountType;
+ public final boolean isKey;
+ private final boolean userVisible;
+ private final boolean supportsUploading;
- public SyncAdapterType(String authority, String accountType) {
+ public SyncAdapterType(String authority, String accountType, boolean userVisible,
+ boolean supportsUploading) {
if (TextUtils.isEmpty(authority)) {
throw new IllegalArgumentException("the authority must not be empty: " + authority);
}
@@ -37,12 +41,50 @@
}
this.authority = authority;
this.accountType = accountType;
+ this.userVisible = userVisible;
+ this.supportsUploading = supportsUploading;
+ this.isKey = false;
+ }
+
+ private SyncAdapterType(String authority, String accountType) {
+ if (TextUtils.isEmpty(authority)) {
+ throw new IllegalArgumentException("the authority must not be empty: " + authority);
+ }
+ if (TextUtils.isEmpty(accountType)) {
+ throw new IllegalArgumentException("the accountType must not be empty: " + accountType);
+ }
+ this.authority = authority;
+ this.accountType = accountType;
+ this.userVisible = true;
+ this.supportsUploading = true;
+ this.isKey = true;
+ }
+
+ public boolean supportsUploading() {
+ if (isKey) {
+ throw new IllegalStateException(
+ "this method is not allowed to be called when this is a key");
+ }
+ return supportsUploading;
+ }
+
+ public boolean isUserVisible() {
+ if (isKey) {
+ throw new IllegalStateException(
+ "this method is not allowed to be called when this is a key");
+ }
+ return userVisible;
+ }
+
+ public static SyncAdapterType newKey(String authority, String accountType) {
+ return new SyncAdapterType(authority, accountType);
}
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof SyncAdapterType)) return false;
final SyncAdapterType other = (SyncAdapterType)o;
+ // don't include userVisible or supportsUploading in the equality check
return authority.equals(other.authority) && accountType.equals(other.accountType);
}
@@ -50,11 +92,22 @@
int result = 17;
result = 31 * result + authority.hashCode();
result = 31 * result + accountType.hashCode();
+ // don't include userVisible or supportsUploading the hash
return result;
}
public String toString() {
- return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}";
+ if (isKey) {
+ return "SyncAdapterType Key {name=" + authority
+ + ", type=" + accountType
+ + "}";
+ } else {
+ return "SyncAdapterType {name=" + authority
+ + ", type=" + accountType
+ + ", userVisible=" + userVisible
+ + ", supportsUploading=" + supportsUploading
+ + "}";
+ }
}
public int describeContents() {
@@ -62,12 +115,22 @@
}
public void writeToParcel(Parcel dest, int flags) {
+ if (isKey) {
+ throw new IllegalStateException("keys aren't parcelable");
+ }
+
dest.writeString(authority);
dest.writeString(accountType);
+ dest.writeInt(userVisible ? 1 : 0);
+ dest.writeInt(supportsUploading ? 1 : 0);
}
public SyncAdapterType(Parcel source) {
- this(source.readString(), source.readString());
+ this(
+ source.readString(),
+ source.readString(),
+ source.readInt() != 0,
+ source.readInt() != 0);
}
public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() {
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index ce47d76..7d9f1de 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -47,7 +47,12 @@
if (authority == null || accountType == null) {
return null;
}
- return new SyncAdapterType(authority, accountType);
+ final boolean userVisible =
+ sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true);
+ final boolean supportsUploading =
+ sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_supportsUploading,
+ true);
+ return new SyncAdapterType(authority, accountType, userVisible, supportsUploading);
} finally {
sa.recycle();
}
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index d54e260..15144a2 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -33,6 +33,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.RegisteredServicesCache;
+import android.content.pm.ProviderInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
@@ -180,7 +181,8 @@
};
public void onAccountsUpdated(Account[] accounts) {
- final boolean hadAccountsAlready = mAccounts != null;
+ // remember if this was the first time this was called after an update
+ final boolean justBootedUp = mAccounts == null;
mAccounts = accounts;
// if a sync is in progress yet it is no longer in the accounts list,
@@ -200,10 +202,22 @@
mSyncStorageEngine.doDatabaseCleanup(accounts);
- if (hadAccountsAlready && accounts.length > 0) {
- // request a sync so that if the password was changed we will
- // retry any sync that failed when it was wrong
- scheduleSync(null, null, null, 0 /* no delay */);
+ if (accounts.length > 0) {
+ // If this is the first time this was called after a bootup then
+ // the accounts haven't really changed, instead they were just loaded
+ // from the AccountManager. Otherwise at least one of the accounts
+ // has a change.
+ //
+ // If there was a real account change then force a sync of all accounts.
+ // This is a bit of overkill, but at least it will end up retrying syncs
+ // that failed due to an authentication failure and thus will recover if the
+ // account change was a password update.
+ //
+ // If this was the bootup case then don't sync everything, instead only
+ // sync those that have an unknown syncable state, which will give them
+ // a chance to set their syncable state.
+ boolean onlyThoseWithUnkownSyncableState = !justBootedUp;
+ scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState);
}
}
@@ -406,7 +420,7 @@
// perform a poll
scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */,
- new Bundle(), 0 /* no delay */);
+ new Bundle(), 0 /* no delay */, false /* onlyThoseWithUnkownSyncableState */);
}
private void writeSyncPollTime(long when) {
@@ -508,17 +522,11 @@
* syncs of a specific provider. Can be null. Is ignored
* if the url is null.
* @param delay how many milliseconds in the future to wait before performing this
+ * @param onlyThoseWithUnkownSyncableState
*/
public void scheduleSync(Account requestedAccount, String requestedAuthority,
- Bundle extras, long delay) {
+ Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- if (isLoggable) {
- Log.v(TAG, "scheduleSync:"
- + " delay " + delay
- + ", account " + requestedAccount
- + ", authority " + requestedAuthority
- + ", extras " + ((extras == null) ? "(null)" : extras));
- }
if (!isSyncEnabled()) {
if (isLoggable) {
@@ -589,22 +597,43 @@
// if the url was specified then replace the list of authorities with just this authority
// or clear it if this authority isn't syncable
if (requestedAuthority != null) {
- final boolean isSyncable = syncableAuthorities.contains(requestedAuthority);
+ final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
syncableAuthorities.clear();
- if (isSyncable) syncableAuthorities.add(requestedAuthority);
+ if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
}
for (String authority : syncableAuthorities) {
for (Account account : accounts) {
- if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.mType))
- != null) {
- scheduleSyncOperation(
- new SyncOperation(account, source, authority, extras, delay));
- // TODO: remove this when Calendar supports multiple accounts. Until then
- // pretend that only the first account exists when syncing calendar.
- if ("calendar".equals(authority)) {
- break;
+ int isSyncable = mSyncStorageEngine.getIsSyncable(account, authority);
+ if (isSyncable == 0) {
+ continue;
+ }
+ if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+ continue;
+ }
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, account.type));
+ if (syncAdapterInfo != null) {
+ if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
+ continue;
}
+ // make this an initialization sync if the isSyncable state is unknown
+ Bundle extrasCopy = extras;
+ if (isSyncable < 0) {
+ extrasCopy = new Bundle(extras);
+ extrasCopy.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ }
+ if (isLoggable) {
+ Log.v(TAG, "scheduleSync:"
+ + " delay " + delay
+ + ", source " + source
+ + ", account " + account
+ + ", authority " + authority
+ + ", extras " + extrasCopy);
+ }
+ scheduleSyncOperation(
+ new SyncOperation(account, source, authority, extrasCopy, delay));
}
}
}
@@ -617,7 +646,8 @@
public void scheduleLocalSync(Account account, String authority) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
- scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY);
+ scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY,
+ false /* onlyThoseWithUnkownSyncableState */);
}
private IPackageManager getPackageManager() {
@@ -1094,8 +1124,8 @@
for (int i=0; i<N; i++) {
SyncStorageEngine.PendingOperation op = ops.get(i);
pw.print(" #"); pw.print(i); pw.print(": account=");
- pw.print(op.account.mName); pw.print(":");
- pw.print(op.account.mType); pw.print(" authority=");
+ pw.print(op.account.name); pw.print(":");
+ pw.print(op.account.type); pw.print(" authority=");
pw.println(op.authority);
if (op.extras != null && op.extras.size() > 0) {
sb.setLength(0);
@@ -1125,8 +1155,8 @@
processedAccounts.add(curAccount);
- pw.print(" Account "); pw.print(authority.account.mName);
- pw.print(" "); pw.print(authority.account.mType);
+ pw.print(" Account "); pw.print(authority.account.name);
+ pw.print(" "); pw.print(authority.account.type);
pw.println(":");
for (int j=i; j<N; j++) {
status = statuses.get(j);
@@ -1248,9 +1278,9 @@
= mSyncStorageEngine.getAuthority(item.authorityId);
pw.print(" #"); pw.print(i+1); pw.print(": ");
if (authority != null) {
- pw.print(authority.account.mName);
+ pw.print(authority.account.name);
pw.print(":");
- pw.print(authority.account.mType);
+ pw.print(authority.account.type);
pw.print(" ");
pw.print(authority.authority);
} else {
@@ -1591,6 +1621,15 @@
&& mSyncStorageEngine.getMasterSyncAutomatically();
boolean syncAllowed =
manualSync || (backgroundDataUsageAllowed && syncAutomatically);
+ int isSyncable = mSyncStorageEngine.getIsSyncable(op.account, op.authority);
+ if (isSyncable == 0) {
+ // if not syncable, don't allow
+ syncAllowed = false;
+ } else if (isSyncable < 0) {
+ // if the syncable state is unknown, only allow initialization syncs
+ syncAllowed =
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
+ }
if (!syncAllowed) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: sync off, dropping " + op);
@@ -1635,8 +1674,7 @@
}
// connect to the sync adapter
- SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority,
- op.account.mType);
+ SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
mSyncAdapters.getServiceInfo(syncAdapterType);
if (syncAdapterInfo == null) {
@@ -1959,11 +1997,19 @@
private void installHandleTooManyDeletesNotification(Account account, String authority,
long numDeletes) {
if (mNotificationMgr == null) return;
+
+ final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
+ authority, 0 /* flags */);
+ if (providerInfo == null) {
+ return;
+ }
+ CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
+
Intent clickIntent = new Intent();
clickIntent.setClassName("com.android.providers.subscribedfeeds",
"com.android.settings.SyncActivityTooManyDeletes");
clickIntent.putExtra("account", account);
- clickIntent.putExtra("provider", authority);
+ clickIntent.putExtra("provider", authorityName.toString());
clickIntent.putExtra("numDeletes", numDeletes);
if (!isActivityAvailable(clickIntent)) {
@@ -1977,14 +2023,13 @@
CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
R.string.contentServiceTooManyDeletesNotificationDesc);
- String[] authorities = authority.split(";");
Notification notification =
new Notification(R.drawable.stat_notify_sync_error,
mContext.getString(R.string.contentServiceSync),
System.currentTimeMillis());
notification.setLatestEventInfo(mContext,
mContext.getString(R.string.contentServiceSyncNotificationTitle),
- String.format(tooManyDeletesDescFormat.toString(), authorities[0]),
+ String.format(tooManyDeletesDescFormat.toString(), authorityName),
pendingIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
mNotificationMgr.notify(account.hashCode() ^ authority.hashCode(), notification);
diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java
index f3260f3..4c201e6 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -113,14 +113,19 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(" syncAlreadyInProgress: ").append(syncAlreadyInProgress);
- sb.append(" tooManyDeletions: ").append(tooManyDeletions);
- sb.append(" tooManyRetries: ").append(tooManyRetries);
- sb.append(" databaseError: ").append(databaseError);
- sb.append(" fullSyncRequested: ").append(fullSyncRequested);
- sb.append(" partialSyncUnavailable: ").append(partialSyncUnavailable);
- sb.append(" moreRecordsToGet: ").append(moreRecordsToGet);
- sb.append(" stats: ").append(stats);
+ sb.append("SyncResult:");
+ if (syncAlreadyInProgress) {
+ sb.append(" syncAlreadyInProgress: ").append(syncAlreadyInProgress);
+ }
+ if (tooManyDeletions) sb.append(" tooManyDeletions: ").append(tooManyDeletions);
+ if (tooManyRetries) sb.append(" tooManyRetries: ").append(tooManyRetries);
+ if (databaseError) sb.append(" databaseError: ").append(databaseError);
+ if (fullSyncRequested) sb.append(" fullSyncRequested: ").append(fullSyncRequested);
+ if (partialSyncUnavailable) {
+ sb.append(" partialSyncUnavailable: ").append(partialSyncUnavailable);
+ }
+ if (moreRecordsToGet) sb.append(" moreRecordsToGet: ").append(moreRecordsToGet);
+ sb.append(stats);
return sb.toString();
}
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index dc728ec..64bbe25 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -172,7 +172,7 @@
*/
public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
Account account) {
- final String[] whereArgs = new String[]{account.mName, account.mType};
+ final String[] whereArgs = new String[]{account.name, account.type};
Cursor c = dbSrc.query(SYNC_STATE_TABLE,
new String[]{"_sync_account", "_sync_account_type", "data"},
ACCOUNT_WHERE, whereArgs, null, null, null);
@@ -209,7 +209,7 @@
public void discardSyncData(SQLiteDatabase db, Account account) {
if (account != null) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.name, account.type});
} else {
db.delete(SYNC_STATE_TABLE, null, null);
}
@@ -220,7 +220,7 @@
*/
public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
- new String[]{account.mName, account.mType}, null, null, null);
+ new String[]{account.name, account.type}, null, null, null);
try {
if (c.moveToFirst()) {
return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -238,6 +238,6 @@
ContentValues values = new ContentValues();
values.put("data", data);
db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
- new String[]{account.mName, account.mType});
+ new String[]{account.name, account.type});
}
}
diff --git a/core/java/android/content/SyncStats.java b/core/java/android/content/SyncStats.java
index b561b05..cc544c0 100644
--- a/core/java/android/content/SyncStats.java
+++ b/core/java/android/content/SyncStats.java
@@ -60,15 +60,18 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("numAuthExceptions: ").append(numAuthExceptions);
- sb.append(" numIoExceptions: ").append(numIoExceptions);
- sb.append(" numParseExceptions: ").append(numParseExceptions);
- sb.append(" numConflictDetectedExceptions: ").append(numConflictDetectedExceptions);
- sb.append(" numInserts: ").append(numInserts);
- sb.append(" numUpdates: ").append(numUpdates);
- sb.append(" numDeletes: ").append(numDeletes);
- sb.append(" numEntries: ").append(numEntries);
- sb.append(" numSkippedEntries: ").append(numSkippedEntries);
+ sb.append(" stats [");
+ if (numAuthExceptions > 0) sb.append(" numAuthExceptions: ").append(numAuthExceptions);
+ if (numIoExceptions > 0) sb.append(" numIoExceptions: ").append(numIoExceptions);
+ if (numParseExceptions > 0) sb.append(" numParseExceptions: ").append(numParseExceptions);
+ if (numConflictDetectedExceptions > 0)
+ sb.append(" numConflictDetectedExceptions: ").append(numConflictDetectedExceptions);
+ if (numInserts > 0) sb.append(" numInserts: ").append(numInserts);
+ if (numUpdates > 0) sb.append(" numUpdates: ").append(numUpdates);
+ if (numDeletes > 0) sb.append(" numDeletes: ").append(numDeletes);
+ if (numEntries > 0) sb.append(" numEntries: ").append(numEntries);
+ if (numSkippedEntries > 0) sb.append(" numSkippedEntries: ").append(numSkippedEntries);
+ sb.append("]");
return sb.toString();
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 8cc0642..3ff13ae 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -155,12 +155,14 @@
final String authority;
final int ident;
boolean enabled;
+ int syncable;
AuthorityInfo(Account account, String authority, int ident) {
this.account = account;
this.authority = authority;
this.ident = ident;
enabled = SYNC_ENABLED_DEFAULT;
+ syncable = -1; // default to "unknown"
}
}
@@ -392,6 +394,50 @@
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
+ public int getIsSyncable(Account account, String providerName) {
+ synchronized (mAuthorities) {
+ if (account != null) {
+ AuthorityInfo authority = getAuthorityLocked(account, providerName,
+ "getIsSyncable");
+ if (authority == null) {
+ return -1;
+ }
+ return authority.syncable;
+ }
+
+ int i = mAuthorities.size();
+ while (i > 0) {
+ i--;
+ AuthorityInfo authority = mAuthorities.get(i);
+ if (authority.authority.equals(providerName)) {
+ return authority.syncable;
+ }
+ }
+ return -1;
+ }
+ }
+
+ public void setIsSyncable(Account account, String providerName, int syncable) {
+ int oldState;
+ if (syncable > 1) {
+ syncable = 1;
+ } else if (syncable < -1) {
+ syncable = -1;
+ }
+ Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName + " -> " + syncable);
+ synchronized (mAuthorities) {
+ AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
+ oldState = authority.syncable;
+ authority.syncable = syncable;
+ writeAccountInfoLocked();
+ }
+
+ if (oldState <= 0 && syncable > 0) {
+ mContext.getContentResolver().requestSync(account, providerName, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+
public void setMasterSyncAutomatically(boolean flag) {
boolean old;
synchronized (mAuthorities) {
@@ -949,14 +995,18 @@
AccountInfo account = mAccounts.get(accountName);
if (account == null) {
if (tag != null) {
- Log.w(TAG, tag + ": unknown account " + accountName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown account " + accountName);
+ }
}
return null;
}
AuthorityInfo authority = account.authorities.get(authorityName);
if (authority == null) {
if (tag != null) {
- Log.w(TAG, tag + ": unknown authority " + authorityName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown authority " + authorityName);
+ }
}
return null;
}
@@ -984,6 +1034,8 @@
ident++;
}
}
+ Log.d(TAG, "created a new AuthorityInfo for " + accountName
+ + ", provider " + authorityName);
authority = new AuthorityInfo(accountName, authorityName, ident);
account.authorities.put(authorityName, authority);
mAuthorities.put(ident, authority);
@@ -1064,10 +1116,12 @@
null, "authority");
String enabled = parser.getAttributeValue(
null, "enabled");
- AuthorityInfo authority = mAuthorities.get(id);
+ String syncable = parser.getAttributeValue(null, "syncable");
+ AuthorityInfo authority = mAuthorities.get(id);
if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
+ accountName + " auth=" + authorityName
- + " enabled=" + enabled);
+ + " enabled=" + enabled
+ + " syncable=" + syncable);
if (authority == null) {
if (DEBUG_FILE) Log.v(TAG, "Creating entry");
authority = getOrCreateAuthorityLocked(
@@ -1077,10 +1131,19 @@
if (authority != null) {
authority.enabled = enabled == null
|| Boolean.parseBoolean(enabled);
+ if ("unknown".equals(syncable)) {
+ authority.syncable = -1;
+ } else {
+ authority.syncable =
+ (syncable == null || Boolean.parseBoolean(enabled))
+ ? 1
+ : 0;
+ }
} else {
Log.w(TAG, "Failure adding authority: account="
+ accountName + " auth=" + authorityName
- + " enabled=" + enabled);
+ + " enabled=" + enabled
+ + " syncable=" + syncable);
}
}
}
@@ -1127,12 +1190,17 @@
AuthorityInfo authority = mAuthorities.get(i);
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, "account", authority.account.mName);
- out.attribute(null, "type", authority.account.mType);
+ out.attribute(null, "account", authority.account.name);
+ out.attribute(null, "type", authority.account.type);
out.attribute(null, "authority", authority.authority);
if (!authority.enabled) {
out.attribute(null, "enabled", "false");
}
+ if (authority.syncable < 0) {
+ out.attribute(null, "syncable", "unknown");
+ } else if (authority.syncable == 0) {
+ out.attribute(null, "syncable", "false");
+ }
out.endTag(null, "authority");
}
@@ -1268,6 +1336,7 @@
AuthorityInfo authority = mAuthorities.get(i);
if (authority.authority.equals(provider)) {
authority.enabled = value == null || Boolean.parseBoolean(value);
+ authority.syncable = 1;
}
}
}
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index fb05fe7..b46c545 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -13,6 +13,10 @@
import android.util.Log;
import android.util.TimingLogger;
import android.accounts.Account;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+
+import java.io.IOException;
/**
* @hide
@@ -84,6 +88,9 @@
*/
public abstract boolean isReadOnly();
+ public abstract boolean getIsSyncable(Account account)
+ throws IOException, AuthenticatorException, OperationCanceledException;
+
/**
* Get diffs from the server since the last completed sync and put them
* into a temporary provider.
@@ -173,6 +180,7 @@
private class SyncThread extends Thread {
private final Account mAccount;
+ private final String mAuthority;
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
@@ -180,9 +188,10 @@
private long mInitialRxBytes;
private final SyncResult mResult;
- SyncThread(SyncContext syncContext, Account account, Bundle extras) {
+ SyncThread(SyncContext syncContext, Account account, String authority, Bundle extras) {
super("SyncThread");
mAccount = account;
+ mAuthority = authority;
mExtras = extras;
mSyncContext = syncContext;
mResult = new SyncResult();
@@ -206,7 +215,7 @@
mInitialTxBytes = NetStat.getUidTxBytes(uid);
mInitialRxBytes = NetStat.getUidRxBytes(uid);
try {
- sync(mSyncContext, mAccount, mExtras);
+ sync(mSyncContext, mAccount, mAuthority, mExtras);
} catch (SQLException e) {
Log.e(TAG, "Sync failed", e);
mResult.databaseError = true;
@@ -220,13 +229,39 @@
}
}
- private void sync(SyncContext syncContext, Account account, Bundle extras) {
+ private void sync(SyncContext syncContext, Account account, String authority,
+ Bundle extras) {
mIsCanceled = false;
mProviderSyncStarted = false;
mAdapterSyncStarted = false;
String message = null;
+ // always attempt to initialize if the isSyncable state isn't set yet
+ int isSyncable = ContentResolver.getIsSyncable(account, authority);
+ if (isSyncable < 0) {
+ try {
+ isSyncable = (getIsSyncable(account)) ? 1 : 0;
+ ContentResolver.setIsSyncable(account, authority, isSyncable);
+ } catch (IOException e) {
+ ++mResult.stats.numIoExceptions;
+ } catch (AuthenticatorException e) {
+ ++mResult.stats.numParseExceptions;
+ } catch (OperationCanceledException e) {
+ // do nothing
+ }
+ }
+
+ // if this is an initialization request then our work is done here
+ if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
+ return;
+ }
+
+ // if we aren't syncable then get out
+ if (isSyncable <= 0) {
+ return;
+ }
+
boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
try {
@@ -517,13 +552,14 @@
EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, "");
}
- public void startSync(SyncContext syncContext, Account account, Bundle extras) {
+ public void startSync(SyncContext syncContext, Account account, String authority,
+ Bundle extras) {
if (mSyncThread != null) {
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
return;
}
- mSyncThread = new SyncThread(syncContext, account, extras);
+ mSyncThread = new SyncThread(syncContext, account, authority, extras);
mSyncThread.start();
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7760612..4fc4fb9 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -123,7 +123,6 @@
* providers that can sync.
* @param outInfo Filled in with a list of the ProviderInfo for each
* name in 'outNames'.
- * @deprecated
*/
void querySyncProviders(inout List<String> outNames,
inout List<ProviderInfo> outInfo);
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index d61e95b..ec01775 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -79,6 +79,7 @@
* @deprecated This flag is now being ignored. The current way to make a provider
* syncable is to provide a SyncAdapter service for a given provider/account type.
*/
+ @Deprecated
public boolean isSyncable = false;
public ProviderInfo() {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2354519..7d412a7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -23,6 +23,7 @@
import org.xmlpull.v1.XmlPullParserException;
import android.content.pm.ApplicationInfo;
+import android.graphics.BitmapFactory;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
@@ -1707,7 +1708,8 @@
InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_BUFFER);
// System.out.println("Opened file " + file + ": " + is);
- dr = Drawable.createFromResourceStream(this, value, is, file);
+ dr = Drawable.createFromResourceStream(this, value, is,
+ file, null);
is.close();
// System.out.println("Created stream: " + dr);
} catch (Exception e) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 184d6dc..6143b6c 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -517,6 +517,7 @@
* @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
* will not be yielded. Use yieldIfContendedSafely instead.
*/
+ @Deprecated
public boolean yieldIfContended() {
return yieldIfContendedHelper(false /* do not check yielding */);
}
diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java
index cfa184b..c71e968 100644
--- a/core/java/android/hardware/SensorListener.java
+++ b/core/java/android/hardware/SensorListener.java
@@ -20,9 +20,8 @@
* Used for receiving notifications from the SensorManager when
* sensor values have changed.
*
- * This interface is deprecated, use
+ * @deprecated Use
* {@link android.hardware.SensorEventListener SensorEventListener} instead.
- *
*/
@Deprecated
public interface SensorListener {
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index bf945ec..271f973 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -116,47 +116,67 @@
@Deprecated
public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
- /** A constant that includes all sensors */
+ /** A constant that includes all sensors
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_ALL = 0x7F;
- /** Smallest sensor ID */
+ /** Smallest sensor ID
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_MIN = SENSOR_ORIENTATION;
- /** Largest sensor ID */
+ /** Largest sensor ID
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
/** Index of the X value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_X = 0;
/** Index of the Y value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_Y = 1;
/** Index of the Z value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_Z = 2;
/** Offset to the untransformed values in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_INDEX = 3;
/** Index of the untransformed X value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_X = 3;
/** Index of the untransformed Y value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_Y = 4;
/** Index of the untransformed Z value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_Z = 5;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6ee92ce..1f640ea 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1992,8 +1992,9 @@
req.flags = InputConnection.GET_TEXT_WITH_STYLES;
req.hintMaxLines = 10;
req.hintMaxChars = 10000;
- mExtractedText = getCurrentInputConnection().getExtractedText(req,
- InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+ InputConnection ic = getCurrentInputConnection();
+ mExtractedText = ic == null? null
+ : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
final EditorInfo ei = getCurrentInputEditorInfo();
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 9e966cd..a141a2a 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1037,6 +1037,10 @@
me.getX(), me.getY(), me.getMetaState());
result = onModifiedTouchEvent(down);
down.recycle();
+ // If it's an up action, then deliver the up as well.
+ if (me.getAction() == MotionEvent.ACTION_UP) {
+ result = onModifiedTouchEvent(me);
+ }
} else {
// Send an up event for the last pointer
MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
@@ -1067,7 +1071,7 @@
if (mGestureDetector.onTouchEvent(me)) {
showPreview(NOT_A_KEY);
mHandler.removeMessages(MSG_REPEAT);
- mHandler.removeMessages(MSG_LONGPRESS);
+ mHandler.removeMessages(MSG_LONGPRESS);
return true;
}
@@ -1116,7 +1120,7 @@
if (keyIndex == mCurrentKey) {
mCurrentKeyTime += eventTime - mLastMoveTime;
continueLongPress = true;
- } else {
+ } else if (mRepeatKeyIndex == NOT_A_KEY) {
resetMultiTap();
mLastKey = mCurrentKey;
mLastCodeX = mLastX;
@@ -1127,10 +1131,6 @@
mCurrentKeyTime = 0;
}
}
- if (keyIndex != mRepeatKeyIndex) {
- mHandler.removeMessages(MSG_REPEAT);
- mRepeatKeyIndex = NOT_A_KEY;
- }
}
if (!continueLongPress) {
// Cancel old longpress
@@ -1141,7 +1141,7 @@
mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT);
}
}
- showPreview(keyIndex);
+ showPreview(mCurrentKey);
break;
case MotionEvent.ACTION_UP:
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 6b00900..f88fcdc 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -49,7 +49,7 @@
private String mApnType;
private boolean mEnabled;
- private boolean mTeardownRequested;
+ private BroadcastReceiver mStateReceiver;
/**
* Create a new MobileDataStateTracker
@@ -66,7 +66,6 @@
TelephonyManager.getDefault().getNetworkTypeName());
mApnType = apnType;
mPhoneService = null;
- mTeardownRequested = false;
if(netType == ConnectivityManager.TYPE_MOBILE) {
mEnabled = true;
} else {
@@ -81,7 +80,9 @@
"net.eth0.dns3",
"net.eth0.dns4",
"net.gprs.dns1",
- "net.gprs.dns2"};
+ "net.gprs.dns2",
+ "net.ppp0.dns1",
+ "net.ppp0.dns2"};
}
@@ -94,7 +95,8 @@
filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
- Intent intent = mContext.registerReceiver(new MobileDataStateReceiver(), filter);
+ mStateReceiver = new MobileDataStateReceiver();
+ Intent intent = mContext.registerReceiver(mStateReceiver, filter);
if (intent != null)
mMobileDataState = getMobileDataState(intent);
else
@@ -130,74 +132,91 @@
private class MobileDataStateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(TelephonyIntents.
- ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
- Phone.DataState state = getMobileDataState(intent);
- String reason =
- intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
- String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ synchronized(this) {
+ if (intent.getAction().equals(TelephonyIntents.
+ ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+ Phone.DataState state = getMobileDataState(intent);
+ String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
+ String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ String apnTypeList = intent.getStringExtra(Phone.DATA_APN_TYPES_KEY);
- String apnTypeList =
- intent.getStringExtra(Phone.DATA_APN_TYPES_KEY);
-
- boolean unavailable = intent.getBooleanExtra(
- Phone.NETWORK_UNAVAILABLE_KEY, false);
- if (DBG) Log.d(TAG, mApnType + " Received "
- + intent.getAction() + " broadcast - state = "
- + state + ", unavailable = " + unavailable
- + ", reason = "
- + (reason == null ? "(unspecified)" : reason));
-
- if ((!isApnTypeIncluded(apnTypeList)) || mEnabled == false) {
- if (DBG) Log.e(TAG, " dropped - mEnabled = "+mEnabled);
- return;
- }
+ boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,
+ false);
+ if (DBG) Log.d(TAG, mApnType + " Received " + intent.getAction() +
+ " broadcast - state = " + state + ", oldstate = " + mMobileDataState +
+ ", unavailable = " + unavailable + ", reason = " +
+ (reason == null ? "(unspecified)" : reason));
- mNetworkInfo.setIsAvailable(!unavailable);
- if (mMobileDataState != state) {
- mMobileDataState = state;
-
- switch (state) {
- case DISCONNECTED:
- if(mTeardownRequested) {
- mEnabled = false;
- mTeardownRequested = false;
+ if (isApnTypeIncluded(apnTypeList)) {
+ // set this even if the apn isn't Enabled
+ mNetworkInfo.setIsAvailable(!unavailable);
+ if (mEnabled == false) {
+ // if we're not enabled but the APN Type is supported by this connection
+ // we should record the interface name if one's provided. If the user
+ // turns on this network we will need the interfacename but won't get
+ // a fresh connected message - TODO fix this..
+ if (state == Phone.DataState.CONNECTED) {
+ if (DBG) Log.d(TAG, "replacing old mInterfaceName (" +
+ mInterfaceName + ") with " +
+ intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY) +
+ " for " + mApnType);
+ mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
+ }
+ if (DBG) Log.d(TAG, " dropped - mEnabled = false");
+ return;
}
-
- setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
- if (mInterfaceName != null) {
- NetworkUtils.resetConnections(mInterfaceName);
- }
- mInterfaceName = null;
- mDefaultGatewayAddr = 0;
- break;
- case CONNECTING:
- setDetailedState(DetailedState.CONNECTING, reason, apnName);
- break;
- case SUSPENDED:
- setDetailedState(DetailedState.SUSPENDED, reason, apnName);
- break;
- case CONNECTED:
- mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
- if (mInterfaceName == null) {
- Log.d(TAG, "CONNECTED event did not supply interface name.");
- }
- setDetailedState(DetailedState.CONNECTED, reason, apnName);
- break;
+ } else {
+ if (DBG) Log.d(TAG, " dropped - wrong Apn");
+ return;
}
+
+ if (mMobileDataState != state) {
+ mMobileDataState = state;
+ switch (state) {
+ case DISCONNECTED:
+ if(isTeardownRequested()) {
+ mEnabled = false;
+ setTeardownRequested(false);
+ }
+
+ setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
+ if (mInterfaceName != null) {
+ NetworkUtils.resetConnections(mInterfaceName);
+ }
+ if (DBG) Log.d(TAG, "clearing mInterfaceName for "+ mApnType +
+ " as it DISCONNECTED");
+ mInterfaceName = null;
+ mDefaultGatewayAddr = 0;
+ break;
+ case CONNECTING:
+ setDetailedState(DetailedState.CONNECTING, reason, apnName);
+ break;
+ case SUSPENDED:
+ setDetailedState(DetailedState.SUSPENDED, reason, apnName);
+ break;
+ case CONNECTED:
+ mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
+ if (mInterfaceName == null) {
+ Log.d(TAG, "CONNECTED event did not supply interface name.");
+ }
+ setDetailedState(DetailedState.CONNECTED, reason, apnName);
+ break;
+ }
+ }
+ } else if (intent.getAction().
+ equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
+ mEnabled = false;
+ String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY);
+ String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" +
+ reason == null ? "" : "(" + reason + ")");
+ setDetailedState(DetailedState.FAILED, reason, apnName);
}
- } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
- mEnabled = false;
- String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY);
- String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
- if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" +
- reason == null ? "" : "(" + reason + ")");
- setDetailedState(DetailedState.FAILED, reason, apnName);
+ TelephonyManager tm = TelephonyManager.getDefault();
+ setRoamingStatus(tm.isNetworkRoaming());
+ setSubtype(tm.getNetworkType(), tm.getNetworkTypeName());
}
- TelephonyManager tm = TelephonyManager.getDefault();
- setRoamingStatus(tm.isNetworkRoaming());
- setSubtype(tm.getNetworkType(), tm.getNetworkTypeName());
}
}
@@ -258,9 +277,21 @@
case TelephonyManager.NETWORK_TYPE_UMTS:
networkTypeStr = "umts";
break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ networkTypeStr = "hsdpa";
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ networkTypeStr = "hsupa";
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ networkTypeStr = "hspa";
+ break;
case TelephonyManager.NETWORK_TYPE_CDMA:
networkTypeStr = "cdma";
break;
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ networkTypeStr = "1xrtt";
+ break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
networkTypeStr = "evdo";
break;
@@ -277,7 +308,7 @@
*/
@Override
public boolean teardown() {
- mTeardownRequested = true;
+ setTeardownRequested(true);
return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED);
}
@@ -285,10 +316,42 @@
* Re-enable mobile data connectivity after a {@link #teardown()}.
*/
public boolean reconnect() {
- mEnabled = true;
- mTeardownRequested = false;
- mEnabled = (setEnableApn(mApnType, true) !=
- Phone.APN_REQUEST_FAILED);
+ setTeardownRequested(false);
+ switch (setEnableApn(mApnType, true)) {
+ case Phone.APN_ALREADY_ACTIVE:
+ mEnabled = true;
+ // need to set self to CONNECTING so the below message is handled.
+ mMobileDataState = Phone.DataState.CONNECTING;
+ setDetailedState(DetailedState.CONNECTING, Phone.REASON_APN_CHANGED, null);
+ //send out a connected message
+ Intent intent = new Intent(TelephonyIntents.
+ ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ intent.putExtra(Phone.STATE_KEY, Phone.DataState.CONNECTED.toString());
+ intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, Phone.REASON_APN_CHANGED);
+ intent.putExtra(Phone.DATA_APN_TYPES_KEY, mApnType);
+ intent.putExtra(Phone.DATA_IFACE_NAME_KEY, mInterfaceName);
+ intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
+ if (mStateReceiver != null) mStateReceiver.onReceive(mContext, intent);
+ break;
+ case Phone.APN_REQUEST_STARTED:
+ mEnabled = true;
+ // no need to do anything - we're already due some status update intents
+ break;
+ case Phone.APN_REQUEST_FAILED:
+ if (mPhoneService == null && mApnType == Phone.APN_TYPE_DEFAULT) {
+ // on startup we may try to talk to the phone before it's ready
+ // just leave mEnabled as it is for the default apn.
+ return false;
+ }
+ // else fall through
+ case Phone.APN_TYPE_NOT_AVAILABLE:
+ mEnabled = false;
+ break;
+ default:
+ Log.e(TAG, "Error in reconnect - unexpected response.");
+ mEnabled = false;
+ break;
+ }
return mEnabled;
}
@@ -371,10 +434,11 @@
*/
@Override
public boolean requestRouteToHost(int hostAddress) {
+ if (DBG) {
+ Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) +
+ " for " + mApnType + "(" + mInterfaceName + ")");
+ }
if (mInterfaceName != null && hostAddress != -1) {
- if (DBG) {
- Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress));
- }
return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0;
} else {
return false;
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 418f511..54529ae 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -48,7 +48,7 @@
private boolean mDefaultRouteSet;
private boolean mTeardownRequested;
- private static boolean DBG = Config.LOGV;
+ private static boolean DBG = true;
private static final String TAG = "NetworkStateTracker";
public static final int EVENT_STATE_CHANGED = 1;
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index deaa3c3..a97b9e5 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -41,6 +41,7 @@
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.harmony.xnet.provider.jsse.SSLParameters;
/**
* SSLSocketFactory that provides optional (on debug devices, only) skipping of ssl certificfate
@@ -54,28 +55,6 @@
private static final String LOG_TAG = "SSLCertificateSocketFactory";
- private static X509TrustManager sDefaultTrustManager;
-
- static {
- try {
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
- tmf.init((KeyStore)null);
- TrustManager[] tms = tmf.getTrustManagers();
- if (tms != null) {
- for (TrustManager tm : tms) {
- if (tm instanceof X509TrustManager) {
- sDefaultTrustManager = (X509TrustManager)tm;
- break;
- }
- }
- }
- } catch (NoSuchAlgorithmException e) {
- Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
- } catch (KeyStoreException e) {
- Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
- }
- }
-
private static final TrustManager[] TRUST_MANAGER = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
@@ -155,20 +134,13 @@
private boolean hasValidCertificateChain(Certificate[] certs)
throws IOException {
- if (sDefaultTrustManager == null) {
- if (Config.LOGD) {
- Log.d(LOG_TAG,"hasValidCertificateChain():" +
- " null default trust manager!");
- }
- throw new IOException("null default trust manager");
- }
-
boolean trusted = (certs != null && (certs.length > 0));
if (trusted) {
try {
// the authtype we pass in doesn't actually matter
- sDefaultTrustManager.checkServerTrusted((X509Certificate[]) certs, "RSA");
+ SSLParameters.getDefaultTrustManager()
+ .checkServerTrusted((X509Certificate[]) certs, "RSA");
} catch (GeneralSecurityException e) {
String exceptionMessage = e != null ? e.getMessage() : "none";
if (Config.LOGD) {
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 91fa900..ed6b4c2 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,6 +16,8 @@
package android.net.http;
+import org.apache.harmony.xnet.provider.jsse.SSLParameters;
+
import java.io.IOException;
import java.security.cert.Certificate;
@@ -47,11 +49,6 @@
= new CertificateChainValidator();
/**
- * Default trust manager (used to perform CA certificate validation)
- */
- private X509TrustManager mDefaultTrustManager;
-
- /**
* @return The singleton instance of the certificator chain validator
*/
public static CertificateChainValidator getInstance() {
@@ -62,28 +59,7 @@
* Creates a new certificate chain validator. This is a pivate constructor.
* If you need a Certificate chain validator, call getInstance().
*/
- private CertificateChainValidator() {
- try {
- TrustManagerFactory trustManagerFactory
- = TrustManagerFactory.getInstance("X509");
- trustManagerFactory.init((KeyStore)null);
- TrustManager[] trustManagers =
- trustManagerFactory.getTrustManagers();
- if (trustManagers != null && trustManagers.length > 0) {
- for (TrustManager trustManager : trustManagers) {
- if (trustManager instanceof X509TrustManager) {
- mDefaultTrustManager = (X509TrustManager)(trustManager);
- break;
- }
- }
- }
- } catch (Exception exc) {
- if (HttpLog.LOGV) {
- HttpLog.v("CertificateChainValidator():" +
- " failed to initialize the trust manager");
- }
- }
- }
+ private CertificateChainValidator() {}
/**
* Performs the handshake and server certificates validation
@@ -156,7 +132,7 @@
// report back to the user.
//
try {
- mDefaultTrustManager.checkServerTrusted(
+ SSLParameters.getDefaultTrustManager().checkServerTrusted(
serverCertificates, "RSA");
// no errors!!!
@@ -186,7 +162,7 @@
// check if the last certificate in the chain (root) is trusted
X509Certificate[] rootCertificateChain = { currCertificate };
try {
- mDefaultTrustManager.checkServerTrusted(
+ SSLParameters.getDefaultTrustManager().checkServerTrusted(
rootCertificateChain, "RSA");
} catch (CertificateExpiredException e) {
String errorMessage = e.getMessage();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1775a4b..6c2a27a 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -70,6 +70,7 @@
*
* @deprecated Use {@link #SDK_INT} to easily get this as an integer.
*/
+ @Deprecated
public static final String SDK = getString("ro.build.version.sdk");
/**
@@ -132,6 +133,19 @@
* </ul>
*/
public static final int DONUT = 4;
+ /**
+ * Current work on "Eclair" development branch.
+ *
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li> The {@link android.app.Service#onStartCommand
+ * Service.onStartCommand} function will return the new
+ * {@link android.app.Service#START_STICKY} behavior instead of the
+ * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}.
+ * </ul>
+ */
+ public static final int ECLAIR = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/HandlerStateMachine.java b/core/java/android/os/HandlerStateMachine.java
index d004a25..9e7902b 100644
--- a/core/java/android/os/HandlerStateMachine.java
+++ b/core/java/android/os/HandlerStateMachine.java
@@ -56,22 +56,22 @@
}
class S1 extends HandlerState {
- @Override public void enter(Message message) {
+ &#064;Override public void enter(Message message) {
}
- @Override public void processMessage(Message message) {
+ &#064;Override public void processMessage(Message message) {
deferMessage(message);
if (message.what == TEST_WHAT_2) {
transitionTo(mS2);
}
}
- @Override public void exit(Message message) {
+ &#064;Override public void exit(Message message) {
}
}
class S2 extends HandlerState {
- @Override public void processMessage(Message message) {
+ &#064;Override public void processMessage(Message message) {
// Do some processing
if (message.what == TEST_WHAT_2) {
transtionTo(mS1);
diff --git a/core/java/android/pim/ContactsAsyncHelper.java b/core/java/android/pim/ContactsAsyncHelper.java
index a21281e..342d208 100644
--- a/core/java/android/pim/ContactsAsyncHelper.java
+++ b/core/java/android/pim/ContactsAsyncHelper.java
@@ -27,8 +27,7 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
+import android.provider.ContactsContract.Contacts;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -39,35 +38,35 @@
* Helper class for async access of images.
*/
public class ContactsAsyncHelper extends Handler {
-
+
private static final boolean DBG = false;
private static final String LOG_TAG = "ContactsAsyncHelper";
-
+
/**
* Interface for a WorkerHandler result return.
*/
public interface OnImageLoadCompleteListener {
/**
* Called when the image load is complete.
- *
+ *
* @param imagePresent true if an image was found
- */
+ */
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
boolean imagePresent);
}
-
+
// constants
private static final int EVENT_LOAD_IMAGE = 1;
private static final int DEFAULT_TOKEN = -1;
-
+
// static objects
private static Handler sThreadHandler;
private static ContactsAsyncHelper sInstance;
-
+
static {
sInstance = new ContactsAsyncHelper();
}
-
+
private static final class WorkerArgs {
public Context context;
public ImageView view;
@@ -78,12 +77,12 @@
public OnImageLoadCompleteListener listener;
public CallerInfo info;
}
-
+
/**
- * public inner class to help out the ContactsAsyncHelper callers
- * with tracking the state of the CallerInfo Queries and image
+ * public inner class to help out the ContactsAsyncHelper callers
+ * with tracking the state of the CallerInfo Queries and image
* loading.
- *
+ *
* Logic contained herein is used to remove the race conditions
* that exist as the CallerInfo queries run and mix with the image
* loads, which then mix with the Phone state changes.
@@ -94,11 +93,11 @@
public static final int DISPLAY_UNDEFINED = 0;
public static final int DISPLAY_IMAGE = -1;
public static final int DISPLAY_DEFAULT = -2;
-
+
// State of the image on the imageview.
private CallerInfo mCurrentCallerInfo;
private int displayMode;
-
+
public ImageTracker() {
mCurrentCallerInfo = null;
displayMode = DISPLAY_UNDEFINED;
@@ -107,17 +106,17 @@
/**
* Used to see if the requested call / connection has a
* different caller attached to it than the one we currently
- * have in the CallCard.
+ * have in the CallCard.
*/
public boolean isDifferentImageRequest(CallerInfo ci) {
// note, since the connections are around for the lifetime of the
- // call, and the CallerInfo-related items as well, we can
+ // call, and the CallerInfo-related items as well, we can
// definitely use a simple != comparison.
return (mCurrentCallerInfo != ci);
}
-
+
public boolean isDifferentImageRequest(Connection connection) {
- // if the connection does not exist, see if the
+ // if the connection does not exist, see if the
// mCurrentCallerInfo is also null to match.
if (connection == null) {
if (DBG) Log.d(LOG_TAG, "isDifferentImageRequest: connection is null");
@@ -133,57 +132,58 @@
}
return runQuery;
}
-
+
/**
- * Simple setter for the CallerInfo object.
+ * Simple setter for the CallerInfo object.
*/
public void setPhotoRequest(CallerInfo ci) {
- mCurrentCallerInfo = ci;
+ mCurrentCallerInfo = ci;
}
-
+
/**
- * Convenience method used to retrieve the URI
- * representing the Photo file recorded in the attached
- * CallerInfo Object.
+ * Convenience method used to retrieve the URI
+ * representing the Photo file recorded in the attached
+ * CallerInfo Object.
*/
public Uri getPhotoUri() {
if (mCurrentCallerInfo != null) {
- return ContentUris.withAppendedId(People.CONTENT_URI,
+ return ContentUris.withAppendedId(Contacts.CONTENT_URI,
mCurrentCallerInfo.person_id);
}
- return null;
+ return null;
}
-
+
/**
- * Simple setter for the Photo state.
+ * Simple setter for the Photo state.
*/
public void setPhotoState(int state) {
displayMode = state;
}
-
+
/**
- * Simple getter for the Photo state.
+ * Simple getter for the Photo state.
*/
public int getPhotoState() {
return displayMode;
}
}
-
+
/**
- * Thread worker class that handles the task of opening the stream and loading
+ * Thread worker class that handles the task of opening the stream and loading
* the images.
*/
private class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
-
+
+ @Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
-
+
switch (msg.arg1) {
case EVENT_LOAD_IMAGE:
- InputStream inputStream = Contacts.People.openContactPhotoInputStream(
+ InputStream inputStream = Contacts.openContactPhotoInputStream(
args.context.getContentResolver(), args.uri);
if (inputStream != null) {
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
@@ -192,22 +192,22 @@
" token: " + msg.what + " image URI: " + args.uri);
} else {
args.result = null;
- if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
- " token: " + msg.what + " image URI: " + args.uri +
+ if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
+ " token: " + msg.what + " image URI: " + args.uri +
", using default image.");
}
break;
default:
}
-
- // send the reply to the enclosing class.
+
+ // send the reply to the enclosing class.
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
reply.arg1 = msg.arg1;
reply.obj = msg.obj;
reply.sendToTarget();
}
}
-
+
/**
* Private constructor for static class
*/
@@ -216,14 +216,14 @@
thread.start();
sThreadHandler = new WorkerHandler(thread.getLooper());
}
-
+
/**
* Convenience method for calls that do not want to deal with listeners and tokens.
*/
- public static final void updateImageViewWithContactPhotoAsync(Context context,
+ public static final void updateImageViewWithContactPhotoAsync(Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
// Added additional Cookie field in the callee.
- updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
+ updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
imageView, person, placeholderImageResource);
}
@@ -231,24 +231,24 @@
* Convenience method for calls that do not want to deal with listeners and tokens, but have
* a CallerInfo object to cache the image to.
*/
- public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
+ public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
// Added additional Cookie field in the callee.
- updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
+ updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
imageView, person, placeholderImageResource);
}
-
+
/**
* Start an image load, attach the result to the specified CallerInfo object.
* Note, when the query is started, we make the ImageView INVISIBLE if the
* placeholderImageResource value is -1. When we're given a valid (!= -1)
* placeholderImageResource value, we make sure the image is visible.
*/
- public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
- OnImageLoadCompleteListener listener, Object cookie, Context context,
+ public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
+ OnImageLoadCompleteListener listener, Object cookie, Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
-
+
// in case the source caller info is null, the URI will be null as well.
// just update using the placeholder image in this case.
if (person == null) {
@@ -257,10 +257,10 @@
imageView.setImageResource(placeholderImageResource);
return;
}
-
+
// Added additional Cookie field in the callee to handle arguments
// sent to the callback function.
-
+
// setup arguments
WorkerArgs args = new WorkerArgs();
args.cookie = cookie;
@@ -270,15 +270,15 @@
args.defaultResource = placeholderImageResource;
args.listener = listener;
args.info = info;
-
+
// setup message arguments
Message msg = sThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_LOAD_IMAGE;
msg.obj = args;
-
- if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
+
+ if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
", displaying default image for now.");
-
+
// set the default image first, when the query is complete, we will
// replace the image with the correct one.
if (placeholderImageResource != -1) {
@@ -287,11 +287,11 @@
} else {
imageView.setVisibility(View.INVISIBLE);
}
-
+
// notify the thread to begin working
sThreadHandler.sendMessage(msg);
}
-
+
/**
* Called when loading is done.
*/
@@ -316,21 +316,21 @@
args.view.setVisibility(View.VISIBLE);
args.view.setImageResource(args.defaultResource);
}
-
+
// Note that the data is cached.
if (args.info != null) {
args.info.isCachedPhotoCurrent = true;
}
-
+
// notify the listener if it is there.
if (args.listener != null) {
- if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
+ if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
" image: " + args.uri + " completed");
args.listener.onImageLoadComplete(msg.what, args.cookie, args.view,
imagePresent);
}
break;
- default:
+ default:
}
}
}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index 7920543..bd7924a 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -410,10 +410,14 @@
Time end = new Time(endTzid);
end.parse(dtendProperty.getValue());
- long durationMillis = end.toMillis(false /* use isDst */)
+ long durationMillis = end.toMillis(false /* use isDst */)
- start.toMillis(false /* use isDst */);
long durationSeconds = (durationMillis / 1000);
- return "P" + durationSeconds + "S";
+ if (start.allDay && (durationSeconds % 86400) == 0) {
+ return "P" + (durationSeconds / 86400) + "D"; // Server wants this instead of P86400S
+ } else {
+ return "P" + durationSeconds + "S";
+ }
}
private static String flattenProperties(ICalendar.Component component,
diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java
new file mode 100644
index 0000000..ca41ce5
--- /dev/null
+++ b/core/java/android/pim/vcard/Constants.java
@@ -0,0 +1,94 @@
+/*
+ * 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.pim.vcard;
+
+/**
+ * Constants used in both composer and parser.
+ */
+/* package */ class Constants {
+
+ public static final String ATTR_TYPE = "TYPE";
+
+ public static final String VERSION_V21 = "2.1";
+ public static final String VERSION_V30 = "3.0";
+
+ // Properties both the current (as of 2009-08-17) ContactsStruct and de-fact vCard extensions
+ // shown in http://en.wikipedia.org/wiki/VCard support are defined here.
+ public static final String PROPERTY_X_AIM = "X-AIM";
+ public static final String PROPERTY_X_MSN = "X-MSN";
+ public static final String PROPERTY_X_YAHOO = "X-YAHOO";
+ public static final String PROPERTY_X_ICQ = "X-ICQ";
+ public static final String PROPERTY_X_JABBER = "X-JABBER";
+ public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
+ public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
+ // Phone number for Skype, available as usual phone.
+ public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
+ // Some device emits this "X-" attribute, which is specifically invalid but should be
+ // always properly accepted, and emitted in some special case (for that device/application).
+ public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
+
+ // How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0
+ //
+ // e.g.
+ // 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."
+ // 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."
+ // 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."
+ //
+ // 2) has been the default of VCard exporter/importer in Android, but we can see the other
+ // formats in vCard data emitted by the other softwares/devices.
+ //
+ // So we are currently not sure which type is the best; probably we will have to change which
+ // type should be emitted depending on the device.
+ public static final String ATTR_TYPE_HOME = "HOME";
+ public static final String ATTR_TYPE_WORK = "WORK";
+ public static final String ATTR_TYPE_FAX = "FAX";
+ public static final String ATTR_TYPE_CELL = "CELL";
+ public static final String ATTR_TYPE_VOICE = "VOICE";
+ public static final String ATTR_TYPE_INTERNET = "INTERNET";
+
+ public static final String ATTR_TYPE_PREF = "PREF";
+
+ // Phone types valid in vCard and known to ContactsContract, but not so common.
+ public static final String ATTR_TYPE_CAR = "CAR";
+ public static final String ATTR_TYPE_ISDN = "ISDN";
+ public static final String ATTR_TYPE_PAGER = "PAGER";
+
+ // Phone types existing in vCard 2.1 but not known to ContactsContract.
+ // TODO: should make parser make these TYPE_CUSTOM.
+ public static final String ATTR_TYPE_MODEM = "MODEM";
+ public static final String ATTR_TYPE_MSG = "MSG";
+ public static final String ATTR_TYPE_BBS = "BBS";
+ public static final String ATTR_TYPE_VIDEO = "VIDEO";
+
+ // Phone types existing in the current Contacts structure but not valid in vCard (at least 2.1)
+ // These types are encoded to "X-" attributes when composing vCard for now.
+ // Parser passes these even if "X-" is added to the attribute.
+ public static final String ATTR_TYPE_PHONE_EXTRA_OTHER = "OTHER";
+ public static final String ATTR_TYPE_PHONE_EXTRA_CALLBACK = "CALLBACK";
+ // TODO: may be "TYPE=COMPANY,PREF", not "COMPANY-MAIN".
+ public static final String ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN = "COMPANY-MAIN";
+ public static final String ATTR_TYPE_PHONE_EXTRA_RADIO = "RADIO";
+ public static final String ATTR_TYPE_PHONE_EXTRA_TELEX = "TELEX";
+ public static final String ATTR_TYPE_PHONE_EXTRA_TTY_TDD = "TTY-TDD";
+ public static final String ATTR_TYPE_PHONE_EXTRA_ASSISTANT = "ASSISTANT";
+
+ // DoCoMo specific attribute. Used with "SOUND" property, which is alternate of SORT-STRING in
+ // vCard 3.0.
+ public static final String ATTR_TYPE_X_IRMC_N = "X-IRMC-N";
+
+ private Constants() {
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index 46725d3..8e8d46a 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -15,38 +15,58 @@
*/
package android.pim.vcard;
-import android.content.AbstractSyncableContentProvider;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
-import android.content.ContentUris;
import android.content.ContentValues;
-import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Extensions;
-import android.provider.Contacts.GroupMembership;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.provider.Contacts.Photos;
+import android.content.OperationApplicationException;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Miscellaneous;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
-import java.util.Map.Entry;
/**
* This class bridges between data structure of Contact app and VCard data.
*/
public class ContactStruct {
- private static final String LOG_TAG = "ContactStruct";
+ private static final String LOG_TAG = "vcard.ContactStruct";
+
+ // Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ"
+ // Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
+ private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
+
+ static {
+ sImMap.put(Constants.PROPERTY_X_AIM, Im.PROTOCOL_AIM);
+ sImMap.put(Constants.PROPERTY_X_MSN, Im.PROTOCOL_MSN);
+ sImMap.put(Constants.PROPERTY_X_YAHOO, Im.PROTOCOL_YAHOO);
+ sImMap.put(Constants.PROPERTY_X_ICQ, Im.PROTOCOL_ICQ);
+ sImMap.put(Constants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER);
+ sImMap.put(Constants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE);
+ sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK);
+ sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK_WITH_SPACE, Im.PROTOCOL_GOOGLE_TALK);
+ }
/**
* @hide only for testing
@@ -85,11 +105,7 @@
/**
* @hide only for testing
*/
- static public class ContactMethod {
- // Contacts.KIND_EMAIL, Contacts.KIND_POSTAL
- public final int kind;
- // e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME
- // If type == Contacts.PhoneColumns.TYPE_CUSTOM, label is used.
+ static public class EmailData {
public final int type;
public final String data;
// Used only when TYPE is TYPE_CUSTOM.
@@ -97,35 +113,143 @@
// isPrimary is changable only when there's no appropriate one existing in
// the original VCard.
public boolean isPrimary;
- public ContactMethod(int kind, int type, String data, String label,
- boolean isPrimary) {
- this.kind = kind;
+ public EmailData(int type, String data, String label, boolean isPrimary) {
this.type = type;
this.data = data;
- this.label = data;
+ this.label = label;
this.isPrimary = isPrimary;
}
@Override
public boolean equals(Object obj) {
- if (obj instanceof ContactMethod) {
+ if (obj instanceof EmailData) {
return false;
}
- ContactMethod contactMethod = (ContactMethod)obj;
- return (kind == contactMethod.kind && type == contactMethod.type &&
- data.equals(contactMethod.data) && label.equals(contactMethod.label) &&
- isPrimary == contactMethod.isPrimary);
+ EmailData emailData = (EmailData)obj;
+ return (type == emailData.type && data.equals(emailData.data) &&
+ label.equals(emailData.label) && isPrimary == emailData.isPrimary);
}
@Override
public String toString() {
- return String.format("kind: %d, type: %d, data: %s, label: %s, isPrimary: %s",
- kind, type, data, label, isPrimary);
+ return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
+ type, data, label, isPrimary);
+ }
+ }
+
+ static public class PostalData {
+ // Determined by vCard spec.
+ // PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
+ public static final int ADDR_MAX_DATA_SIZE = 7;
+ private final String[] dataArray;
+ public final String pobox;
+ public final String extendedAddress;
+ public final String street;
+ public final String localty;
+ public final String region;
+ public final String postalCode;
+ public final String country;
+
+ public final int type;
+
+ // Used only when type variable is TYPE_CUSTOM.
+ public final String label;
+
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public PostalData(int type, List<String> propValueList,
+ String label, boolean isPrimary) {
+ this.type = type;
+ dataArray = new String[ADDR_MAX_DATA_SIZE];
+
+ int size = propValueList.size();
+ if (size > ADDR_MAX_DATA_SIZE) {
+ size = ADDR_MAX_DATA_SIZE;
+ }
+
+ // adr-value = 0*6(text-value ";") text-value
+ // ; PO Box, Extended Address, Street, Locality, Region, Postal
+ // ; Code, Country Name
+ //
+ // Use Iterator assuming List may be LinkedList, though actually it is
+ // always ArrayList in the current implementation.
+ int i = 0;
+ for (String addressElement : propValueList) {
+ dataArray[i] = addressElement;
+ if (++i >= size) {
+ break;
+ }
+ }
+ while (i < ADDR_MAX_DATA_SIZE) {
+ dataArray[i++] = null;
+ }
+
+ this.pobox = dataArray[0];
+ this.extendedAddress = dataArray[1];
+ this.street = dataArray[2];
+ this.localty = dataArray[3];
+ this.region = dataArray[4];
+ this.postalCode = dataArray[5];
+ this.country = dataArray[6];
+
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PostalData) {
+ return false;
+ }
+ PostalData postalData = (PostalData)obj;
+ return (Arrays.equals(dataArray, postalData.dataArray) &&
+ (type == postalData.type &&
+ (type == StructuredPostal.TYPE_CUSTOM ?
+ (label == postalData.label) : true)) &&
+ (isPrimary == postalData.isPrimary));
+ }
+
+ public String getFormattedAddress(int vcardType) {
+ StringBuilder builder = new StringBuilder();
+ boolean empty = true;
+ if (VCardConfig.isJapaneseDevice(vcardType)) {
+ // In Japan, the order is reversed.
+ for (int i = ADDR_MAX_DATA_SIZE - 1; i >= 0; i--) {
+ String addressPart = dataArray[i];
+ if (!TextUtils.isEmpty(addressPart)) {
+ if (!empty) {
+ builder.append(' ');
+ }
+ builder.append(addressPart);
+ empty = false;
+ }
+ }
+ } else {
+ for (int i = 0; i < ADDR_MAX_DATA_SIZE; i++) {
+ String addressPart = dataArray[i];
+ if (!TextUtils.isEmpty(addressPart)) {
+ if (!empty) {
+ builder.append(' ');
+ }
+ builder.append(addressPart);
+ empty = false;
+ }
+ }
+ }
+
+ return builder.toString().trim();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, label: %s, isPrimary: %s",
+ type, label, isPrimary);
}
}
/**
- * @hide only for testing
+ * @hide only for testing.
*/
static public class OrganizationData {
public final int type;
@@ -161,7 +285,54 @@
}
}
- static class Property {
+ static public class ImData {
+ public final int type;
+ public final String data;
+ public final String label;
+ public final boolean isPrimary;
+
+ // TODO: ContactsConstant#PROTOCOL, ContactsConstant#CUSTOM_PROTOCOL should be used?
+ public ImData(int type, String data, String label, boolean isPrimary) {
+ this.type = type;
+ this.data = data;
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ImData) {
+ return false;
+ }
+ ImData imData = (ImData)obj;
+ return (type == imData.type && data.equals(imData.data) &&
+ label.equals(imData.label) && isPrimary == imData.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
+ type, data, label, isPrimary);
+ }
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ static public class PhotoData {
+ public static final String FORMAT_FLASH = "SWF";
+ public final int type;
+ public final String formatName; // used when type is not defined in ContactsContract.
+ public final byte[] photoBytes;
+
+ public PhotoData(int type, String formatName, byte[] photoBytes) {
+ this.type = type;
+ this.formatName = formatName;
+ this.photoBytes = photoBytes;
+ }
+ }
+
+ static /* package */ class Property {
private String mPropertyName;
private Map<String, Collection<String>> mParameterMap =
new HashMap<String, Collection<String>>();
@@ -178,7 +349,7 @@
public void addParameter(final String paramName, final String paramValue) {
Collection<String> values;
- if (mParameterMap.containsKey(paramName)) {
+ if (!mParameterMap.containsKey(paramName)) {
if (paramName.equals("TYPE")) {
values = new HashSet<String>();
} else {
@@ -188,6 +359,7 @@
} else {
values = mParameterMap.get(paramName);
}
+ values.add(paramValue);
}
public void addToPropertyValueList(final String propertyValue) {
@@ -213,124 +385,130 @@
}
}
- private String mName;
- private String mPhoneticName;
- // private String mPhotoType;
- private byte[] mPhotoBytes;
- private List<String> mNotes;
+ private String mFamilyName;
+ private String mGivenName;
+ private String mMiddleName;
+ private String mPrefix;
+ private String mSuffix;
+
+ // Used only when no family nor given name is found.
+ private String mFullName;
+
+ private String mPhoneticFamilyName;
+ private String mPhoneticGivenName;
+ private String mPhoneticMiddleName;
+
+ private String mPhoneticFullName;
+
+ private List<String> mNickNameList;
+
+ private String mDisplayName;
+
+ private String mBirthday;
+
+ private List<String> mNoteList;
private List<PhoneData> mPhoneList;
- private List<ContactMethod> mContactMethodList;
+ private List<EmailData> mEmailList;
+ private List<PostalData> mPostalList;
private List<OrganizationData> mOrganizationList;
- private Map<String, List<String>> mExtensionMap;
-
- private int mNameOrderType;
+ private List<ImData> mImList;
+ private List<PhotoData> mPhotoList;
+ private List<String> mWebsiteList;
- /* private variables bellow is for temporary use. */
-
- // For name, there are three fields in vCard: FN, N, NAME.
- // We prefer FN, which is a required field in vCard 3.0 , but not in vCard 2.1.
- // Next, we prefer NAME, which is defined only in vCard 3.0.
- // Finally, we use N, which is a little difficult to parse.
- private String mTmpFullName;
- private String mTmpNameFromNProperty;
-
- // Some vCard has "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", and
- // "X-PHONETIC-LAST-NAME"
- private String mTmpXPhoneticFirstName;
- private String mTmpXPhoneticMiddleName;
- private String mTmpXPhoneticLastName;
+ private final int mVCardType;
// Each Column of four properties has ISPRIMARY field
// (See android.provider.Contacts)
- // If false even after the following loop, we choose the first
- // entry as a "primary" entry.
+ // If false even after the parsing loop, we choose the first entry as a "primary"
+ // entry.
private boolean mPrefIsSet_Address;
private boolean mPrefIsSet_Phone;
private boolean mPrefIsSet_Email;
private boolean mPrefIsSet_Organization;
public ContactStruct() {
- mNameOrderType = VCardConfig.NAME_ORDER_TYPE_DEFAULT;
+ this(VCardConfig.VCARD_TYPE_V21_GENERIC);
}
- public ContactStruct(int nameOrderType) {
- mNameOrderType = nameOrderType;
- }
-
- /**
- * @hide only for test
- */
- public ContactStruct(String name,
- String phoneticName,
- byte[] photoBytes,
- List<String> notes,
- List<PhoneData> phoneList,
- List<ContactMethod> contactMethodList,
- List<OrganizationData> organizationList,
- Map<String, List<String>> extensionMap) {
- mName = name;
- mPhoneticName = phoneticName;
- mPhotoBytes = photoBytes;
- mContactMethodList = contactMethodList;
- mOrganizationList = organizationList;
- mExtensionMap = extensionMap;
- }
-
- /**
- * @hide only for test
- */
- public String getName() {
- return mName;
- }
-
- /**
- * @hide only for test
- */
- public String getPhoneticName() {
- return mPhoneticName;
+ public ContactStruct(int vcardType) {
+ mVCardType = vcardType;
}
/**
- * @hide only for test
+ * @hide only for testing.
*/
- public final byte[] getPhotoBytes() {
- return mPhotoBytes;
+ public ContactStruct(String givenName,
+ String familyName,
+ String middleName,
+ String prefix,
+ String suffix,
+ String phoneticGivenName,
+ String pheneticFamilyName,
+ String phoneticMiddleName,
+ List<byte[]> photoBytesList,
+ List<String> notes,
+ List<PhoneData> phoneList,
+ List<EmailData> emailList,
+ List<PostalData> postalList,
+ List<OrganizationData> organizationList,
+ List<PhotoData> photoList,
+ List<String> websiteList) {
+ this(VCardConfig.VCARD_TYPE_DEFAULT);
+ mGivenName = givenName;
+ mFamilyName = familyName;
+ mPrefix = prefix;
+ mSuffix = suffix;
+ mPhoneticGivenName = givenName;
+ mPhoneticFamilyName = familyName;
+ mPhoneticMiddleName = middleName;
+ mEmailList = emailList;
+ mPostalList = postalList;
+ mOrganizationList = organizationList;
+ mPhotoList = photoList;
+ mWebsiteList = websiteList;
}
/**
- * @hide only for test
+ * @hide only for testing.
+ */
+ public final List<PhotoData> getPhotoList() {
+ return mPhotoList;
+ }
+
+ /**
+ * @hide only for testing.
*/
public final List<String> getNotes() {
- return mNotes;
+ return mNoteList;
}
/**
- * @hide only for test
+ * @hide only for testing.
*/
public final List<PhoneData> getPhoneList() {
return mPhoneList;
}
/**
- * @hide only for test
+ * @hide only for testing.
*/
- public final List<ContactMethod> getContactMethodList() {
- return mContactMethodList;
+ public final List<EmailData> getEmailList() {
+ return mEmailList;
}
/**
- * @hide only for test
+ * @hide only for testing.
+ */
+ public final List<PostalData> getPostalList() {
+ return mPostalList;
+ }
+
+ /**
+ * @hide only for testing.
*/
public final List<OrganizationData> getOrganizationList() {
return mOrganizationList;
}
-
- /**
- * @hide only for test
- */
- public final Map<String, List<String>> getExtensionMap() {
- return mExtensionMap;
- }
/**
* Add a phone info to phoneList.
@@ -359,32 +537,55 @@
mPhoneList.add(phoneData);
}
- /**
- * Add a contactmethod info to contactmethodList.
- * @param kind integer value defined in Contacts.java
- * (e.g. Contacts.KIND_EMAIL)
- * @param type type col of content://contacts/contact_methods
- * @param data contact data
- * @param label extra string used only when kind is Contacts.KIND_CUSTOM.
- */
- private void addContactmethod(int kind, int type, String data,
- String label, boolean isPrimary){
- if (mContactMethodList == null) {
- mContactMethodList = new ArrayList<ContactMethod>();
+ private void addNickName(final String nickName) {
+ if (mNickNameList == null) {
+ mNickNameList = new ArrayList<String>();
}
- mContactMethodList.add(new ContactMethod(kind, type, data, label, isPrimary));
+ mNickNameList.add(nickName);
}
- /**
- * Add a Organization info to organizationList.
- */
- private void addOrganization(int type, String companyName, String positionName,
- boolean isPrimary) {
+ private void addEmail(int type, String data, String label, boolean isPrimary){
+ if (mEmailList == null) {
+ mEmailList = new ArrayList<EmailData>();
+ }
+ mEmailList.add(new EmailData(type, data, label, isPrimary));
+ }
+
+ private void addPostal(int type, List<String> propValueList, String label, boolean isPrimary){
+ if (mPostalList == null) {
+ mPostalList = new ArrayList<PostalData>();
+ }
+ mPostalList.add(new PostalData(type, propValueList, label, isPrimary));
+ }
+
+ private void addOrganization(int type, final String companyName,
+ final String positionName, boolean isPrimary) {
if (mOrganizationList == null) {
mOrganizationList = new ArrayList<OrganizationData>();
}
mOrganizationList.add(new OrganizationData(type, companyName, positionName, isPrimary));
}
+
+ private void addIm(int type, String data, String label, boolean isPrimary) {
+ if (mImList == null) {
+ mImList = new ArrayList<ImData>();
+ }
+ mImList.add(new ImData(type, data, label, isPrimary));
+ }
+
+ private void addNote(final String note) {
+ if (mNoteList == null) {
+ mNoteList = new ArrayList<String>(1);
+ }
+ mNoteList.add(note);
+ }
+
+ private void addPhotoBytes(String formatName, byte[] photoBytes) {
+ if (mPhotoList == null) {
+ mPhotoList = new ArrayList<PhotoData>(1);
+ }
+ final PhotoData photoData = new PhotoData(0, null, photoBytes);
+ }
/**
* Set "position" value to the appropriate data. If there's more than one
@@ -407,148 +608,66 @@
}
int size = mOrganizationList.size();
if (size == 0) {
- addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false);
+ addOrganization(ContactsContract.CommonDataKinds.Organization.TYPE_OTHER,
+ "", null, false);
size = 1;
}
OrganizationData lastData = mOrganizationList.get(size - 1);
lastData.positionName = positionValue;
}
- private void addExtension(String propName, Map<String, Collection<String>> paramMap,
- List<String> propValueList) {
- if (propValueList.size() == 0) {
+ @SuppressWarnings("fallthrough")
+ private void handleNProperty(List<String> elems) {
+ // Family, Given, Middle, Prefix, Suffix. (1 - 5)
+ int size;
+ if (elems == null || (size = elems.size()) < 1) {
return;
}
- // Now store the string into extensionMap.
- List<String> list;
- if (mExtensionMap == null) {
- mExtensionMap = new HashMap<String, List<String>>();
- }
- if (!mExtensionMap.containsKey(propName)){
- list = new ArrayList<String>();
- mExtensionMap.put(propName, list);
- } else {
- list = mExtensionMap.get(propName);
- }
-
- list.add(encodeProperty(propName, paramMap, propValueList));
- }
-
- private String encodeProperty(String propName, Map<String, Collection<String>> paramMap,
- List<String> propValueList) {
- // PropertyNode#toString() is for reading, not for parsing in the future.
- // We construct appropriate String here.
- StringBuilder builder = new StringBuilder();
- if (propName.length() > 0) {
- builder.append("propName:[");
- builder.append(propName);
- builder.append("],");
+ if (size > 5) {
+ size = 5;
}
- if (paramMap.size() > 0) {
- builder.append("paramMap:[");
- int size = paramMap.size();
- int i = 0;
- for (Map.Entry<String, Collection<String>> entry : paramMap.entrySet()) {
- String key = entry.getKey();
- for (String value : entry.getValue()) {
- // Assuming param-key does not contain NON-ASCII nor symbols.
- // TODO: check it.
- //
- // According to vCard 3.0:
- // param-name = iana-token / x-name
- builder.append(key);
-
- // param-value may contain any value including NON-ASCIIs.
- // We use the following replacing rule.
- // \ -> \\
- // , -> \,
- // In String#replaceAll(), "\\\\" means a single backslash.
- builder.append("=");
-
- // TODO: fix this.
- builder.append(value.replaceAll("\\\\", "\\\\\\\\").replaceAll(",", "\\\\,"));
- if (i < size -1) {
- builder.append(",");
- }
- i++;
- }
- }
-
- builder.append("],");
+ switch (size) {
+ // fallthrough
+ case 5:
+ mSuffix = elems.get(4);
+ case 4:
+ mPrefix = elems.get(3);
+ case 3:
+ mMiddleName = elems.get(2);
+ case 2:
+ mGivenName = elems.get(1);
+ default:
+ mFamilyName = elems.get(0);
}
-
- int size = propValueList.size();
- if (size > 0) {
- builder.append("propValue:[");
- List<String> list = propValueList;
- for (int i = 0; i < size; i++) {
- // TODO: fix this.
- builder.append(list.get(i).replaceAll("\\\\", "\\\\\\\\").replaceAll(",", "\\\\,"));
- if (i < size -1) {
- builder.append(",");
- }
- }
- builder.append("],");
- }
-
- return builder.toString();
}
- private static String getNameFromNProperty(List<String> elems, int nameOrderType) {
- // Family, Given, Middle, Prefix, Suffix. (1 - 5)
- int size = elems.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- boolean builderIsEmpty = true;
- // Prefix
- if (size > 3 && elems.get(3).length() > 0) {
- builder.append(elems.get(3));
- builderIsEmpty = false;
- }
- String first, second;
- if (nameOrderType == VCardConfig.NAME_ORDER_TYPE_JAPANESE) {
- first = elems.get(0);
- second = elems.get(1);
- } else {
- first = elems.get(1);
- second = elems.get(0);
- }
- if (first.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(first);
- builderIsEmpty = false;
- }
- // Middle name
- if (size > 2 && elems.get(2).length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(elems.get(2));
- builderIsEmpty = false;
- }
- if (second.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(second);
- builderIsEmpty = false;
- }
- // Suffix
- if (size > 4 && elems.get(4).length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(elems.get(4));
- builderIsEmpty = false;
- }
- return builder.toString();
- } else if (size == 1) {
- return elems.get(0);
- } else {
- return "";
+ /**
+ * Some Japanese mobile phones use this field for phonetic name,
+ * since vCard 2.1 does not have "SORT-STRING" type.
+ * Also, in some cases, the field has some ';'s in it.
+ * Assume the ';' means the same meaning in N property
+ */
+ @SuppressWarnings("fallthrough")
+ private void handlePhoneticNameFromSound(List<String> elems) {
+ // Family, Given, Middle. (1-3)
+ // This is not from specification but mere assumption. Some Japanese phones use this order.
+ int size;
+ if (elems == null || (size = elems.size()) < 1) {
+ return;
+ }
+ if (size > 3) {
+ size = 3;
+ }
+
+ switch (size) {
+ // fallthrough
+ case 3:
+ mPhoneticMiddleName = elems.get(2);
+ case 2:
+ mPhoneticGivenName = elems.get(1);
+ default:
+ mPhoneticFamilyName = elems.get(0);
}
}
@@ -561,41 +680,27 @@
if (propValueList.size() == 0) {
return;
}
-
- String propValue = listToString(propValueList);
-
+ final String propValue = listToString(propValueList).trim();
+
if (propName.equals("VERSION")) {
// vCard version. Ignore this.
} else if (propName.equals("FN")) {
- mTmpFullName = propValue;
- } else if (propName.equals("NAME") && mTmpFullName == null) {
- // Only in vCard 3.0. Use this if FN does not exist.
- // Though, note that vCard 3.0 requires FN.
- mTmpFullName = propValue;
+ mFullName = propValue;
+ } else if (propName.equals("NAME") && mFullName == null) {
+ // Only in vCard 3.0. Use this if FN, which must exist in vCard 3.0 but may not
+ // actually exist in the real vCard data, does not exist.
+ mFullName = propValue;
} else if (propName.equals("N")) {
- mTmpNameFromNProperty = getNameFromNProperty(propValueList, mNameOrderType);
+ handleNProperty(propValueList);
} else if (propName.equals("SORT-STRING")) {
- mPhoneticName = propValue;
+ mPhoneticFullName = propValue;
+ } else if (propName.equals("NICKNAME") || propName.equals("X-NICKNAME")) {
+ addNickName(propValue);
} else if (propName.equals("SOUND")) {
- if ("X-IRMC-N".equals(paramMap.get("TYPE")) && mPhoneticName == null) {
- // Some Japanese mobile phones use this field for phonetic name,
- // since vCard 2.1 does not have "SORT-STRING" type.
- // Also, in some cases, the field has some ';'s in it.
- // We remove them.
- StringBuilder builder = new StringBuilder();
- String value = propValue;
- int length = value.length();
- for (int i = 0; i < length; i++) {
- char ch = value.charAt(i);
- if (ch != ';') {
- builder.append(ch);
- }
- }
- if (builder.length() > 0) {
- mPhoneticName = builder.toString();
- }
+ if (Constants.ATTR_TYPE_X_IRMC_N.equals(paramMap.get(Constants.ATTR_TYPE))) {
+ handlePhoneticNameFromSound(propValueList);
} else {
- addExtension(propName, paramMap, propValueList);
+ // Ignore this field since Android cannot understand what it is.
}
} else if (propName.equals("ADR")) {
boolean valuesAreAllEmpty = true;
@@ -609,108 +714,103 @@
return;
}
- int kind = Contacts.KIND_POSTAL;
int type = -1;
String label = "";
boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get("TYPE");
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
if (typeCollection != null) {
for (String typeString : typeCollection) {
- if (typeString.equals("PREF") && !mPrefIsSet_Address) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Address) {
// Only first "PREF" is considered.
mPrefIsSet_Address = true;
isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
+ } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) {
+ type = StructuredPostal.TYPE_HOME;
label = "";
- } else if (typeString.equalsIgnoreCase("WORK") ||
+ } else if (typeString.equals(Constants.ATTR_TYPE_WORK) ||
typeString.equalsIgnoreCase("COMPANY")) {
// "COMPANY" seems emitted by Windows Mobile, which is not
// specifically supported by vCard 2.1. We assume this is same
// as "WORK".
- type = Contacts.ContactMethodsColumns.TYPE_WORK;
+ type = StructuredPostal.TYPE_WORK;
label = "";
- } else if (typeString.equalsIgnoreCase("POSTAL")) {
- kind = Contacts.KIND_POSTAL;
- } else if (typeString.equalsIgnoreCase("PARCEL") ||
- typeString.equalsIgnoreCase("DOM") ||
- typeString.equalsIgnoreCase("INTL")) {
- // We do not have a kind or type matching these.
- // TODO: fix this. We may need to split entries into two.
- // (e.g. entries for KIND_POSTAL and KIND_PERCEL)
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0) {
+ } else if (typeString.equals("PARCEL") ||
+ typeString.equals("DOM") ||
+ typeString.equals("INTL")) {
+ // We do not have any appropriate way to store this information.
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
// vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
// emit non-standard types. We do not handle their values now.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
+ type = StructuredPostal.TYPE_CUSTOM;
label = typeString;
}
}
}
// We use "HOME" as default
if (type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
+ type = StructuredPostal.TYPE_HOME;
}
-
- // adr-value = 0*6(text-value ";") text-value
- // ; PO Box, Extended Address, Street, Locality, Region, Postal
- // ; Code, Country Name
- String address;
- int size = propValueList.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- boolean builderIsEmpty = true;
- if (Locale.getDefault().getCountry().equals(Locale.JAPAN.getCountry())) {
- // In Japan, the order is reversed.
- for (int i = size - 1; i >= 0; i--) {
- String addressPart = propValueList.get(i);
- if (addressPart.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(addressPart);
- builderIsEmpty = false;
- }
- }
- } else {
- for (int i = 0; i < size; i++) {
- String addressPart = propValueList.get(i);
- if (addressPart.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(addressPart);
- builderIsEmpty = false;
- }
- }
- }
- address = builder.toString().trim();
- } else {
- address = propValue;
- }
- addContactmethod(kind, type, address, label, isPrimary);
- } else if (propName.equals("ORG")) {
- // vCard specification does not specify other types.
- int type = Contacts.OrganizationColumns.TYPE_WORK;
+
+ addPostal(type, propValueList, label, isPrimary);
+ } else if (propName.equals("EMAIL")) {
+ int type = -1;
+ String label = null;
boolean isPrimary = false;
-
- Collection<String> typeCollection = paramMap.get("TYPE");
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
if (typeCollection != null) {
for (String typeString : typeCollection) {
- if (typeString.equals("PREF") && !mPrefIsSet_Organization) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Email) {
+ // Only first "PREF" is considered.
+ mPrefIsSet_Email = true;
+ isPrimary = true;
+ } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) {
+ type = Email.TYPE_HOME;
+ } else if (typeString.equals(Constants.ATTR_TYPE_WORK)) {
+ type = Email.TYPE_WORK;
+ } else if (typeString.equals(Constants.ATTR_TYPE_CELL)) {
+ // We do not have TYPE_MOBILE yet.
+ // TODO: modify this code when TYPE_MOBILE is supported.
+ type = Email.TYPE_CUSTOM;
+ label =
+ android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME;
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
+ // vCard 3.0 allows iana-token.
+ // We may have INTERNET (specified in vCard spec),
+ // SCHOOL, etc.
+ type = Email.TYPE_CUSTOM;
+ label = typeString;
+ }
+ }
+ }
+ if (type < 0) {
+ type = Email.TYPE_OTHER;
+ }
+ addEmail(type, propValue, label, isPrimary);
+ } else if (propName.equals("ORG")) {
+ // vCard specification does not specify other types.
+ int type = Organization.TYPE_WORK;
+ boolean isPrimary = false;
+
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Organization) {
// vCard specification officially does not have PREF in ORG.
// This is just for safety.
mPrefIsSet_Organization = true;
isPrimary = true;
}
- // XXX: Should we cope with X- words?
}
}
- int size = propValueList.size();
StringBuilder builder = new StringBuilder();
for (Iterator<String> iter = propValueList.iterator(); iter.hasNext();) {
builder.append(iter.next());
@@ -718,250 +818,190 @@
builder.append(' ');
}
}
-
addOrganization(type, builder.toString(), "", isPrimary);
} else if (propName.equals("TITLE")) {
setPosition(propValue);
} else if (propName.equals("ROLE")) {
setPosition(propValue);
- } else if ((propName.equals("PHOTO") || (propName.equals("LOGO")) && mPhotoBytes == null)) {
- // We prefer PHOTO to LOGO.
+ } else if (propName.equals("PHOTO") || propName.equals("LOGO")) {
+ String formatName = null;
+ Collection<String> typeCollection = paramMap.get("TYPE");
+ if (typeCollection != null) {
+ formatName = typeCollection.iterator().next();
+ }
Collection<String> paramMapValue = paramMap.get("VALUE");
if (paramMapValue != null && paramMapValue.contains("URL")) {
- // TODO: do something.
+ // Currently we do not have appropriate example for testing this case.
} else {
- // Assume PHOTO is stored in BASE64. In that case,
- // data is already stored in propValue_bytes in binary form.
- // It should be automatically done by VBuilder (VDataBuilder/VCardDatabuilder)
- mPhotoBytes = propBytes;
- /*
- Collection<String> typeCollection = paramMap.get("TYPE");
- if (typeCollection != null) {
- if (typeCollection.size() > 1) {
- StringBuilder builder = new StringBuilder();
- int size = typeCollection.size();
- int i = 0;
- for (String type : typeCollection) {
- builder.append(type);
- if (i < size - 1) {
- builder.append(',');
- }
- i++;
- }
- Log.w(LOG_TAG, "There is more than TYPE: " + builder.toString());
- }
- mPhotoType = typeCollection.iterator().next();
- }*/
+ addPhotoBytes(formatName, propBytes);
}
- } else if (propName.equals("EMAIL")) {
- int type = -1;
- String label = null;
- boolean isPrimary = false;
- Collection<String> typeCollection = paramMap.get("TYPE");
- if (typeCollection != null) {
- for (String typeString : typeCollection) {
- if (typeString.equals("PREF") && !mPrefIsSet_Email) {
- // Only first "PREF" is considered.
- mPrefIsSet_Email = true;
- isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
- } else if (typeString.equalsIgnoreCase("WORK")) {
- type = Contacts.ContactMethodsColumns.TYPE_WORK;
- } else if (typeString.equalsIgnoreCase("CELL")) {
- // We do not have Contacts.ContactMethodsColumns.TYPE_MOBILE yet.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME;
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0) {
- // vCard 3.0 allows iana-token.
- // We may have INTERNET (specified in vCard spec),
- // SCHOOL, etc.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString;
- }
- }
- }
- if (type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_OTHER;
- }
- addContactmethod(Contacts.KIND_EMAIL, type, propValue,label, isPrimary);
} else if (propName.equals("TEL")) {
- int type = -1;
- String label = null;
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ Object typeObject = VCardUtils.getPhoneTypeFromStrings(typeCollection);
+ final int type;
+ final String label;
+ if (typeObject instanceof Integer) {
+ type = (Integer)typeObject;
+ label = null;
+ } else {
+ type = Phone.TYPE_CUSTOM;
+ label = typeObject.toString();
+ }
+
+ final boolean isPrimary;
+ if (!mPrefIsSet_Phone && typeCollection != null &&
+ typeCollection.contains(Constants.ATTR_TYPE_PREF)) {
+ mPrefIsSet_Phone = true;
+ isPrimary = true;
+ } else {
+ isPrimary = false;
+ }
+ addPhone(type, propValue, label, isPrimary);
+ } else if (propName.equals(Constants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
+ // The phone number available via Skype.
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ // XXX: should use TYPE_CUSTOM + the label "Skype"? (which may need localization)
+ int type = Phone.TYPE_OTHER;
+ final String label = null;
+ final boolean isPrimary;
+ if (!mPrefIsSet_Phone && typeCollection != null &&
+ typeCollection.contains(Constants.ATTR_TYPE_PREF)) {
+ mPrefIsSet_Phone = true;
+ isPrimary = true;
+ } else {
+ isPrimary = false;
+ }
+ addPhone(type, propValue, label, isPrimary);
+ } else if (sImMap.containsKey(propName)){
+ int type = sImMap.get(propName);
boolean isPrimary = false;
- boolean isFax = false;
- Collection<String> typeCollection = paramMap.get("TYPE");
+ final Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
if (typeCollection != null) {
for (String typeString : typeCollection) {
- if (typeString.equals("PREF") && !mPrefIsSet_Phone) {
- // Only first "PREF" is considered.
- mPrefIsSet_Phone = true;
+ if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.PhonesColumns.TYPE_HOME;
- } else if (typeString.equalsIgnoreCase("WORK")) {
- type = Contacts.PhonesColumns.TYPE_WORK;
- } else if (typeString.equalsIgnoreCase("CELL")) {
- type = Contacts.PhonesColumns.TYPE_MOBILE;
- } else if (typeString.equalsIgnoreCase("PAGER")) {
- type = Contacts.PhonesColumns.TYPE_PAGER;
- } else if (typeString.equalsIgnoreCase("FAX")) {
- isFax = true;
- } else if (typeString.equalsIgnoreCase("VOICE") ||
- typeString.equalsIgnoreCase("MSG")) {
- // Defined in vCard 3.0. Ignore these because they
- // conflict with "HOME", "WORK", etc.
- // XXX: do something?
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.PhonesColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0){
- // We may have MODEM, CAR, ISDN, etc...
- type = Contacts.PhonesColumns.TYPE_CUSTOM;
- label = typeString;
+ } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_HOME)) {
+ type = Phone.TYPE_HOME;
+ } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_WORK)) {
+ type = Phone.TYPE_WORK;
}
}
}
if (type < 0) {
- type = Contacts.PhonesColumns.TYPE_HOME;
+ type = Phone.TYPE_HOME;
}
- if (isFax) {
- if (type == Contacts.PhonesColumns.TYPE_HOME) {
- type = Contacts.PhonesColumns.TYPE_FAX_HOME;
- } else if (type == Contacts.PhonesColumns.TYPE_WORK) {
- type = Contacts.PhonesColumns.TYPE_FAX_WORK;
- }
- }
-
- addPhone(type, propValue, label, isPrimary);
+ addIm(type, propValue, null, isPrimary);
} else if (propName.equals("NOTE")) {
- if (mNotes == null) {
- mNotes = new ArrayList<String>(1);
- }
- mNotes.add(propValue);
- } else if (propName.equals("BDAY")) {
- addExtension(propName, paramMap, propValueList);
+ addNote(propValue);
} else if (propName.equals("URL")) {
- addExtension(propName, paramMap, propValueList);
- } else if (propName.equals("REV")) {
+ if (mWebsiteList == null) {
+ mWebsiteList = new ArrayList<String>(1);
+ }
+ mWebsiteList.add(propValue);
+ } else if (propName.equals("X-PHONETIC-FIRST-NAME")) {
+ mPhoneticGivenName = propValue;
+ } else if (propName.equals("X-PHONETIC-MIDDLE-NAME")) {
+ mPhoneticMiddleName = propValue;
+ } else if (propName.equals("X-PHONETIC-LAST-NAME")) {
+ mPhoneticFamilyName = propValue;
+ } else if (propName.equals("BDAY")) {
+ mBirthday = propValue;
+ /*} else if (propName.equals("REV")) {
// Revision of this VCard entry. I think we can ignore this.
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("UID")) {
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("KEY")) {
// Type is X509 or PGP? I don't know how to handle this...
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("MAILER")) {
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("TZ")) {
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("GEO")) {
- addExtension(propName, paramMap, propValueList);
- } else if (propName.equals("NICKNAME")) {
- // vCard 3.0 only.
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("CLASS")) {
// vCard 3.0 only.
// e.g. CLASS:CONFIDENTIAL
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("PROFILE")) {
// VCard 3.0 only. Must be "VCARD". I think we can ignore this.
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("CATEGORIES")) {
// VCard 3.0 only.
// e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("SOURCE")) {
// VCard 3.0 only.
- addExtension(propName, paramMap, propValueList);
} else if (propName.equals("PRODID")) {
// VCard 3.0 only.
// To specify the identifier for the product that created
- // the vCard object.
- addExtension(propName, paramMap, propValueList);
- } else if (propName.equals("X-PHONETIC-FIRST-NAME")) {
- mTmpXPhoneticFirstName = propValue;
- } else if (propName.equals("X-PHONETIC-MIDDLE-NAME")) {
- mTmpXPhoneticMiddleName = propValue;
- } else if (propName.equals("X-PHONETIC-LAST-NAME")) {
- mTmpXPhoneticLastName = propValue;
+ // the vCard object.*/
} else {
// Unknown X- words and IANA token.
- addExtension(propName, paramMap, propValueList);
}
}
- public String displayString() {
- if (mName.length() > 0) {
- return mName;
+ public String getDisplayName() {
+ if (mDisplayName == null) {
+ constructDisplayName();
}
- if (mContactMethodList != null && mContactMethodList.size() > 0) {
- for (ContactMethod contactMethod : mContactMethodList) {
- if (contactMethod.kind == Contacts.KIND_EMAIL && contactMethod.isPrimary) {
- return contactMethod.data;
- }
- }
- }
- if (mPhoneList != null && mPhoneList.size() > 0) {
- for (PhoneData phoneData : mPhoneList) {
- if (phoneData.isPrimary) {
- return phoneData.data;
- }
- }
- }
- return "";
+ return mDisplayName;
}
/**
+ * Construct the display name. The constructed data must not be null.
+ */
+ private void constructDisplayName() {
+ if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) {
+ StringBuilder builder = new StringBuilder();
+ List<String> nameList;
+ switch (VCardConfig.getNameOrderType(mVCardType)) {
+ case VCardConfig.NAME_ORDER_JAPANESE:
+ if (VCardUtils.containsOnlyAscii(mFamilyName) &&
+ VCardUtils.containsOnlyAscii(mGivenName)) {
+ nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix);
+ } else {
+ nameList = Arrays.asList(mPrefix, mFamilyName, mMiddleName, mGivenName, mSuffix);
+ }
+ break;
+ case VCardConfig.NAME_ORDER_EUROPE:
+ nameList = Arrays.asList(mPrefix, mMiddleName, mGivenName, mFamilyName, mSuffix);
+ break;
+ default:
+ nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix);
+ break;
+ }
+ boolean first = true;
+ for (String namePart : nameList) {
+ if (!TextUtils.isEmpty(namePart)) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(' ');
+ }
+ builder.append(namePart);
+ }
+ }
+ mDisplayName = builder.toString();
+ } else if (!TextUtils.isEmpty(mFullName)) {
+ mDisplayName = mFullName;
+ } else if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
+ TextUtils.isEmpty(mPhoneticGivenName))) {
+ mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
+ mPhoneticFamilyName, mPhoneticMiddleName, mPhoneticGivenName);
+ } else if (mEmailList != null && mEmailList.size() > 0) {
+ mDisplayName = mEmailList.get(0).data;
+ } else if (mPhoneList != null && mPhoneList.size() > 0) {
+ mDisplayName = mPhoneList.get(0).data;
+ } else if (mPostalList != null && mPostalList.size() > 0) {
+ mDisplayName = mPostalList.get(0).getFormattedAddress(mVCardType);
+ }
+
+ if (mDisplayName == null) {
+ mDisplayName = "";
+ }
+ }
+
+ /**
* Consolidate several fielsds (like mName) using name candidates,
*/
public void consolidateFields() {
- if (mTmpFullName != null) {
- mName = mTmpFullName;
- } else if(mTmpNameFromNProperty != null) {
- mName = mTmpNameFromNProperty;
- } else {
- mName = "";
- }
-
- if (mPhoneticName == null &&
- (mTmpXPhoneticFirstName != null || mTmpXPhoneticMiddleName != null ||
- mTmpXPhoneticLastName != null)) {
- // Note: In Europe, this order should be "LAST FIRST MIDDLE". See the comment around
- // NAME_ORDER_TYPE_* for more detail.
- String first;
- String second;
- if (mNameOrderType == VCardConfig.NAME_ORDER_TYPE_JAPANESE) {
- first = mTmpXPhoneticLastName;
- second = mTmpXPhoneticFirstName;
- } else {
- first = mTmpXPhoneticFirstName;
- second = mTmpXPhoneticLastName;
- }
- StringBuilder builder = new StringBuilder();
- if (first != null) {
- builder.append(first);
- }
- if (mTmpXPhoneticMiddleName != null) {
- builder.append(mTmpXPhoneticMiddleName);
- }
- if (second != null) {
- builder.append(second);
- }
- mPhoneticName = builder.toString();
- }
+ constructDisplayName();
- // Remove unnecessary white spaces.
- // It is found that some mobile phone emits phonetic name with just one white space
- // when a user does not specify one.
- // This logic is effective toward such kind of weird data.
- if (mPhoneticName != null) {
- mPhoneticName = mPhoneticName.trim();
+ if (mPhoneticFullName != null) {
+ mPhoneticFullName = mPhoneticFullName.trim();
}
// If there is no "PREF", we choose the first entries as primary.
@@ -969,258 +1009,196 @@
mPhoneList.get(0).isPrimary = true;
}
- if (!mPrefIsSet_Address && mContactMethodList != null) {
- for (ContactMethod contactMethod : mContactMethodList) {
- if (contactMethod.kind == Contacts.KIND_POSTAL) {
- contactMethod.isPrimary = true;
- break;
- }
- }
+ if (!mPrefIsSet_Address && mPostalList != null && mPostalList.size() > 0) {
+ mPostalList.get(0).isPrimary = true;
}
- if (!mPrefIsSet_Email && mContactMethodList != null) {
- for (ContactMethod contactMethod : mContactMethodList) {
- if (contactMethod.kind == Contacts.KIND_EMAIL) {
- contactMethod.isPrimary = true;
- break;
- }
- }
+ if (!mPrefIsSet_Email && mEmailList != null && mEmailList.size() > 0) {
+ mEmailList.get(0).isPrimary = true;
}
if (!mPrefIsSet_Organization && mOrganizationList != null && mOrganizationList.size() > 0) {
mOrganizationList.get(0).isPrimary = true;
}
-
}
- private void pushIntoContentProviderOrResolver(Object contentSomething,
- long myContactsGroupId) {
- ContentResolver resolver = null;
- AbstractSyncableContentProvider provider = null;
- if (contentSomething instanceof ContentResolver) {
- resolver = (ContentResolver)contentSomething;
- } else if (contentSomething instanceof AbstractSyncableContentProvider) {
- provider = (AbstractSyncableContentProvider)contentSomething;
- } else {
- Log.e(LOG_TAG, "Unsupported object came.");
- return;
- }
-
- ContentValues contentValues = new ContentValues();
- contentValues.put(People.NAME, mName);
- contentValues.put(People.PHONETIC_NAME, mPhoneticName);
-
- if (mNotes != null && mNotes.size() > 0) {
- if (mNotes.size() > 1) {
- StringBuilder builder = new StringBuilder();
- for (String note : mNotes) {
- builder.append(note);
- builder.append("\n");
- }
- contentValues.put(People.NOTES, builder.toString());
- } else {
- contentValues.put(People.NOTES, mNotes.get(0));
- }
- }
-
- Uri personUri;
- long personId = 0;
- if (resolver != null) {
- personUri = Contacts.People.createPersonInMyContactsGroup(resolver, contentValues);
- if (personUri != null) {
- personId = ContentUris.parseId(personUri);
- }
- } else {
- personUri = provider.insert(People.CONTENT_URI, contentValues);
- if (personUri != null) {
- personId = ContentUris.parseId(personUri);
- ContentValues values = new ContentValues();
- values.put(GroupMembership.PERSON_ID, personId);
- values.put(GroupMembership.GROUP_ID, myContactsGroupId);
- Uri resultUri = provider.insert(GroupMembership.CONTENT_URI, values);
- if (resultUri == null) {
- Log.e(LOG_TAG, "Faild to insert the person to MyContact.");
- provider.delete(personUri, null, null);
- personUri = null;
- }
- }
- }
-
- if (personUri == null) {
- Log.e(LOG_TAG, "Failed to create the contact.");
- return;
- }
-
- if (mPhotoBytes != null) {
- if (resolver != null) {
- People.setPhotoData(resolver, personUri, mPhotoBytes);
- } else {
- Uri photoUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY);
- ContentValues values = new ContentValues();
- values.put(Photos.DATA, mPhotoBytes);
- provider.update(photoUri, values, null, null);
- }
- }
-
- long primaryPhoneId = -1;
- if (mPhoneList != null && mPhoneList.size() > 0) {
- for (PhoneData phoneData : mPhoneList) {
- ContentValues values = new ContentValues();
- values.put(Contacts.PhonesColumns.TYPE, phoneData.type);
- if (phoneData.type == Contacts.PhonesColumns.TYPE_CUSTOM) {
- values.put(Contacts.PhonesColumns.LABEL, phoneData.label);
- }
- // Already formatted.
- values.put(Contacts.PhonesColumns.NUMBER, phoneData.data);
-
- // Not sure about Contacts.PhonesColumns.NUMBER_KEY ...
- values.put(Contacts.PhonesColumns.ISPRIMARY, 1);
- values.put(Contacts.Phones.PERSON_ID, personId);
- Uri phoneUri;
- if (resolver != null) {
- phoneUri = resolver.insert(Phones.CONTENT_URI, values);
- } else {
- phoneUri = provider.insert(Phones.CONTENT_URI, values);
- }
- if (phoneData.isPrimary) {
- primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());
- }
- }
- }
-
- long primaryOrganizationId = -1;
- if (mOrganizationList != null && mOrganizationList.size() > 0) {
- for (OrganizationData organizationData : mOrganizationList) {
- ContentValues values = new ContentValues();
- // Currently, we do not use TYPE_CUSTOM.
- values.put(Contacts.OrganizationColumns.TYPE,
- organizationData.type);
- values.put(Contacts.OrganizationColumns.COMPANY,
- organizationData.companyName);
- values.put(Contacts.OrganizationColumns.TITLE,
- organizationData.positionName);
- values.put(Contacts.OrganizationColumns.ISPRIMARY, 1);
- values.put(Contacts.OrganizationColumns.PERSON_ID, personId);
-
- Uri organizationUri;
- if (resolver != null) {
- organizationUri = resolver.insert(Organizations.CONTENT_URI, values);
- } else {
- organizationUri = provider.insert(Organizations.CONTENT_URI, values);
- }
- if (organizationData.isPrimary) {
- primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());
- }
- }
- }
-
- long primaryEmailId = -1;
- if (mContactMethodList != null && mContactMethodList.size() > 0) {
- for (ContactMethod contactMethod : mContactMethodList) {
- ContentValues values = new ContentValues();
- values.put(Contacts.ContactMethodsColumns.KIND, contactMethod.kind);
- values.put(Contacts.ContactMethodsColumns.TYPE, contactMethod.type);
- if (contactMethod.type == Contacts.ContactMethodsColumns.TYPE_CUSTOM) {
- values.put(Contacts.ContactMethodsColumns.LABEL, contactMethod.label);
- }
- values.put(Contacts.ContactMethodsColumns.DATA, contactMethod.data);
- values.put(Contacts.ContactMethodsColumns.ISPRIMARY, 1);
- values.put(Contacts.ContactMethods.PERSON_ID, personId);
-
- if (contactMethod.kind == Contacts.KIND_EMAIL) {
- Uri emailUri;
- if (resolver != null) {
- emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);
- } else {
- emailUri = provider.insert(ContactMethods.CONTENT_URI, values);
- }
- if (contactMethod.isPrimary) {
- primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());
- }
- } else { // probably KIND_POSTAL
- if (resolver != null) {
- resolver.insert(ContactMethods.CONTENT_URI, values);
- } else {
- provider.insert(ContactMethods.CONTENT_URI, values);
- }
- }
- }
- }
-
- if (mExtensionMap != null && mExtensionMap.size() > 0) {
- ArrayList<ContentValues> contentValuesArray;
- if (resolver != null) {
- contentValuesArray = new ArrayList<ContentValues>();
- } else {
- contentValuesArray = null;
- }
- for (Entry<String, List<String>> entry : mExtensionMap.entrySet()) {
- String key = entry.getKey();
- List<String> list = entry.getValue();
- for (String value : list) {
- ContentValues values = new ContentValues();
- values.put(Extensions.NAME, key);
- values.put(Extensions.VALUE, value);
- values.put(Extensions.PERSON_ID, personId);
- if (resolver != null) {
- contentValuesArray.add(values);
- } else {
- provider.insert(Extensions.CONTENT_URI, values);
- }
- }
- }
- if (resolver != null) {
- resolver.bulkInsert(Extensions.CONTENT_URI,
- contentValuesArray.toArray(new ContentValues[0]));
- }
- }
-
- if (primaryPhoneId >= 0 || primaryOrganizationId >= 0 || primaryEmailId >= 0) {
- ContentValues values = new ContentValues();
- if (primaryPhoneId >= 0) {
- values.put(People.PRIMARY_PHONE_ID, primaryPhoneId);
- }
- if (primaryOrganizationId >= 0) {
- values.put(People.PRIMARY_ORGANIZATION_ID, primaryOrganizationId);
- }
- if (primaryEmailId >= 0) {
- values.put(People.PRIMARY_EMAIL_ID, primaryEmailId);
- }
- if (resolver != null) {
- resolver.update(personUri, values, null, null);
- } else {
- provider.update(personUri, values, null, null);
- }
- }
- }
-
- /**
- * Push this object into database in the resolver.
- */
public void pushIntoContentResolver(ContentResolver resolver) {
- pushIntoContentProviderOrResolver(resolver, 0);
- }
-
- /**
- * Push this object into AbstractSyncableContentProvider object.
- * {@link #consolidateFields() must be called before this method is called}
- * @hide
- */
- public void pushIntoAbstractSyncableContentProvider(
- AbstractSyncableContentProvider provider, long myContactsGroupId) {
- boolean successful = false;
- provider.beginBatch();
+ ArrayList<ContentProviderOperation> operationList =
+ new ArrayList<ContentProviderOperation>();
+ ContentProviderOperation.Builder builder =
+ ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
+ builder.withValues(new ContentValues());
+ operationList.add(builder.build());
+
+ {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+
+ builder.withValue(StructuredName.GIVEN_NAME, mGivenName);
+ builder.withValue(StructuredName.FAMILY_NAME, mFamilyName);
+ builder.withValue(StructuredName.MIDDLE_NAME, mMiddleName);
+ builder.withValue(StructuredName.PREFIX, mPrefix);
+ builder.withValue(StructuredName.SUFFIX, mSuffix);
+
+ builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticGivenName);
+ builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, mPhoneticFamilyName);
+ builder.withValue(StructuredName.PHONETIC_MIDDLE_NAME, mPhoneticMiddleName);
+
+ builder.withValue(StructuredName.DISPLAY_NAME, getDisplayName());
+ operationList.add(builder.build());
+ }
+
+ if (mNickNameList != null && mNickNameList.size() > 0) {
+ boolean first = true;
+ for (String nickName : mNickNameList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Nickname.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
+ builder.withValue(Nickname.NAME, nickName);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ first = false;
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPhoneList != null) {
+ for (PhoneData phoneData : mPhoneList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Phone.TYPE, phoneData.type);
+ if (phoneData.type == Phone.TYPE_CUSTOM) {
+ builder.withValue(Phone.LABEL, phoneData.label);
+ }
+ builder.withValue(Phone.NUMBER, phoneData.data);
+ if (phoneData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mOrganizationList != null) {
+ boolean first = true;
+ for (OrganizationData organizationData : mOrganizationList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Organization.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+
+ // Currently, we do not use TYPE_CUSTOM.
+ builder.withValue(Organization.TYPE, organizationData.type);
+ builder.withValue(Organization.COMPANY, organizationData.companyName);
+ builder.withValue(Organization.TITLE, organizationData.positionName);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mEmailList != null) {
+ for (EmailData emailData : mEmailList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Email.TYPE, emailData.type);
+ if (emailData.type == Email.TYPE_CUSTOM) {
+ builder.withValue(Email.LABEL, emailData.label);
+ }
+ builder.withValue(Email.DATA, emailData.data);
+ if (emailData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPostalList != null) {
+ for (PostalData postalData : mPostalList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ VCardUtils.insertStructuredPostalDataUsingContactsStruct(
+ mVCardType, builder, postalData);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mImList != null) {
+ for (ImData imData : mImList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Im.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Im.TYPE, imData.type);
+ if (imData.type == Im.TYPE_CUSTOM) {
+ builder.withValue(Im.LABEL, imData.label);
+ }
+ builder.withValue(Im.DATA, imData.data);
+ if (imData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ }
+ }
+
+ if (mNoteList != null) {
+ for (String note : mNoteList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Note.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Note.NOTE, note);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPhotoList != null) {
+ boolean first = true;
+ for (PhotoData photoData : mPhotoList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Photo.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+ builder.withValue(Photo.PHOTO, photoData.photoBytes);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ first = false;
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mWebsiteList != null) {
+ for (String website : mWebsiteList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Website.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
+ builder.withValue(Website.URL, website);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (!TextUtils.isEmpty(mBirthday)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Miscellaneous.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Miscellaneous.CONTENT_ITEM_TYPE);
+ builder.withValue(Miscellaneous.BIRTHDAY, mBirthday);
+ operationList.add(builder.build());
+ }
+
try {
- pushIntoContentProviderOrResolver(provider, myContactsGroupId);
- successful = true;
- } finally {
- provider.endBatch(successful);
+ resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+ } catch (OperationApplicationException e) {
+ Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
}
-
+
public boolean isIgnorable() {
- return TextUtils.isEmpty(mName) &&
- TextUtils.isEmpty(mPhoneticName) &&
- (mPhoneList == null || mPhoneList.size() == 0) &&
- (mContactMethodList == null || mContactMethodList.size() == 0);
+ return getDisplayName().length() == 0;
}
private String listToString(List<String> list){
diff --git a/core/java/android/pim/vcard/EntryCommitter.java b/core/java/android/pim/vcard/EntryCommitter.java
index e26fac5..3f1655d 100644
--- a/core/java/android/pim/vcard/EntryCommitter.java
+++ b/core/java/android/pim/vcard/EntryCommitter.java
@@ -15,11 +15,7 @@
*/
package android.pim.vcard;
-import android.content.AbstractSyncableContentProvider;
-import android.content.ContentProvider;
import android.content.ContentResolver;
-import android.content.IContentProvider;
-import android.provider.Contacts;
import android.util.Log;
/**
@@ -27,62 +23,26 @@
*/
public class EntryCommitter implements EntryHandler {
public static String LOG_TAG = "vcard.EntryComitter";
-
+
private ContentResolver mContentResolver;
-
- // Ideally, this should be ContactsProvider but it seems Class loader cannot find it,
- // even when it is subclass of ContactsProvider...
- private AbstractSyncableContentProvider mProvider;
- private long mMyContactsGroupId;
-
private long mTimeToCommit;
public EntryCommitter(ContentResolver resolver) {
mContentResolver = resolver;
-
- tryGetOriginalProvider();
}
-
- public void onFinal() {
- if (VCardConfig.showPerformanceLog()) {
- Log.d(LOG_TAG,
- String.format("time to commit entries: %ld ms", mTimeToCommit));
- }
- }
-
- private void tryGetOriginalProvider() {
- final ContentResolver resolver = mContentResolver;
-
- if ((mMyContactsGroupId = Contacts.People.tryGetMyContactsGroupId(resolver)) == 0) {
- Log.e(LOG_TAG, "Could not get group id of MyContact");
- return;
- }
- IContentProvider iProviderForName = resolver.acquireProvider(Contacts.CONTENT_URI);
- ContentProvider contentProvider =
- ContentProvider.coerceToLocalContentProvider(iProviderForName);
- if (contentProvider == null) {
- Log.e(LOG_TAG, "Fail to get ContentProvider object.");
- return;
- }
-
- if (!(contentProvider instanceof AbstractSyncableContentProvider)) {
- Log.e(LOG_TAG,
- "Acquired ContentProvider object is not AbstractSyncableContentProvider.");
- return;
- }
-
- mProvider = (AbstractSyncableContentProvider)contentProvider;
+ public void onParsingStart() {
}
+ public void onParsingEnd() {
+ if (VCardConfig.showPerformanceLog()) {
+ Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
+ }
+ }
+
public void onEntryCreated(final ContactStruct contactStruct) {
long start = System.currentTimeMillis();
- if (mProvider != null) {
- contactStruct.pushIntoAbstractSyncableContentProvider(
- mProvider, mMyContactsGroupId);
- } else {
- contactStruct.pushIntoContentResolver(mContentResolver);
- }
+ contactStruct.pushIntoContentResolver(mContentResolver);
mTimeToCommit += System.currentTimeMillis() - start;
}
}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/EntryHandler.java b/core/java/android/pim/vcard/EntryHandler.java
index 4015cb5..7fb8114 100644
--- a/core/java/android/pim/vcard/EntryHandler.java
+++ b/core/java/android/pim/vcard/EntryHandler.java
@@ -16,18 +16,23 @@
package android.pim.vcard;
/**
- * Unlike VCardBuilderBase, this (and VCardDataBuilder) assumes
+ * Unlike {@link VCardBuilder}, this (and {@link VCardDataBuilder}) assumes
* "each VCard entry should be correctly parsed and passed to each EntryHandler object",
*/
public interface EntryHandler {
/**
- * Able to be use this method for showing performance log, etc.
- * TODO: better name?
+ * Called when the parsing started.
*/
- public void onFinal();
+ public void onParsingStart();
/**
* The method called when one VCard entry is successfully created
*/
public void onEntryCreated(final ContactStruct entry);
+
+ /**
+ * Called when the parsing ended.
+ * Able to be use this method for showing performance log, etc.
+ */
+ public void onParsingEnd();
}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
new file mode 100644
index 0000000..283d00b
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -0,0 +1,1433 @@
+/*
+ * 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.pim.vcard;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.content.Entity.NamedContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.os.RemoteException;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Miscellaneous;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.text.TextUtils;
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * The class for composing VCard from Contacts information. Note that this is
+ * completely differnt implementation from
+ * android.syncml.pim.vcard.VCardComposer, which is not maintained anymore.
+ * </p>
+ *
+ * <p>
+ * Usually, this class should be used like this.
+ * </p>
+ *
+ * <pre class="prettyprint"> VCardComposer composer = null; try { composer = new
+ * VCardComposer(context); composer.addHandler(composer.new
+ * HandlerForOutputStream(outputStream)); if (!composer.init()) { // Do
+ * something handling the situation. return; } while (!composer.isAfterLast()) {
+ * if (mCanceled) { // Assume a user may cancel this operation during the
+ * export. return; } if (!composer.createOneEntry()) { // Do something handling
+ * the error situation. return; } } } finally { if (composer != null) {
+ * composer.terminate(); } } </pre>
+ */
+public class VCardComposer {
+ private static final String LOG_TAG = "vcard.VCardComposer";
+
+ public static interface OneEntryHandler {
+ public boolean onInit(Context context);
+
+ public boolean onEntryCreated(String vcard);
+
+ public void onTerminate();
+ }
+
+ /**
+ * <p>
+ * An useful example handler, which emits VCard String to outputstream one
+ * by one.
+ * </p>
+ * <p>
+ * The input OutputStream object is closed() on {{@link #onTerminate()}.
+ * Must not close the stream outside.
+ * </p>
+ */
+ public class HandlerForOutputStream implements OneEntryHandler {
+ @SuppressWarnings("hiding")
+ private static final String LOG_TAG = "vcard.VCardComposer.HandlerForOutputStream";
+
+ private OutputStream mOutputStream; // mWriter will close this.
+ private Writer mWriter;
+
+ private boolean mFinishIsCalled = false;
+
+ /**
+ * Input stream will be closed on the detruction of this object.
+ */
+ public HandlerForOutputStream(OutputStream outputStream) {
+ mOutputStream = outputStream;
+ }
+
+ public boolean onInit(Context context) {
+ try {
+ mWriter = new BufferedWriter(new OutputStreamWriter(
+ mOutputStream, mCharsetString));
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Unsupported charset: " + mCharsetString);
+ mErrorReason = "Encoding is not supported (usually this does not happen!): "
+ + mCharsetString;
+ return false;
+ }
+
+ if (mIsDoCoMo) {
+ try {
+ // Create one empty entry.
+ mWriter.write(createOneEntryInternal("-1"));
+ } catch (IOException e) {
+ Log.e(LOG_TAG,
+ "IOException occurred during exportOneContactData: "
+ + e.getMessage());
+ mErrorReason = "IOException occurred: " + e.getMessage();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean onEntryCreated(String vcard) {
+ try {
+ mWriter.write(vcard);
+ } catch (IOException e) {
+ Log.e(LOG_TAG,
+ "IOException occurred during exportOneContactData: "
+ + e.getMessage());
+ mErrorReason = "IOException occurred: " + e.getMessage();
+ return false;
+ }
+ return true;
+ }
+
+ public void onTerminate() {
+ if (mWriter != null) {
+ try {
+ // Flush and sync the data so that a user is able to pull
+ // the SDCard just after
+ // the export.
+ mWriter.flush();
+ if (mOutputStream != null
+ && mOutputStream instanceof FileOutputStream) {
+ ((FileOutputStream) mOutputStream).getFD().sync();
+ }
+ } catch (IOException e) {
+ Log.d(LOG_TAG,
+ "IOException during closing the output stream: "
+ + e.getMessage());
+ } finally {
+ try {
+ mWriter.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void finalize() {
+ if (!mFinishIsCalled) {
+ onTerminate();
+ }
+ }
+ }
+
+ public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
+
+ private static final String VCARD_PROPERTY_ADR = "ADR";
+ private static final String VCARD_PROPERTY_BEGIN = "BEGIN";
+ private static final String VCARD_PROPERTY_EMAIL = "EMAIL";
+ private static final String VCARD_PROPERTY_END = "END";
+ private static final String VCARD_PROPERTY_NAME = "N";
+ private static final String VCARD_PROPERTY_FULL_NAME = "FN";
+ private static final String VCARD_PROPERTY_NOTE = "NOTE";
+ private static final String VCARD_PROPERTY_ORG = "ORG";
+ private static final String VCARD_PROPERTY_SOUND = "SOUND";
+ private static final String VCARD_PROPERTY_SORT_STRING = "SORT-STRING";
+ private static final String VCARD_PROPERTY_NICKNAME = "NICKNAME";
+ private static final String VCARD_PROPERTY_TEL = "TEL";
+ private static final String VCARD_PROPERTY_TITLE = "TITLE";
+ private static final String VCARD_PROPERTY_PHOTO = "PHOTO";
+ private static final String VCARD_PROPERTY_VERSION = "VERSION";
+ private static final String VCARD_PROPERTY_URL = "URL";
+ private static final String VCARD_PROPERTY_BIRTHDAY = "BDAY";
+
+ private static final String VCARD_PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME";
+ private static final String VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
+ private static final String VCARD_PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
+
+ // Android specific properties
+ private static final String VCARD_PROPERTY_X_PHONETIC_NAME = "X-PHONETIC-NAME";
+ private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME";
+ // TODO: add properties like X-LATITUDE
+
+ // Properties for DoCoMo vCard.
+ private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS";
+ private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION";
+ private static final String VCARD_PROPERTY_X_NO = "X-NO";
+ private static final String VCARD_PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
+
+ private static final String VCARD_DATA_VCARD = "VCARD";
+ private static final String VCARD_DATA_PUBLIC = "PUBLIC";
+
+ private static final String VCARD_ATTR_SEPARATOR = ";";
+ private static final String VCARD_COL_SEPARATOR = "\r\n";
+ private static final String VCARD_DATA_SEPARATOR = ":";
+ private static final String VCARD_ITEM_SEPARATOR = ";";
+ private static final String VCARD_WS = " ";
+
+ // Type strings are now in VCardConstants.java.
+
+ private static final String VCARD_ATTR_ENCODING_QP = "ENCODING=QUOTED-PRINTABLE";
+
+ private static final String VCARD_ATTR_ENCODING_BASE64_V21 = "ENCODING=BASE64";
+ private static final String VCARD_ATTR_ENCODING_BASE64_V30 = "ENCODING=b";
+
+ private static final String SHIFT_JIS = "SHIFT_JIS";
+
+ private final Context mContext;
+ private final int mVCardType;
+ private final boolean mCareHandlerErrors;
+ private final ContentResolver mContentResolver;
+
+ // Convenient member variables about the restriction of the vCard format.
+ // Used for not calling the same methods returning same results.
+ private final boolean mIsV30;
+ private final boolean mIsJapaneseMobilePhone;
+ private final boolean mOnlyOneNoteFieldIsAvailable;
+ private final boolean mIsDoCoMo;
+ private final boolean mUsesQuotedPrintable;
+ private final boolean mUsesAndroidProperty;
+ private final boolean mUsesDefactProperty;
+ private final boolean mUsesShiftJis;
+
+ private Cursor mCursor;
+ private int mIdColumn;
+
+ private String mCharsetString;
+ private static String mVCardAttributeCharset;
+ private boolean mTerminateIsCalled;
+ private List<OneEntryHandler> mHandlerList;
+
+ private String mErrorReason = "No error";
+
+ private static final Map<Integer, String> sImMap;
+
+ static {
+ sImMap = new HashMap<Integer, String>();
+ sImMap.put(Im.PROTOCOL_AIM, Constants.PROPERTY_X_AIM);
+ sImMap.put(Im.PROTOCOL_MSN, Constants.PROPERTY_X_MSN);
+ sImMap.put(Im.PROTOCOL_YAHOO, Constants.PROPERTY_X_YAHOO);
+ sImMap.put(Im.PROTOCOL_ICQ, Constants.PROPERTY_X_ICQ);
+ sImMap.put(Im.PROTOCOL_JABBER, Constants.PROPERTY_X_JABBER);
+ sImMap.put(Im.PROTOCOL_SKYPE, Constants.PROPERTY_X_SKYPE_USERNAME);
+ // Google talk is a special case.
+ }
+
+
+ public VCardComposer(Context context) {
+ this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
+ }
+
+ public VCardComposer(Context context, String vcardTypeStr,
+ boolean careHandlerErrors) {
+ this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr),
+ careHandlerErrors);
+ }
+
+ public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) {
+ mContext = context;
+ mVCardType = vcardType;
+ mCareHandlerErrors = careHandlerErrors;
+ mContentResolver = context.getContentResolver();
+
+ mIsV30 = VCardConfig.isV30(vcardType);
+ mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType);
+ mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
+ mIsJapaneseMobilePhone = VCardConfig
+ .needsToConvertPhoneticString(vcardType);
+ mOnlyOneNoteFieldIsAvailable = VCardConfig
+ .onlyOneNoteFieldIsAvailable(vcardType);
+ mUsesAndroidProperty = VCardConfig
+ .usesAndroidSpecificProperty(vcardType);
+ mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
+ mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
+
+ if (mIsDoCoMo) {
+ mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+ // Do not use mCharsetString bellow since it is different from "SHIFT_JIS" but
+ // may be "DOCOMO_SHIFT_JIS" or something like that (internal expression used in
+ // Android, not shown to the public).
+ mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS;
+ } else if (mUsesShiftJis) {
+ mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+ mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS;
+ } else {
+ mCharsetString = "UTF-8";
+ mVCardAttributeCharset = "CHARSET=UTF-8";
+ }
+ }
+
+ /**
+ * Must call before {{@link #init()}.
+ */
+ public void addHandler(OneEntryHandler handler) {
+ if (mHandlerList == null) {
+ mHandlerList = new ArrayList<OneEntryHandler>();
+ }
+ mHandlerList.add(handler);
+ }
+
+ public boolean init() {
+ return init(null, null);
+ }
+
+ /**
+ * @return Returns true when initialization is successful and all the other
+ * methods are available. Returns false otherwise.
+ */
+ public boolean init(final String selection, final String[] selectionArgs) {
+ if (mCareHandlerErrors) {
+ List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
+ mHandlerList.size());
+ for (OneEntryHandler handler : mHandlerList) {
+ if (!handler.onInit(mContext)) {
+ for (OneEntryHandler finished : finishedList) {
+ finished.onTerminate();
+ }
+ return false;
+ }
+ }
+ } else {
+ // Just ignore the false returned from onInit().
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onInit(mContext);
+ }
+ }
+
+ final String[] projection = new String[] {Contacts._ID,};
+
+ // TODO: thorow an appropriate exception!
+ mCursor = mContentResolver.query(RawContacts.CONTENT_URI, projection,
+ selection, selectionArgs, null);
+ if (mCursor == null || !mCursor.moveToFirst()) {
+ if (mCursor != null) {
+ try {
+ mCursor.close();
+ } catch (SQLiteException e) {
+ Log.e(LOG_TAG, "SQLiteException on Cursor#close(): "
+ + e.getMessage());
+ }
+ mCursor = null;
+ }
+ mErrorReason = "Getting database information failed.";
+ return false;
+ }
+
+ mIdColumn = mCursor.getColumnIndex(Contacts._ID);
+
+ return true;
+ }
+
+ public boolean createOneEntry() {
+ if (mCursor == null || mCursor.isAfterLast()) {
+ // TODO: ditto
+ mErrorReason = "Not initialized or database has some problem.";
+ return false;
+ }
+ String name = null;
+ String vcard;
+ try {
+ vcard = createOneEntryInternal(mCursor.getString(mIdColumn));
+ } catch (OutOfMemoryError error) {
+ // Maybe some data (e.g. photo) is too big to have in memory. But it
+ // should be rare.
+ Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry: "
+ + name);
+ System.gc();
+ // TODO: should tell users what happened?
+ return true;
+ } finally {
+ mCursor.moveToNext();
+ }
+
+ // This function does not care the OutOfMemoryError on the handler side
+ // :-P
+ if (mCareHandlerErrors) {
+ List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
+ mHandlerList.size());
+ for (OneEntryHandler handler : mHandlerList) {
+ if (!handler.onEntryCreated(vcard)) {
+ return false;
+ }
+ }
+ } else {
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onEntryCreated(vcard);
+ }
+ }
+
+ return true;
+ }
+
+ private String createOneEntryInternal(final String contactId) {
+ final StringBuilder builder = new StringBuilder();
+ appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD);
+ if (mIsV30) {
+ appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30);
+ } else {
+ appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21);
+ }
+
+ final Map<String, List<ContentValues>> contentValuesListMap =
+ new HashMap<String, List<ContentValues>>();
+
+ final String selection = Data.RAW_CONTACT_ID + "=?";
+ final String[] selectionArgs = new String[] {contactId};
+ EntityIterator entityIterator = null;
+ try {
+ entityIterator = mContentResolver.queryEntities(
+ RawContacts.CONTENT_URI, selection, selectionArgs, null);
+ while (entityIterator.hasNext()) {
+ Entity entity = entityIterator.next();
+ for (NamedContentValues namedContentValues : entity
+ .getSubValues()) {
+ ContentValues contentValues = namedContentValues.values;
+ String key = contentValues.getAsString(Data.MIMETYPE);
+ if (key != null) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(key);
+ if (contentValuesList == null) {
+ contentValuesList = new ArrayList<ContentValues>();
+ contentValuesListMap.put(key, contentValuesList);
+ }
+ contentValuesList.add(contentValues);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, String.format("RemoteException at id %s (%s)",
+ contactId, e.getMessage()));
+ return "";
+ } finally {
+ if (entityIterator != null) {
+ entityIterator.close();
+ }
+ }
+
+ // TODO: consolidate order? (low priority)
+ appendStructuredNames(builder, contentValuesListMap);
+ appendNickNames(builder, contentValuesListMap);
+ appendPhones(builder, contentValuesListMap);
+ appendEmails(builder, contentValuesListMap);
+ appendPostals(builder, contentValuesListMap);
+ appendIms(builder, contentValuesListMap);
+ appendWebsites(builder, contentValuesListMap);
+ appendBirthday(builder, contentValuesListMap);
+ appendOrganizations(builder, contentValuesListMap);
+ appendPhotos(builder, contentValuesListMap);
+ appendNotes(builder, contentValuesListMap);
+ // TODO: GroupMembership... What?
+
+ if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_X_CLASS, VCARD_DATA_PUBLIC);
+ appendVCardLine(builder, VCARD_PROPERTY_X_REDUCTION, "");
+ appendVCardLine(builder, VCARD_PROPERTY_X_NO, "");
+ appendVCardLine(builder, VCARD_PROPERTY_X_DCM_HMN_MODE, "");
+ }
+
+ appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD);
+
+ return builder.toString();
+ }
+
+ public void terminate() {
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onTerminate();
+ }
+
+ if (mCursor != null) {
+ try {
+ mCursor.close();
+ } catch (SQLiteException e) {
+ Log.e(LOG_TAG, "SQLiteException on Cursor#close(): "
+ + e.getMessage());
+ }
+ mCursor = null;
+ }
+
+ mTerminateIsCalled = true;
+ }
+
+ @Override
+ public void finalize() {
+ if (!mTerminateIsCalled) {
+ terminate();
+ }
+ }
+
+ public int getCount() {
+ if (mCursor == null) {
+ return 0;
+ }
+ return mCursor.getCount();
+ }
+
+ public boolean isAfterLast() {
+ if (mCursor == null) {
+ return false;
+ }
+ return mCursor.isAfterLast();
+ }
+
+ /**
+ * @return Return the error reason if possible.
+ */
+ public String getErrorReason() {
+ return mErrorReason;
+ }
+
+ private void appendStructuredNames(StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(StructuredName.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ appendStructuredNamesInternal(builder, contentValuesList);
+ } else if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+ }
+ }
+
+ private void appendStructuredNamesInternal(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String familyName = contentValues
+ .getAsString(StructuredName.FAMILY_NAME);
+ final String middleName = contentValues
+ .getAsString(StructuredName.MIDDLE_NAME);
+ final String givenName = contentValues
+ .getAsString(StructuredName.GIVEN_NAME);
+ final String prefix = contentValues
+ .getAsString(StructuredName.PREFIX);
+ final String suffix = contentValues
+ .getAsString(StructuredName.SUFFIX);
+ final String displayName = contentValues
+ .getAsString(StructuredName.DISPLAY_NAME);
+
+ // For now, some primary element is not encoded into Quoted-Printable, which is not
+ // valid in vCard spec strictly. In the future, we may have to have some flag to
+ // enable composer to encode these primary field into Quoted-Printable.
+ if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
+ final String encodedFamily = escapeCharacters(familyName);
+ final String encodedGiven = escapeCharacters(givenName);
+ final String encodedMiddle = escapeCharacters(middleName);
+ final String encodedPrefix = escapeCharacters(prefix);
+ final String encodedSuffix = escapeCharacters(suffix);
+
+ // N property. This order is specified by vCard spec and does not depend on countries.
+ builder.append(VCARD_PROPERTY_NAME);
+ if (!(VCardUtils.containsOnlyAscii(familyName) &&
+ VCardUtils.containsOnlyAscii(givenName) &&
+ VCardUtils.containsOnlyAscii(middleName) &&
+ VCardUtils.containsOnlyAscii(prefix) &&
+ VCardUtils.containsOnlyAscii(suffix))) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedFamily);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedGiven);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedMiddle);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedPrefix);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedSuffix);
+ builder.append(VCARD_COL_SEPARATOR);
+
+ final String encodedFullname = VCardUtils.constructNameFromElements(
+ VCardConfig.getNameOrderType(mVCardType),
+ encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
+
+ // FN property
+ builder.append(VCARD_PROPERTY_FULL_NAME);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ if (!VCardUtils.containsOnlyAscii(encodedFullname)) {
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+ builder.append(encodedFullname);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else if (!TextUtils.isEmpty(displayName)) {
+ builder.append(VCARD_PROPERTY_NAME);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(escapeCharacters(displayName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+ }
+
+ String phoneticFamilyName = contentValues
+ .getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ String phoneticMiddleName = contentValues
+ .getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ String phoneticGivenName = contentValues
+ .getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ if (!(TextUtils.isEmpty(phoneticFamilyName)
+ && TextUtils.isEmpty(phoneticMiddleName) && TextUtils
+ .isEmpty(phoneticGivenName))) { // if not empty
+ if (mIsJapaneseMobilePhone) {
+ phoneticFamilyName = VCardUtils
+ .toHalfWidthString(phoneticFamilyName);
+ phoneticMiddleName = VCardUtils
+ .toHalfWidthString(phoneticMiddleName);
+ phoneticGivenName = VCardUtils
+ .toHalfWidthString(phoneticGivenName);
+ }
+
+ if (mIsV30) {
+ final String sortString = VCardUtils
+ .constructNameFromElements(mVCardType,
+ phoneticFamilyName, phoneticMiddleName,
+ phoneticGivenName);
+ builder.append(VCARD_PROPERTY_SORT_STRING);
+
+ if (!VCardUtils.containsOnlyAscii(sortString)) {
+ // Strictly, adding charset information is NOT valid in
+ // VCard 3.0,
+ // but we'll add this info since parser side may be able to
+ // use the charset via
+ // this attribute field.
+ //
+ // e.g. Japanese mobile phones use Shift_Jis while RFC 2426
+ // recommends
+ // UTF-8. By adding this field, parsers may be able to know
+ // this text
+ // is NOT UTF-8 but Shift_Jis.
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(sortString);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else {
+ // Note: There is no appropriate property for expressing
+ // phonetic name in
+ // VCard 2.1, while there is in VCard 3.0 (SORT-STRING).
+ // We chose to use DoCoMo's way since it is supported by a
+ // lot of
+ // Japanese mobile phones.
+ //
+ // TODO: should use Quoted-Pritable?
+ builder.append(VCARD_PROPERTY_SOUND);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_X_IRMC_N);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ if (!(VCardUtils.containsOnlyAscii(phoneticFamilyName) &&
+ VCardUtils.containsOnlyAscii(phoneticMiddleName) &&
+ VCardUtils.containsOnlyAscii(phoneticGivenName))) {
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+
+ builder.append(escapeCharacters(phoneticFamilyName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(escapeCharacters(phoneticMiddleName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(escapeCharacters(phoneticGivenName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+
+ if (mUsesAndroidProperty) {
+ final String phoneticName = VCardUtils
+ .constructNameFromElements(mVCardType,
+ phoneticFamilyName, phoneticMiddleName,
+ phoneticGivenName);
+ builder.append(VCARD_PROPERTY_X_PHONETIC_NAME);
+
+ if (!VCardUtils.containsOnlyAscii(phoneticName)) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ // TODO: may need to make the text quoted-printable.
+ builder.append(phoneticName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ } else if (mIsDoCoMo) {
+ builder.append(VCARD_PROPERTY_SOUND);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_X_IRMC_N);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ if (mUsesDefactProperty) {
+ if (!TextUtils.isEmpty(phoneticGivenName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticGivenName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ if (!TextUtils.isEmpty(phoneticMiddleName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticMiddleName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ if (!TextUtils.isEmpty(phoneticFamilyName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticFamilyName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ }
+ }
+
+ private void appendNickNames(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Nickname.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ final String propertyNickname;
+ if (mIsV30) {
+ propertyNickname = VCARD_PROPERTY_NICKNAME;
+ } else if (mUsesAndroidProperty) {
+ propertyNickname = VCARD_PROPERTY_X_NICKNAME;
+ } else {
+ // There's no way to add this field.
+ return;
+ }
+
+ for (ContentValues contentValues : contentValuesList) {
+ final String nickname = contentValues
+ .getAsString(Nickname.NAME);
+ if (TextUtils.isEmpty(nickname)) {
+ continue;
+ }
+ builder.append(propertyNickname);
+
+ if (!VCardUtils.containsOnlyAscii(propertyNickname)) {
+ // Strictly, this is not valid in vCard 3.0. See above.
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(escapeCharacters(nickname));
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ }
+
+ private void appendPhones(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Phone.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ appendVCardTelephoneLine(builder, contentValues
+ .getAsInteger(Phone.TYPE), contentValues
+ .getAsString(Phone.LABEL), contentValues
+ .getAsString(Phone.NUMBER));
+ }
+ } else if (mIsDoCoMo) {
+ appendVCardTelephoneLine(builder, Phone.TYPE_HOME, "", "");
+ }
+ }
+
+ private void appendEmails(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Email.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ appendVCardEmailLine(builder, contentValues
+ .getAsInteger(Email.TYPE), contentValues
+ .getAsString(Email.LABEL), contentValues
+ .getAsString(Email.DATA));
+ }
+ } else if (mIsDoCoMo) {
+ appendVCardEmailLine(builder, Email.TYPE_HOME, "", "");
+ }
+ }
+
+ private void appendPostals(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ if (contentValuesList != null) {
+ if (mIsDoCoMo) {
+ appendPostalsForDoCoMo(builder, contentValuesList);
+ } else {
+ appendPostalsForGeneric(builder, contentValuesList);
+ }
+ } else if (mIsDoCoMo) {
+ builder.append(VCARD_PROPERTY_ADR);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_HOME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+
+ /**
+ * Try to append just one line. If there's no appropriate address
+ * information, append an empty line.
+ */
+ private void appendPostalsForDoCoMo(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ // TODO: from old, inefficient code. fix this.
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_HOME)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_WORK)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_OTHER)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_CUSTOM)) {
+ return;
+ }
+
+ Log.w(LOG_TAG,
+ "Should not come here. Must have at least one postal data.");
+ }
+
+ private boolean appendPostalsForDoCoMoInternal(final StringBuilder builder,
+ final List<ContentValues> contentValuesList, int preferedType) {
+ for (ContentValues contentValues : contentValuesList) {
+ final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
+ final String label = contentValues
+ .getAsString(StructuredPostal.LABEL);
+ if (type == preferedType) {
+ appendVCardPostalLine(builder, type, label, contentValues);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void appendPostalsForGeneric(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ for (ContentValues contentValues : contentValuesList) {
+ final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
+ final String label = contentValues
+ .getAsString(StructuredPostal.LABEL);
+ appendVCardPostalLine(builder, type, label, contentValues);
+ }
+ }
+
+ private void appendIms(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Im.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ int type = contentValues.getAsInteger(Im.PROTOCOL);
+ String data = contentValues.getAsString(Im.DATA);
+
+ Log.d("@@@", "Im information. protocol=\"" + type +
+ "\", data=\"" + data + "\", protocol=\"" +
+ contentValues.getAsString(Im.PROTOCOL) + "\", custom_protocol=\"" +
+ contentValues.getAsString(Im.CUSTOM_PROTOCOL) + "\"");
+
+ if (type == Im.PROTOCOL_GOOGLE_TALK) {
+ if (VCardConfig.usesAndroidSpecificProperty(mVCardType)) {
+ appendVCardLine(builder, Constants.PROPERTY_X_GOOGLE_TALK, data);
+ }
+ // TODO: add "X-GOOGLE TALK" case...
+ }
+ }
+ }
+ }
+
+ private void appendWebsites(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Website.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String website = contentValues.getAsString(Website.URL);
+ appendVCardLine(builder, VCARD_PROPERTY_URL, website);
+ }
+ }
+ }
+
+ private void appendBirthday(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Website.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null && contentValuesList.size() > 0) {
+ // Theoretically, there must be only one birthday for each vCard data and
+ // we are afraid of some parse error occuring in some devices, so
+ // we emit only one birthday entry for now.
+ final String birthday = contentValuesList.get(0).getAsString(Miscellaneous.BIRTHDAY);
+ appendVCardLine(builder, VCARD_PROPERTY_BIRTHDAY, birthday);
+ }
+ }
+
+ private void appendOrganizations(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Organization.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String company = contentValues
+ .getAsString(Organization.COMPANY);
+ final String title = contentValues
+ .getAsString(Organization.TITLE);
+ appendVCardLine(builder, VCARD_PROPERTY_ORG, company, true,
+ mUsesQuotedPrintable);
+ appendVCardLine(builder, VCARD_PROPERTY_TITLE, title, true,
+ mUsesQuotedPrintable);
+ }
+ }
+ }
+
+ private void appendPhotos(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Photo.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ byte[] data = contentValues.getAsByteArray(Photo.PHOTO);
+ final String photoType;
+ // Use some heuristics for guessing the format of the image.
+ // TODO: there should be some general API for detecting the file format.
+ if (data.length >= 3 && data[0] == 'G' && data[1] == 'I'
+ && data[2] == 'F') {
+ photoType = "GIF";
+ } else if (data.length >= 4 && data[0] == (byte) 0x89
+ && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
+ // Note: vCard 2.1 officially does not support PNG, but we
+ // may have it
+ // and using X- word like "X-PNG" may not let importers know
+ // it is
+ // PNG. So we use the String "PNG" as is...
+ photoType = "PNG";
+ } else if (data.length >= 2 && data[0] == (byte) 0xff
+ && data[1] == (byte) 0xd8) {
+ photoType = "JPEG";
+ } else {
+ Log.d(LOG_TAG, "Unknown photo type. Ignore.");
+ continue;
+ }
+ String photoString = VCardUtils.encodeBase64(data);
+ if (photoString.length() > 0) {
+ appendVCardPhotoLine(builder, photoString, photoType);
+ }
+ }
+ }
+ }
+
+ private void appendNotes(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ final List<ContentValues> contentValuesList =
+ contentValuesListMap.get(Note.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ if (mOnlyOneNoteFieldIsAvailable) {
+ StringBuilder noteBuilder = new StringBuilder();
+ boolean first = true;
+ for (ContentValues contentValues : contentValuesList) {
+ final String note = contentValues.getAsString(Note.NOTE);
+ if (note.length() > 0) {
+ if (first) {
+ first = false;
+ } else {
+ noteBuilder.append('\n');
+ }
+ noteBuilder.append(note);
+ }
+ }
+ appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteBuilder.toString(),
+ true, mUsesQuotedPrintable);
+ } else {
+ for (ContentValues contentValues : contentValuesList) {
+ final String note = contentValues.getAsString(Note.NOTE);
+ if (!TextUtils.isEmpty(note)) {
+ appendVCardLine(builder, VCARD_PROPERTY_NOTE, note, true,
+ mUsesQuotedPrintable);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Append '\' to the characters which should be escaped. The character set is different
+ * not only between vCard 2.1 and vCard 3.0 but also among each device.
+ *
+ * Note that Quoted-Printable string must not be input here.
+ */
+ @SuppressWarnings("fallthrough")
+ private String escapeCharacters(String unescaped) {
+ if (TextUtils.isEmpty(unescaped)) {
+ return "";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ final int length = unescaped.length();
+ for (int i = 0; i < length; i++) {
+ char ch = unescaped.charAt(i);
+ switch (ch) {
+ case ';':
+ builder.append('\\');
+ builder.append(';');
+ break;
+ case '\r':
+ if (i + 1 < length) {
+ char nextChar = unescaped.charAt(i);
+ if (nextChar == '\n') {
+ continue;
+ } else {
+ // fall through
+ }
+ } else {
+ // fall through
+ }
+ case '\n':
+ // In vCard 2.1, there's no specification about this, while
+ // vCard 3.0 explicitly
+ // requires this should be encoded to "\n".
+ builder.append("\\n");
+ break;
+ case '\\':
+ if (mIsV30) {
+ builder.append("\\\\");
+ break;
+ }
+ case '<':
+ case '>':
+ if (mIsDoCoMo) {
+ builder.append('\\');
+ builder.append(ch);
+ }
+ break;
+ case ',':
+ if (mIsV30) {
+ builder.append("\\,");
+ break;
+ }
+ default:
+ builder.append(ch);
+ break;
+ }
+ }
+ return builder.toString();
+ }
+
+ private void appendVCardPhotoLine(StringBuilder builder,
+ String encodedData, String type) {
+ StringBuilder tmpBuilder = new StringBuilder();
+ tmpBuilder.append(VCARD_PROPERTY_PHOTO);
+ tmpBuilder.append(VCARD_ATTR_SEPARATOR);
+ if (mIsV30) {
+ tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V30);
+ } else {
+ tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V21);
+ }
+ tmpBuilder.append(VCARD_ATTR_SEPARATOR);
+ tmpBuilder.append("TYPE=");
+ tmpBuilder.append(type);
+ tmpBuilder.append(VCARD_DATA_SEPARATOR);
+ tmpBuilder.append(encodedData);
+
+ String tmpStr = tmpBuilder.toString();
+ tmpBuilder = new StringBuilder();
+ int lineCount = 0;
+ for (int i = 0; i < tmpStr.length(); i++) {
+ tmpBuilder.append(tmpStr.charAt(i));
+ lineCount++;
+ if (lineCount > 72) {
+ tmpBuilder.append(VCARD_COL_SEPARATOR);
+ tmpBuilder.append(VCARD_WS);
+ lineCount = 0;
+ }
+ }
+ builder.append(tmpBuilder.toString());
+ builder.append(VCARD_COL_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardPostalLine(StringBuilder builder, int type,
+ String label, final ContentValues contentValues) {
+ builder.append(VCARD_PROPERTY_ADR);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ boolean dataExists = false;
+ String[] dataArray = VCardUtils.getVCardPostalElements(contentValues);
+ int length = dataArray.length;
+ final boolean useQuotedPrintable = mUsesQuotedPrintable;
+ for (int i = 0; i < length; i++) {
+ String data = dataArray[i];
+ if (!TextUtils.isEmpty(data)) {
+ dataExists = true;
+ if (useQuotedPrintable) {
+ dataArray[i] = encodeQuotedPrintable(data);
+ } else {
+ dataArray[i] = escapeCharacters(data);
+ }
+ }
+ }
+
+ boolean typeIsAppended = false;
+ switch (type) {
+ case StructuredPostal.TYPE_HOME:
+ builder.append(Constants.ATTR_TYPE_HOME);
+ typeIsAppended = true;
+ break;
+ case StructuredPostal.TYPE_WORK:
+ builder.append(Constants.ATTR_TYPE_WORK);
+ typeIsAppended = true;
+ break;
+ case StructuredPostal.TYPE_CUSTOM:
+ if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+ // We're not sure whether the label is valid in the spec ("IANA-token" in the vCard 3.1
+ // is unclear...)
+ // Just for safety, we add "X-" at the beggining of each label.
+ // Also checks the label obeys with vCard 3.0 spec.
+ builder.append("X-");
+ builder.append(label);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+ break;
+ case StructuredPostal.TYPE_OTHER:
+ break;
+ default:
+ Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type);
+ break;
+ }
+
+ if (dataExists) {
+ if (typeIsAppended) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ }
+ // Strictly, vCard 3.0 does not allow this, but we add this since
+ // this information
+ // should be useful, Assume no parser does not emit error with this
+ // attribute.
+ builder.append(mVCardAttributeCharset);
+ if (useQuotedPrintable) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(VCARD_ATTR_ENCODING_QP);
+ }
+ }
+ builder.append(VCARD_DATA_SEPARATOR);
+ if (dataExists) {
+ // The elements in dataArray are already encoded to quoted printable
+ // if needed.
+ // See above.
+ //
+ // TODO: in vCard 3.0, one line may become too huge. Fix this.
+ builder.append(dataArray[0]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[1]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[2]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[3]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[4]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[5]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[6]);
+ }
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardEmailLine(StringBuilder builder, int type,
+ String label, String data) {
+ builder.append(VCARD_PROPERTY_EMAIL);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ switch (type) {
+ case Email.TYPE_CUSTOM:
+ if (label.equals(
+ android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME)) {
+ builder.append(Constants.ATTR_TYPE_CELL);
+ } else if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+ builder.append("X-");
+ builder.append(label);
+ } else {
+ // Default to INTERNET.
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ }
+ break;
+ case Email.TYPE_HOME:
+ builder.append(Constants.ATTR_TYPE_HOME);
+ break;
+ case Email.TYPE_WORK:
+ builder.append(Constants.ATTR_TYPE_WORK);
+ break;
+ case Email.TYPE_OTHER:
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ break;
+ default:
+ Log.e(LOG_TAG, "Unknown Email type: " + type);
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ break;
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(data);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardTelephoneLine(StringBuilder builder, int type,
+ String label, String encodedData) {
+ builder.append(VCARD_PROPERTY_TEL);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ switch (type) {
+ case Phone.TYPE_HOME:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_VOICE));
+ break;
+ case Phone.TYPE_WORK:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_VOICE));
+ break;
+ case Phone.TYPE_FAX_HOME:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_FAX));
+ break;
+ case Phone.TYPE_FAX_WORK:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_FAX));
+ break;
+ case Phone.TYPE_MOBILE:
+ builder.append(Constants.ATTR_TYPE_CELL);
+ break;
+ case Phone.TYPE_PAGER:
+ if (mIsDoCoMo) {
+ // Not sure about the reason, but previous implementation had
+ // used "VOICE" instead of "PAGER"
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ } else {
+ builder.append(Constants.ATTR_TYPE_PAGER);
+ }
+ break;
+ case Phone.TYPE_OTHER:
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ break;
+ case Phone.TYPE_CUSTOM:
+ if (mUsesAndroidProperty) {
+ VCardUtils.containsOnlyAlphaDigitHyphen(label);
+ builder.append("X-" + label);
+ } else {
+ // Just ignore the custom type.
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ }
+ break;
+ default:
+ appendUncommonPhoneType(builder, type);
+ break;
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedData);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ /**
+ * Appends phone type string which may not be available in some devices.
+ */
+ private void appendUncommonPhoneType(StringBuilder builder, int type) {
+ if (mIsDoCoMo) {
+ // The previous implementation for DoCoMo had been conservative
+ // about
+ // miscellaneous types.
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ } else {
+ String phoneAttribute = VCardUtils.getPhoneAttributeString(type);
+ if (phoneAttribute != null) {
+ builder.append(phoneAttribute);
+ } else {
+ Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type);
+ }
+ }
+ }
+
+ private void appendVCardLine(final StringBuilder builder,
+ final String propertyName, final String rawData) {
+ appendVCardLine(builder, propertyName, rawData, false, false);
+ }
+
+ private void appendVCardLine(final StringBuilder builder,
+ final String field, final String rawData, boolean needCharset,
+ boolean needQuotedPrintable) {
+ builder.append(field);
+ if (needCharset) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ final String encodedData;
+ if (needQuotedPrintable) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(VCARD_ATTR_ENCODING_QP);
+ encodedData = encodeQuotedPrintable(rawData);
+ } else {
+ // TODO: one line may be too huge, which may be invalid in vCard spec, though
+ // several (even well-known) applications do not care this.
+ encodedData = escapeCharacters(rawData);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedData);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendTypeAttributes(final StringBuilder builder,
+ final List<String> types) {
+ // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future,
+ // which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
+ boolean first = true;
+ for (String type : types) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ }
+ if (mIsV30) {
+ builder.append(Constants.ATTR_TYPE);
+ builder.append('=');
+ }
+ builder.append(type);
+ }
+ }
+
+ private String encodeQuotedPrintable(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return "";
+ }
+ {
+ // Replace "\n" and "\r" with "\r\n".
+ StringBuilder tmpBuilder = new StringBuilder();
+ int length = str.length();
+ for (int i = 0; i < length; i++) {
+ char ch = str.charAt(i);
+ if (ch == '\r') {
+ if (i + 1 < length && str.charAt(i + 1) == '\n') {
+ i++;
+ }
+ tmpBuilder.append("\r\n");
+ } else if (ch == '\n') {
+ tmpBuilder.append("\r\n");
+ } else {
+ tmpBuilder.append(ch);
+ }
+ }
+ str = tmpBuilder.toString();
+ }
+
+ StringBuilder builder = new StringBuilder();
+ int index = 0;
+ int lineCount = 0;
+ byte[] strArray = null;
+
+ try {
+ strArray = str.getBytes(mCharsetString);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Charset " + mCharsetString + " cannot be used. "
+ + "Try default charset");
+ strArray = str.getBytes();
+ }
+ while (index < strArray.length) {
+ builder.append(String.format("=%02X", strArray[index]));
+ index += 1;
+ lineCount += 3;
+
+ if (lineCount >= 67) {
+ // Specification requires CRLF must be inserted before the
+ // length of the line
+ // becomes more than 76.
+ // Assuming that the next character is a multi-byte character,
+ // it will become
+ // 6 bytes.
+ // 76 - 6 - 3 = 67
+ builder.append("=\r\n");
+ lineCount = 0;
+ }
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index fef9dba..d87b002 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -15,43 +15,267 @@
*/
package android.pim.vcard;
+import java.util.HashMap;
+import java.util.Map;
+
/**
- * The class representing VCard related configurations
+ * The class representing VCard related configurations. Useful static methods are not in this class
+ * but in VCardUtils.
*/
public class VCardConfig {
- static final int LOG_LEVEL_NONE = 0;
- static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
- static final int LOG_LEVEL_SHOW_WARNING = 0x2;
- static final int LOG_LEVEL_VERBOSE =
+ // TODO: may be better to make the instance of this available and stop using static methods and
+ // one integer.
+
+ /* package */ static final int LOG_LEVEL_NONE = 0;
+ /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
+ /* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
+ /* package */ static final int LOG_LEVEL_VERBOSE =
LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
-
+
+ /* package */ static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
+
// Assumes that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
// decode the unicode to the original charset. If not, this setting will cause some bug.
public static final String DEFAULT_CHARSET = "iso-8859-1";
- // TODO: use this flag
- public static boolean IGNORE_CASE_EXCEPT_VALUE = true;
+ // TODO: make the other codes use this flag
+ public static final boolean IGNORE_CASE_EXCEPT_VALUE = true;
- protected static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
+ private static final int FLAG_V21 = 0;
+ private static final int FLAG_V30 = 1;
+
+ // 0x2 is reserved for the future use ...
+
+ public static final int NAME_ORDER_DEFAULT = 0;
+ public static final int NAME_ORDER_EUROPE = 0x4;
+ public static final int NAME_ORDER_JAPANESE = 0x8;
+ private static final int NAME_ORDER_MASK = 0xC;
+
+ // 0x10 is reserved for safety
- // Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and
- // space should be added between each element while it should not be in Japanese.
- // But unfortunately, we currently do not have the data and are not sure whether we should
- // support European version of name ordering.
- //
- // TODO: Implement the logic described above if we really need European version of
- // phonetic name handling. Also, adding the appropriate test case of vCard would be
- // highly appreciated.
- public static final int NAME_ORDER_TYPE_ENGLISH = 0;
- public static final int NAME_ORDER_TYPE_JAPANESE = 1;
-
- public static final int NAME_ORDER_TYPE_DEFAULT = NAME_ORDER_TYPE_ENGLISH;
+ private static final int FLAG_CHARSET_UTF8 = 0;
+ private static final int FLAG_CHARSET_SHIFT_JIS = 0x20;
/**
- * @hide temporal. may be deleted
+ * The flag indicating the vCard composer will add some "X-" properties used only in Android
+ * when the formal vCard specification does not have appropriate fields for that data.
+ *
+ * For example, Android accepts nickname information while vCard 2.1 does not.
+ * When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
+ * instead of just dropping it.
+ *
+ * vCard parser code automatically parses the field emitted even when this flag is off.
+ *
+ * Note that this flag does not assure all the information must be hold in the emitted vCard.
*/
+ private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
+
+ /**
+ * The flag indicating the vCard composer will add some "X-" properties seen in the
+ * vCard data emitted by the other softwares/devices when the formal vCard specification
+ * does not have appropriate field(s) for that data.
+ *
+ * One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
+ * for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
+ * non-Android devices/softwares. We chose to enable the vCard composer to use those
+ * defact properties since they are also useful for Android devices.
+ *
+ * Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
+ * allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
+ * in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
+ */
+ private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
+
+ /**
+ * The flag indicating some specific dialect seen in vcard of DoCoMo (one of Japanese
+ * mobile careers) should be used. This flag does not include any other information like
+ * that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
+ * dialect but the name order should be European", but it is not recommended.
+ */
+ private static final int FLAG_DOCOMO = 0x20000000;
+
+
+ // VCard types
+
+
+ /**
+ * General vCard format with the version 2.1. Uses UTF-8 for the charset.
+ * When composing a vCard entry, the US convension will be used.
+ *
+ * e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
+ * while in Japan, it should be "Prefix Family Middle Given Suffix".
+ */
+ public static final int VCARD_TYPE_V21_GENERIC =
+ (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
+
+ /**
+ * General vCard format with the version 3.0. Uses UTF-8 for the charset.
+ *
+ * Note that this type is not fully implemented, so probably some bugs remain especially
+ * in parsing part.
+ *
+ * TODO: implement this type.
+ */
+ public static final int VCARD_TYPE_V30_GENERIC =
+ (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
+
+ /**
+ * General vCard format with the version 2.1 with some Europe convension. Uses Utf-8.
+ * Currently, only name order is considered ("Prefix Middle Given Family Suffix")
+ */
+ public static final int VCARD_TYPE_V21_EUROPE =
+ (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
+
+ /**
+ * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8
+ */
+ public static final int VCARD_TYPE_V30_EUROPE =
+ (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
+
+ /**
+ * vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
+ * parsing/composing the vCard data.
+ */
+ public static final int VCARD_TYPE_V21_JAPANESE =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese";
+
+ /**
+ * vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
+ */
+ public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
+
+ /**
+ * vCard format for miscellaneous Japanese devices, using Shift_Jis for
+ * parsing/composing the vCard data.
+ */
+ public static final int VCARD_TYPE_V30_JAPANESE =
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese";
+
+ /**
+ * vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
+ */
+ public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
+
+ /**
+ * VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
+ * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
+ * No Android-specific property nor defact property is included.
+ */
+ public static final int VCARD_TYPE_DOCOMO =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS | FLAG_DOCOMO);
+
+ private static final String VCARD_TYPE_DOCOMO_STR = "docomo";
+
+ public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
+
+ private static final Map<String, Integer> VCARD_TYPES_MAP;
+
+ static {
+ VCARD_TYPES_MAP = new HashMap<String, Integer>();
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
+ }
+
+ public static int getVCardTypeFromString(String vcardTypeString) {
+ String loweredKey = vcardTypeString.toLowerCase();
+ if (VCARD_TYPES_MAP.containsKey(loweredKey)) {
+ return VCARD_TYPES_MAP.get(loweredKey);
+ } else {
+ // XXX: should return the value indicating the input is invalid?
+ return VCARD_TYPE_DEFAULT;
+ }
+ }
+
+ public static boolean isV30(int vcardType) {
+ return ((vcardType & FLAG_V30) != 0);
+ }
+
+ public static boolean usesQuotedPrintable(int vcardType) {
+ return !isV30(vcardType);
+ }
+
+ public static boolean isDoCoMo(int vcardType) {
+ return ((vcardType & FLAG_DOCOMO) != 0);
+ }
+
+ /**
+ * @return true if the device is Japanese and some Japanese convension is
+ * applied to creating "formatted" something like FORMATTED_ADDRESS.
+ */
+ public static boolean isJapaneseDevice(int vcardType) {
+ return ((vcardType == VCARD_TYPE_V21_JAPANESE) ||
+ (vcardType == VCARD_TYPE_V21_JAPANESE_UTF8) ||
+ (vcardType == VCARD_TYPE_V30_JAPANESE) ||
+ (vcardType == VCARD_TYPE_V30_JAPANESE_UTF8) ||
+ (vcardType == VCARD_TYPE_DOCOMO));
+ }
+
+ public static boolean usesShiftJis(int vcardType) {
+ return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0);
+ }
+
+ /**
+ * @return true when Japanese phonetic string must be converted to a string
+ * containing only half-width katakana. This method exists since Japanese mobile
+ * phones usually use only half-width katakana for expressing phonetic names and
+ * some devices are not ready for parsing other phonetic strings like hiragana and
+ * full-width katakana.
+ */
+ public static boolean needsToConvertPhoneticString(int vcardType) {
+ return (vcardType == VCARD_TYPE_DOCOMO);
+ }
+
+ public static int getNameOrderType(int vcardType) {
+ return vcardType & NAME_ORDER_MASK;
+ }
+
+ public static boolean usesAndroidSpecificProperty(int vcardType) {
+ return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
+ }
+
+ public static boolean usesDefactProperty(int vcardType) {
+ return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
+ }
+
+ public static boolean onlyOneNoteFieldIsAvailable(int vcardType) {
+ return vcardType == VCARD_TYPE_DOCOMO;
+ }
+
public static boolean showPerformanceLog() {
- return (LOG_LEVEL & LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
+ return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
}
private VCardConfig() {
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java
index 4025f6c..fd165e9 100644
--- a/core/java/android/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/pim/vcard/VCardDataBuilder.java
@@ -59,7 +59,7 @@
private String mTargetCharset;
private boolean mStrictLineBreakParsing;
- private int mNameOrderType;
+ private int mVCardType;
// Just for testing.
private long mTimePushIntoContentResolver;
@@ -67,23 +67,21 @@
private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
public VCardDataBuilder() {
- this(null, null, false, VCardConfig.NAME_ORDER_TYPE_DEFAULT);
+ this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC);
}
/**
* @hide
*/
- public VCardDataBuilder(int nameOrderType) {
- this(null, null, false, nameOrderType);
+ public VCardDataBuilder(int vcardType) {
+ this(null, null, false, vcardType);
}
-
+
/**
* @hide
*/
- public VCardDataBuilder(String charset,
- boolean strictLineBreakParsing,
- int nameOrderType) {
- this(null, charset, strictLineBreakParsing, nameOrderType);
+ public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) {
+ this(null, charset, strictLineBreakParsing, vcardType);
}
/**
@@ -92,7 +90,7 @@
public VCardDataBuilder(String sourceCharset,
String targetCharset,
boolean strictLineBreakParsing,
- int nameOrderType) {
+ int vcardType) {
if (sourceCharset != null) {
mSourceCharset = sourceCharset;
} else {
@@ -104,7 +102,7 @@
mTargetCharset = TARGET_CHARSET;
}
mStrictLineBreakParsing = strictLineBreakParsing;
- mNameOrderType = nameOrderType;
+ mVCardType = vcardType;
}
public void addEntryHandler(EntryHandler entryHandler) {
@@ -112,11 +110,14 @@
}
public void start() {
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onParsingStart();
+ }
}
public void end() {
for (EntryHandler entryHandler : mEntryHandlers) {
- entryHandler.onFinal();
+ entryHandler.onParsingEnd();
}
}
@@ -135,7 +136,7 @@
Log.e(LOG_TAG, "This is not VCARD!");
}
- mCurrentContactStruct = new ContactStruct(mNameOrderType);
+ mCurrentContactStruct = new ContactStruct(mVCardType);
}
public void endRecord() {
@@ -164,8 +165,7 @@
public void propertyParamType(String type) {
if (mParamType != null) {
- Log.e(LOG_TAG,
- "propertyParamType() is called more than once " +
+ Log.e(LOG_TAG, "propertyParamType() is called more than once " +
"before propertyParamValue() is called");
}
mParamType = type;
@@ -173,6 +173,7 @@
public void propertyParamValue(String value) {
if (mParamType == null) {
+ // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
mParamType = "TYPE";
}
mCurrentProperty.addParameter(mParamType, value);
@@ -297,7 +298,7 @@
String charset =
((charsetCollection != null) ? charsetCollection.iterator().next() : null);
String targetCharset = CharsetUtils.nameForDefaultVendor(charset);
-
+
final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
String encoding =
((encodingCollection != null) ? encodingCollection.iterator().next() : null);
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index 17a138f..974fca8 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -34,7 +34,7 @@
* This class is used to parse vcard. Please refer to vCard Specification 2.1.
*/
public class VCardParser_V21 extends VCardParser {
- private static final String LOG_TAG = "VCardParser_V21";
+ private static final String LOG_TAG = "vcard.VCardParser_V21";
/** Store the known-type */
private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
@@ -58,8 +58,10 @@
"VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
"BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
- // Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
- // We allow it for safety...
+ /**
+ * Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
+ * We allow it for safety...
+ */
private static final HashSet<String> sAvailableEncodingV21 =
new HashSet<String>(Arrays.asList(
"7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
@@ -70,7 +72,10 @@
/** The builder to build parsed data */
protected VCardBuilder mBuilder = null;
- /** The encoding type */
+ /**
+ * The encoding type. "Encoding" in vCard is different from "Charset".
+ * e.g. 7BIT, 8BIT, QUOTED-PRINTABLE.
+ */
protected String mEncoding = null;
protected final String sDefaultEncoding = "8BIT";
@@ -88,17 +93,17 @@
// Just for debugging
private long mTimeTotal;
- private long mTimeStartRecord;
- private long mTimeEndRecord;
+ private long mTimeReadStartRecord;
+ private long mTimeReadEndRecord;
private long mTimeStartProperty;
private long mTimeEndProperty;
private long mTimeParseItems;
- private long mTimeParseItem1;
- private long mTimeParseItem2;
- private long mTimeParseItem3;
- private long mTimeHandlePropertyValue1;
- private long mTimeHandlePropertyValue2;
- private long mTimeHandlePropertyValue3;
+ private long mTimeParseLineAndHandleGroup;
+ private long mTimeParsePropertyValues;
+ private long mTimeParseAdrOrgN;
+ private long mTimeHandleMiscPropertyValue;
+ private long mTimeHandleQuotedPrintable;
+ private long mTimeHandleBase64;
/**
* Create a new VCard parser.
@@ -213,7 +218,7 @@
if (mBuilder != null) {
start = System.currentTimeMillis();
mBuilder.startRecord("VCARD");
- mTimeStartRecord += System.currentTimeMillis() - start;
+ mTimeReadStartRecord += System.currentTimeMillis() - start;
}
start = System.currentTimeMillis();
parseItems();
@@ -222,7 +227,7 @@
if (mBuilder != null) {
start = System.currentTimeMillis();
mBuilder.endRecord();
- mTimeEndRecord += System.currentTimeMillis() - start;
+ mTimeReadEndRecord += System.currentTimeMillis() - start;
}
return true;
}
@@ -250,26 +255,6 @@
// Though vCard 2.1/3.0 specification does not allow lower cases,
// some data may have them, so we allow it (Actually, previous code
// had explicitly allowed "BEGIN:vCard" though there's no example).
- //
- // TODO: ignore non vCard entry (e.g. vcalendar).
- // XXX: Not sure, but according to VDataBuilder.java, vcalendar
- // entry
- // may be nested. Just seeking "END:SOMETHING" may not be enough.
- // e.g.
- // BEGIN:VCARD
- // ... (Valid. Must parse this)
- // END:VCARD
- // BEGIN:VSOMETHING
- // ... (Must ignore this)
- // BEGIN:VSOMETHING2
- // ... (Must ignore this)
- // END:VSOMETHING2
- // ... (Must ignore this!)
- // END:VSOMETHING
- // BEGIN:VCARD
- // ... (Valid. Must parse this)
- // END:VCARD
- // INVALID_STRING (VCardException should be thrown)
if (length == 2 &&
strArray[0].trim().equalsIgnoreCase("BEGIN") &&
strArray[1].trim().equalsIgnoreCase("VCARD")) {
@@ -367,11 +352,11 @@
}
/**
- * item = [groups "."] name [params] ":" value CRLF
- * / [groups "."] "ADR" [params] ":" addressparts CRLF
- * / [groups "."] "ORG" [params] ":" orgparts CRLF
- * / [groups "."] "N" [params] ":" nameparts CRLF
- * / [groups "."] "AGENT" [params] ":" vcard CRLF
+ * item = [groups "."] name [params] ":" value CRLF
+ * / [groups "."] "ADR" [params] ":" addressparts CRLF
+ * / [groups "."] "ORG" [params] ":" orgparts CRLF
+ * / [groups "."] "N" [params] ":" nameparts CRLF
+ * / [groups "."] "AGENT" [params] ":" vcard CRLF
*/
protected boolean parseItem() throws IOException, VCardException {
mEncoding = sDefaultEncoding;
@@ -389,14 +374,13 @@
String propertyName = propertyNameAndValue[0].toUpperCase();
String propertyValue = propertyNameAndValue[1];
- mTimeParseItem1 += System.currentTimeMillis() - start;
+ mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
- if (propertyName.equals("ADR") ||
- propertyName.equals("ORG") ||
+ if (propertyName.equals("ADR") || propertyName.equals("ORG") ||
propertyName.equals("N")) {
start = System.currentTimeMillis();
handleMultiplePropertyValue(propertyName, propertyValue);
- mTimeParseItem3 += System.currentTimeMillis() - start;
+ mTimeParseAdrOrgN += System.currentTimeMillis() - start;
return false;
} else if (propertyName.equals("AGENT")) {
handleAgent(propertyValue);
@@ -408,14 +392,13 @@
} else {
throw new VCardException("Unknown BEGIN type: " + propertyValue);
}
- } else if (propertyName.equals("VERSION") &&
- !propertyValue.equals(getVersion())) {
+ } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersion())) {
throw new VCardVersionException("Incompatible version: " +
propertyValue + " != " + getVersion());
}
start = System.currentTimeMillis();
handlePropertyValue(propertyName, propertyValue);
- mTimeParseItem2 += System.currentTimeMillis() - start;
+ mTimeParsePropertyValues += System.currentTimeMillis() - start;
return false;
}
@@ -542,7 +525,7 @@
}
/**
- * ptypeval = knowntype / "X-" word
+ * ptypeval = knowntype / "X-" word
*/
protected void handleType(String ptypeval) {
String upperTypeValue = ptypeval;
@@ -637,8 +620,7 @@
}
}
- protected void handlePropertyValue(
- String propertyName, String propertyValue) throws
+ protected void handlePropertyValue(String propertyName, String propertyValue) throws
IOException, VCardException {
if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
long start = System.currentTimeMillis();
@@ -648,7 +630,7 @@
v.add(result);
mBuilder.propertyValues(v);
}
- mTimeHandlePropertyValue2 += System.currentTimeMillis() - start;
+ mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
} else if (mEncoding.equalsIgnoreCase("BASE64") ||
mEncoding.equalsIgnoreCase("B")) {
long start = System.currentTimeMillis();
@@ -667,7 +649,7 @@
mBuilder.propertyValues(null);
}
}
- mTimeHandlePropertyValue3 += System.currentTimeMillis() - start;
+ mTimeHandleBase64 += System.currentTimeMillis() - start;
} else {
if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
|| mEncoding.equalsIgnoreCase("8BIT")
@@ -681,7 +663,7 @@
v.add(maybeUnescapeText(propertyValue));
mBuilder.propertyValues(v);
}
- mTimeHandlePropertyValue1 += System.currentTimeMillis() - start;
+ mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
}
}
@@ -770,15 +752,15 @@
* We are not sure whether we should add "\" CRLF to each value.
* For now, we exclude them.
*/
- protected void handleMultiplePropertyValue(
- String propertyName, String propertyValue) throws IOException, VCardException {
- // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some data have it.
+ protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
+ throws IOException, VCardException {
+ // vCard 2.1 does not allow QUOTED-PRINTABLE here,
+ // but some softwares/devices emit such data.
if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
propertyValue = getQuotedPrintable(propertyValue);
}
if (mBuilder != null) {
- // TODO: limit should be set in accordance with propertyName?
StringBuilder builder = new StringBuilder();
ArrayList<String> list = new ArrayList<String>();
int length = propertyValue.length();
@@ -786,7 +768,7 @@
char ch = propertyValue.charAt(i);
if (ch == '\\' && i < length - 1) {
char nextCh = propertyValue.charAt(i + 1);
- String unescapedString = maybeUnescape(nextCh);
+ String unescapedString = maybeUnescapeCharacter(nextCh);
if (unescapedString != null) {
builder.append(unescapedString);
i++;
@@ -819,7 +801,6 @@
throw new VCardNotSupportedException("AGENT Property is not supported now.");
/* This is insufficient support. Also, AGENT Property is very rare.
Ignore it for now.
- TODO: fix this.
String[] strArray = propertyValue.split(":", 2);
if (!(strArray.length == 2 ||
@@ -843,7 +824,7 @@
* Returns unescaped String if the character should be unescaped. Return null otherwise.
* e.g. In vCard 2.1, "\;" should be unescaped into ";" while "\x" should not be.
*/
- protected String maybeUnescape(char ch) {
+ protected String maybeUnescapeCharacter(char ch) {
// Original vCard 2.1 specification does not allow transformation
// "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
// this class allowed them, so keep it as is.
@@ -863,17 +844,11 @@
@Override
public boolean parse(InputStream is, String charset, VCardBuilder builder)
throws IOException, VCardException {
- // TODO: make this count error entries instead of just throwing VCardException.
-
- {
- // TODO: If we really need to allow only CRLF as line break,
- // we will have to develop our own BufferedReader().
- final InputStreamReader tmpReader = new InputStreamReader(is, charset);
- if (VCardConfig.showPerformanceLog()) {
- mReader = new CustomBufferedReader(tmpReader);
- } else {
- mReader = new BufferedReader(tmpReader);
- }
+ final InputStreamReader tmpReader = new InputStreamReader(is, charset);
+ if (VCardConfig.showPerformanceLog()) {
+ mReader = new CustomBufferedReader(tmpReader);
+ } else {
+ mReader = new BufferedReader(tmpReader);
}
mBuilder = builder;
@@ -903,21 +878,26 @@
}
private void showPerformanceInfo() {
- Log.d(LOG_TAG, "total parsing time: " + mTimeTotal + " ms");
+ Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms");
if (mReader instanceof CustomBufferedReader) {
- Log.d(LOG_TAG, "total readLine time: " +
+ Log.d(LOG_TAG, "Total readLine time: " +
((CustomBufferedReader)mReader).getTotalmillisecond() + " ms");
}
- Log.d(LOG_TAG, "mTimeStartRecord: " + mTimeStartRecord + " ms");
- Log.d(LOG_TAG, "mTimeEndRecord: " + mTimeEndRecord + " ms");
- Log.d(LOG_TAG, "mTimeParseItem1: " + mTimeParseItem1 + " ms");
- Log.d(LOG_TAG, "mTimeParseItem2: " + mTimeParseItem2 + " ms");
- Log.d(LOG_TAG, "mTimeParseItem3: " + mTimeParseItem3 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue1: " + mTimeHandlePropertyValue1 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue2: " + mTimeHandlePropertyValue2 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue3: " + mTimeHandlePropertyValue3 + " ms");
+ Log.d(LOG_TAG, "Time for handling the beggining of the record: " +
+ mTimeReadStartRecord + " ms");
+ Log.d(LOG_TAG, "Time for handling the end of the record: " +
+ mTimeReadEndRecord + " ms");
+ Log.d(LOG_TAG, "Time for parsing line, and handling group: " +
+ mTimeParseLineAndHandleGroup + " ms");
+ Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
+ Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
+ Log.d(LOG_TAG, "Time for handling normal property values: " +
+ mTimeHandleMiscPropertyValue + " ms");
+ Log.d(LOG_TAG, "Time for handling Quoted-Printable: " +
+ mTimeHandleQuotedPrintable + " ms");
+ Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
}
-
+
private boolean isLetter(char ch) {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
return true;
diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java
index 634d9f5..475be4e 100644
--- a/core/java/android/pim/vcard/VCardParser_V30.java
+++ b/core/java/android/pim/vcard/VCardParser_V30.java
@@ -27,7 +27,7 @@
* Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
*/
public class VCardParser_V30 extends VCardParser_V21 {
- private static final String LOG_TAG = "VCardParser_V30";
+ private static final String LOG_TAG = "vcard.VCardParser_V30";
private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
Arrays.asList(
@@ -49,7 +49,7 @@
@Override
protected String getVersion() {
- return "3.0";
+ return Constants.VERSION_V30;
}
@Override
@@ -284,7 +284,7 @@
if (ch == '\\' && i < length - 1) {
char next_ch = text.charAt(++i);
if (next_ch == 'n' || next_ch == 'N') {
- builder.append("\r\n");
+ builder.append("\n");
} else {
builder.append(next_ch);
}
@@ -296,9 +296,9 @@
}
@Override
- protected String maybeUnescape(char ch) {
+ protected String maybeUnescapeCharacter(char ch) {
if (ch == 'n' || ch == 'N') {
- return "\r\n";
+ return "\n";
} else {
return String.valueOf(ch);
}
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
new file mode 100644
index 0000000..b7b706f
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -0,0 +1,764 @@
+/*
+ * 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.pim.vcard;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.text.TextUtils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utilities for VCard handling codes.
+ */
+public class VCardUtils {
+ /*
+ * TODO: some of methods in this class should be placed to the more appropriate place...
+ */
+
+ // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
+ // converted to two attribute Strings. These only contain some minor fields valid in both
+ // vCard and current (as of 2009-08-07) Contacts structure.
+ private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
+ private static final Set<String> sPhoneTypesSetUnknownToContacts;
+
+ private static final Map<String, Integer> sKnownPhoneTypesMap_StoI;
+
+ static {
+ sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
+ sKnownPhoneTypesMap_StoI = new HashMap<String, Integer>();
+
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, Constants.ATTR_TYPE_CAR);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR);
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, Constants.ATTR_TYPE_PAGER);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER);
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, Constants.ATTR_TYPE_ISDN);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN);
+
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE);
+
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_OTHER, Phone.TYPE_OTHER);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_CALLBACK, Phone.TYPE_CALLBACK);
+ sKnownPhoneTypesMap_StoI.put(
+ Constants.ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_RADIO, Phone.TYPE_RADIO);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TELEX, Phone.TYPE_TELEX);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TTY_TDD, Phone.TYPE_TTY_TDD);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_ASSISTANT, Phone.TYPE_ASSISTANT);
+
+ sPhoneTypesSetUnknownToContacts = new HashSet<String>();
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MODEM);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MSG);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_BBS);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO);
+ }
+
+ public static String getPhoneAttributeString(int type) {
+ return sKnownPhoneTypesMap_ItoS.get(type);
+ }
+
+ /**
+ * Returns Interger when the given types can be parsed as known type. Returns String object
+ * when not, which should be set to label.
+ */
+ public static Object getPhoneTypeFromStrings(Collection<String> types) {
+ int type = -1;
+ String label = null;
+ boolean isFax = false;
+ boolean hasPref = false;
+
+ if (types != null) {
+ for (String typeString : types) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
+ hasPref = true;
+ } else if (typeString.equals(Constants.ATTR_TYPE_FAX)) {
+ isFax = true;
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
+ Integer tmp = sKnownPhoneTypesMap_StoI.get(typeString);
+ if (tmp != null) {
+ type = tmp;
+ } else if (type < 0) {
+ type = Phone.TYPE_CUSTOM;
+ label = typeString;
+ }
+ }
+ }
+ }
+ if (type < 0) {
+ if (hasPref) {
+ type = Phone.TYPE_MAIN;
+ } else {
+ // default to TYPE_HOME
+ type = Phone.TYPE_HOME;
+ }
+ }
+ if (isFax) {
+ if (type == Phone.TYPE_HOME) {
+ type = Phone.TYPE_FAX_HOME;
+ } else if (type == Phone.TYPE_WORK) {
+ type = Phone.TYPE_FAX_WORK;
+ } else if (type == Phone.TYPE_OTHER) {
+ type = Phone.TYPE_OTHER_FAX;
+ }
+ }
+ if (type == Phone.TYPE_CUSTOM) {
+ return label;
+ } else {
+ return type;
+ }
+ }
+
+ public static boolean isValidPhoneAttribute(String phoneAttribute, int vcardType) {
+ // TODO: check the following.
+ // - it may violate vCard spec
+ // - it may contain non-ASCII characters
+ //
+ // TODO: use vcardType
+ return (phoneAttribute.startsWith("X-") || phoneAttribute.startsWith("x-") ||
+ sPhoneTypesSetUnknownToContacts.contains(phoneAttribute));
+ }
+
+ public static String[] sortNameElements(int vcardType,
+ String familyName, String middleName, String givenName) {
+ String[] list = new String[3];
+ switch (VCardConfig.getNameOrderType(vcardType)) {
+ case VCardConfig.NAME_ORDER_JAPANESE:
+ // TODO: Should handle Ascii case?
+ list[0] = familyName;
+ list[1] = middleName;
+ list[2] = givenName;
+ break;
+ case VCardConfig.NAME_ORDER_EUROPE:
+ list[0] = middleName;
+ list[1] = givenName;
+ list[2] = familyName;
+ break;
+ default:
+ list[0] = givenName;
+ list[1] = middleName;
+ list[2] = familyName;
+ break;
+ }
+ return list;
+ }
+
+ /**
+ * Inserts postal data into the builder object.
+ *
+ * Note that the data structure of ContactsContract is different from that defined in vCard.
+ * So some conversion may be performed in this method. See also
+ * {{@link #getVCardPostalElements(ContentValues)}
+ */
+ public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
+ final ContentProviderOperation.Builder builder,
+ final ContactStruct.PostalData postalData) {
+ builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+
+ builder.withValue(StructuredPostal.TYPE, postalData.type);
+ if (postalData.type == StructuredPostal.TYPE_CUSTOM) {
+ builder.withValue(StructuredPostal.LABEL, postalData.label);
+ }
+
+ builder.withValue(StructuredPostal.POBOX, postalData.pobox);
+ // Extended address is dropped since there's no relevant entry in ContactsContract.
+ builder.withValue(StructuredPostal.STREET, postalData.street);
+ builder.withValue(StructuredPostal.CITY, postalData.localty);
+ builder.withValue(StructuredPostal.REGION, postalData.region);
+ builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode);
+ builder.withValue(StructuredPostal.COUNTRY, postalData.country);
+
+ builder.withValue(StructuredPostal.FORMATTED_ADDRESS,
+ postalData.getFormattedAddress(vcardType));
+ if (postalData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ }
+
+ /**
+ * Returns String[] containing address information based on vCard spec
+ * (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name).
+ * All String objects are non-null ("" is used when the relevant data is empty).
+ *
+ * Note that the data structure of ContactsContract is different from that defined in vCard.
+ * So some conversion may be performed in this method. See also
+ * {{@link #insertStructuredPostalDataUsingContactsStruct(int,
+ * android.content.ContentProviderOperation.Builder,
+ * android.pim.vcard.ContactStruct.PostalData)}
+ */
+ public static String[] getVCardPostalElements(ContentValues contentValues) {
+ String[] dataArray = new String[7];
+ dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX);
+ if (dataArray[0] == null) {
+ dataArray[0] = "";
+ }
+ // Extended addr. There's no relevant data in ContactsContract.
+ dataArray[1] = "";
+ dataArray[2] = contentValues.getAsString(StructuredPostal.STREET);
+ if (dataArray[2] == null) {
+ dataArray[2] = "";
+ }
+ // Assume that localty == city
+ dataArray[3] = contentValues.getAsString(StructuredPostal.CITY);
+ if (dataArray[3] == null) {
+ dataArray[3] = "";
+ }
+ String region = contentValues.getAsString(StructuredPostal.REGION);
+ if (!TextUtils.isEmpty(region)) {
+ dataArray[4] = region;
+ } else {
+ dataArray[4] = "";
+ }
+ dataArray[5] = contentValues.getAsString(StructuredPostal.POSTCODE);
+ if (dataArray[5] == null) {
+ dataArray[5] = "";
+ }
+ dataArray[6] = contentValues.getAsString(StructuredPostal.COUNTRY);
+ if (dataArray[6] == null) {
+ dataArray[6] = "";
+ }
+
+ return dataArray;
+ }
+
+ public static String constructNameFromElements(int nameOrderType,
+ String familyName, String middleName, String givenName) {
+ return constructNameFromElements(nameOrderType, familyName, middleName, givenName,
+ null, null);
+ }
+
+ public static String constructNameFromElements(int nameOrderType,
+ String familyName, String middleName, String givenName,
+ String prefix, String suffix) {
+ StringBuilder builder = new StringBuilder();
+ String[] nameList = sortNameElements(nameOrderType,
+ familyName, middleName, givenName);
+ boolean first = true;
+ if (!TextUtils.isEmpty(prefix)) {
+ first = false;
+ builder.append(prefix);
+ }
+ for (String namePart : nameList) {
+ if (!TextUtils.isEmpty(namePart)) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(' ');
+ }
+ builder.append(namePart);
+ }
+ }
+ if (!TextUtils.isEmpty(suffix)) {
+ if (!first) {
+ builder.append(' ');
+ }
+ builder.append(suffix);
+ }
+ return builder.toString();
+ }
+
+ public static boolean containsOnlyAscii(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return true;
+ }
+
+ final int length = str.length();
+ final int asciiFirst = 0x20;
+ final int asciiLast = 0x126;
+ for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
+ int c = str.codePointAt(i);
+ if (c < asciiFirst || asciiLast < c) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This is useful since vCard 3.0 often requires the ("X-") properties and groups
+ * should contain only alphabets, digits, and hyphen.
+ *
+ * Note: It is already known some devices (wrongly) outputs properties with characters
+ * which should not be in the field. One example is "X-GOOGLE TALK". We appreciate
+ * such kind of input but must never output it unless the target is very specific
+ * to the device which is able to parse the malformed input.
+ */
+ public static boolean containsOnlyAlphaDigitHyphen(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return true;
+ }
+
+ final int lowerAlphabetFirst = 0x41; // included ('A')
+ final int lowerAlphabetLast = 0x5b; // not included ('[')
+ final int upperAlphabetFirst = 0x61; // included ('a')
+ final int upperAlphabetLast = 0x7b; // included ('{')
+ final int digitFirst = 0x30; // included ('0')
+ final int digitLast = 0x39; // included ('9')
+ final int hyphen = '-';
+ final int length = str.length();
+ for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
+ int codepoint = str.codePointAt(i);
+ if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetLast) ||
+ (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetLast) ||
+ (digitFirst <= codepoint && codepoint < digitLast) ||
+ (codepoint == hyphen))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // TODO: Replace wth the method in Base64 class.
+ private static char PAD = '=';
+ private static final char[] ENCODE64 = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+ };
+
+ static public String encodeBase64(byte[] data) {
+ if (data == null) {
+ return "";
+ }
+
+ char[] charBuffer = new char[(data.length + 2) / 3 * 4];
+ int position = 0;
+ int _3byte = 0;
+ for (int i=0; i<data.length-2; i+=3) {
+ _3byte = ((data[i] & 0xFF) << 16) + ((data[i+1] & 0xFF) << 8) + (data[i+2] & 0xFF);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
+ charBuffer[position++] = ENCODE64[_3byte & 0x3F];
+ }
+ switch(data.length % 3) {
+ case 1: // [111111][11 0000][0000 00][000000]
+ _3byte = ((data[data.length-1] & 0xFF) << 16);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = PAD;
+ charBuffer[position++] = PAD;
+ break;
+ case 2: // [111111][11 1111][1111 00][000000]
+ _3byte = ((data[data.length-2] & 0xFF) << 16) + ((data[data.length-1] & 0xFF) << 8);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
+ charBuffer[position++] = PAD;
+ break;
+ }
+
+ return new String(charBuffer);
+ }
+
+ static public String toHalfWidthString(String orgString) {
+ if (TextUtils.isEmpty(orgString)) {
+ return null;
+ }
+ StringBuilder builder = new StringBuilder();
+ int length = orgString.length();
+ for (int i = 0; i < length; i++) {
+ // All Japanese character is able to be expressed by char.
+ // Do not need to use String#codepPointAt().
+ char ch = orgString.charAt(i);
+ CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
+ if (halfWidthText != null) {
+ builder.append(halfWidthText);
+ } else {
+ builder.append(ch);
+ }
+ }
+ return builder.toString();
+ }
+
+ private VCardUtils() {
+ }
+}
+
+/**
+ * TextUtils especially for Japanese.
+ * TODO: make this in android.text in the future
+ */
+class JapaneseUtils {
+ static private final Map<Character, String> sHalfWidthMap =
+ new HashMap<Character, String>();
+
+ static {
+ // There's no logical mapping rule in Unicode. Sigh.
+ sHalfWidthMap.put('\u3001', "\uFF64");
+ sHalfWidthMap.put('\u3002', "\uFF61");
+ sHalfWidthMap.put('\u300C', "\uFF62");
+ sHalfWidthMap.put('\u300D', "\uFF63");
+ sHalfWidthMap.put('\u301C', "~");
+ sHalfWidthMap.put('\u3041', "\uFF67");
+ sHalfWidthMap.put('\u3042', "\uFF71");
+ sHalfWidthMap.put('\u3043', "\uFF68");
+ sHalfWidthMap.put('\u3044', "\uFF72");
+ sHalfWidthMap.put('\u3045', "\uFF69");
+ sHalfWidthMap.put('\u3046', "\uFF73");
+ sHalfWidthMap.put('\u3047', "\uFF6A");
+ sHalfWidthMap.put('\u3048', "\uFF74");
+ sHalfWidthMap.put('\u3049', "\uFF6B");
+ sHalfWidthMap.put('\u304A', "\uFF75");
+ sHalfWidthMap.put('\u304B', "\uFF76");
+ sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
+ sHalfWidthMap.put('\u304D', "\uFF77");
+ sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
+ sHalfWidthMap.put('\u304F', "\uFF78");
+ sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
+ sHalfWidthMap.put('\u3051', "\uFF79");
+ sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
+ sHalfWidthMap.put('\u3053', "\uFF7A");
+ sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
+ sHalfWidthMap.put('\u3055', "\uFF7B");
+ sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
+ sHalfWidthMap.put('\u3057', "\uFF7C");
+ sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
+ sHalfWidthMap.put('\u3059', "\uFF7D");
+ sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
+ sHalfWidthMap.put('\u305B', "\uFF7E");
+ sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
+ sHalfWidthMap.put('\u305D', "\uFF7F");
+ sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
+ sHalfWidthMap.put('\u305F', "\uFF80");
+ sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
+ sHalfWidthMap.put('\u3061', "\uFF81");
+ sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
+ sHalfWidthMap.put('\u3063', "\uFF6F");
+ sHalfWidthMap.put('\u3064', "\uFF82");
+ sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
+ sHalfWidthMap.put('\u3066', "\uFF83");
+ sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
+ sHalfWidthMap.put('\u3068', "\uFF84");
+ sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
+ sHalfWidthMap.put('\u306A', "\uFF85");
+ sHalfWidthMap.put('\u306B', "\uFF86");
+ sHalfWidthMap.put('\u306C', "\uFF87");
+ sHalfWidthMap.put('\u306D', "\uFF88");
+ sHalfWidthMap.put('\u306E', "\uFF89");
+ sHalfWidthMap.put('\u306F', "\uFF8A");
+ sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
+ sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
+ sHalfWidthMap.put('\u3072', "\uFF8B");
+ sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
+ sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
+ sHalfWidthMap.put('\u3075', "\uFF8C");
+ sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
+ sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
+ sHalfWidthMap.put('\u3078', "\uFF8D");
+ sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
+ sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
+ sHalfWidthMap.put('\u307B', "\uFF8E");
+ sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
+ sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
+ sHalfWidthMap.put('\u307E', "\uFF8F");
+ sHalfWidthMap.put('\u307F', "\uFF90");
+ sHalfWidthMap.put('\u3080', "\uFF91");
+ sHalfWidthMap.put('\u3081', "\uFF92");
+ sHalfWidthMap.put('\u3082', "\uFF93");
+ sHalfWidthMap.put('\u3083', "\uFF6C");
+ sHalfWidthMap.put('\u3084', "\uFF94");
+ sHalfWidthMap.put('\u3085', "\uFF6D");
+ sHalfWidthMap.put('\u3086', "\uFF95");
+ sHalfWidthMap.put('\u3087', "\uFF6E");
+ sHalfWidthMap.put('\u3088', "\uFF96");
+ sHalfWidthMap.put('\u3089', "\uFF97");
+ sHalfWidthMap.put('\u308A', "\uFF98");
+ sHalfWidthMap.put('\u308B', "\uFF99");
+ sHalfWidthMap.put('\u308C', "\uFF9A");
+ sHalfWidthMap.put('\u308D', "\uFF9B");
+ sHalfWidthMap.put('\u308E', "\uFF9C");
+ sHalfWidthMap.put('\u308F', "\uFF9C");
+ sHalfWidthMap.put('\u3090', "\uFF72");
+ sHalfWidthMap.put('\u3091', "\uFF74");
+ sHalfWidthMap.put('\u3092', "\uFF66");
+ sHalfWidthMap.put('\u3093', "\uFF9D");
+ sHalfWidthMap.put('\u309B', "\uFF9E");
+ sHalfWidthMap.put('\u309C', "\uFF9F");
+ sHalfWidthMap.put('\u30A1', "\uFF67");
+ sHalfWidthMap.put('\u30A2', "\uFF71");
+ sHalfWidthMap.put('\u30A3', "\uFF68");
+ sHalfWidthMap.put('\u30A4', "\uFF72");
+ sHalfWidthMap.put('\u30A5', "\uFF69");
+ sHalfWidthMap.put('\u30A6', "\uFF73");
+ sHalfWidthMap.put('\u30A7', "\uFF6A");
+ sHalfWidthMap.put('\u30A8', "\uFF74");
+ sHalfWidthMap.put('\u30A9', "\uFF6B");
+ sHalfWidthMap.put('\u30AA', "\uFF75");
+ sHalfWidthMap.put('\u30AB', "\uFF76");
+ sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
+ sHalfWidthMap.put('\u30AD', "\uFF77");
+ sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
+ sHalfWidthMap.put('\u30AF', "\uFF78");
+ sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
+ sHalfWidthMap.put('\u30B1', "\uFF79");
+ sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
+ sHalfWidthMap.put('\u30B3', "\uFF7A");
+ sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
+ sHalfWidthMap.put('\u30B5', "\uFF7B");
+ sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
+ sHalfWidthMap.put('\u30B7', "\uFF7C");
+ sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
+ sHalfWidthMap.put('\u30B9', "\uFF7D");
+ sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
+ sHalfWidthMap.put('\u30BB', "\uFF7E");
+ sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
+ sHalfWidthMap.put('\u30BD', "\uFF7F");
+ sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
+ sHalfWidthMap.put('\u30BF', "\uFF80");
+ sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
+ sHalfWidthMap.put('\u30C1', "\uFF81");
+ sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
+ sHalfWidthMap.put('\u30C3', "\uFF6F");
+ sHalfWidthMap.put('\u30C4', "\uFF82");
+ sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
+ sHalfWidthMap.put('\u30C6', "\uFF83");
+ sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
+ sHalfWidthMap.put('\u30C8', "\uFF84");
+ sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
+ sHalfWidthMap.put('\u30CA', "\uFF85");
+ sHalfWidthMap.put('\u30CB', "\uFF86");
+ sHalfWidthMap.put('\u30CC', "\uFF87");
+ sHalfWidthMap.put('\u30CD', "\uFF88");
+ sHalfWidthMap.put('\u30CE', "\uFF89");
+ sHalfWidthMap.put('\u30CF', "\uFF8A");
+ sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
+ sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
+ sHalfWidthMap.put('\u30D2', "\uFF8B");
+ sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
+ sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
+ sHalfWidthMap.put('\u30D5', "\uFF8C");
+ sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
+ sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
+ sHalfWidthMap.put('\u30D8', "\uFF8D");
+ sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
+ sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
+ sHalfWidthMap.put('\u30DB', "\uFF8E");
+ sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
+ sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
+ sHalfWidthMap.put('\u30DE', "\uFF8F");
+ sHalfWidthMap.put('\u30DF', "\uFF90");
+ sHalfWidthMap.put('\u30E0', "\uFF91");
+ sHalfWidthMap.put('\u30E1', "\uFF92");
+ sHalfWidthMap.put('\u30E2', "\uFF93");
+ sHalfWidthMap.put('\u30E3', "\uFF6C");
+ sHalfWidthMap.put('\u30E4', "\uFF94");
+ sHalfWidthMap.put('\u30E5', "\uFF6D");
+ sHalfWidthMap.put('\u30E6', "\uFF95");
+ sHalfWidthMap.put('\u30E7', "\uFF6E");
+ sHalfWidthMap.put('\u30E8', "\uFF96");
+ sHalfWidthMap.put('\u30E9', "\uFF97");
+ sHalfWidthMap.put('\u30EA', "\uFF98");
+ sHalfWidthMap.put('\u30EB', "\uFF99");
+ sHalfWidthMap.put('\u30EC', "\uFF9A");
+ sHalfWidthMap.put('\u30ED', "\uFF9B");
+ sHalfWidthMap.put('\u30EE', "\uFF9C");
+ sHalfWidthMap.put('\u30EF', "\uFF9C");
+ sHalfWidthMap.put('\u30F0', "\uFF72");
+ sHalfWidthMap.put('\u30F1', "\uFF74");
+ sHalfWidthMap.put('\u30F2', "\uFF66");
+ sHalfWidthMap.put('\u30F3', "\uFF9D");
+ sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
+ sHalfWidthMap.put('\u30F5', "\uFF76");
+ sHalfWidthMap.put('\u30F6', "\uFF79");
+ sHalfWidthMap.put('\u30FB', "\uFF65");
+ sHalfWidthMap.put('\u30FC', "\uFF70");
+ sHalfWidthMap.put('\uFF01', "!");
+ sHalfWidthMap.put('\uFF02', "\"");
+ sHalfWidthMap.put('\uFF03', "#");
+ sHalfWidthMap.put('\uFF04', "$");
+ sHalfWidthMap.put('\uFF05', "%");
+ sHalfWidthMap.put('\uFF06', "&");
+ sHalfWidthMap.put('\uFF07', "'");
+ sHalfWidthMap.put('\uFF08', "(");
+ sHalfWidthMap.put('\uFF09', ")");
+ sHalfWidthMap.put('\uFF0A', "*");
+ sHalfWidthMap.put('\uFF0B', "+");
+ sHalfWidthMap.put('\uFF0C', ",");
+ sHalfWidthMap.put('\uFF0D', "-");
+ sHalfWidthMap.put('\uFF0E', ".");
+ sHalfWidthMap.put('\uFF0F', "/");
+ sHalfWidthMap.put('\uFF10', "0");
+ sHalfWidthMap.put('\uFF11', "1");
+ sHalfWidthMap.put('\uFF12', "2");
+ sHalfWidthMap.put('\uFF13', "3");
+ sHalfWidthMap.put('\uFF14', "4");
+ sHalfWidthMap.put('\uFF15', "5");
+ sHalfWidthMap.put('\uFF16', "6");
+ sHalfWidthMap.put('\uFF17', "7");
+ sHalfWidthMap.put('\uFF18', "8");
+ sHalfWidthMap.put('\uFF19', "9");
+ sHalfWidthMap.put('\uFF1A', ":");
+ sHalfWidthMap.put('\uFF1B', ";");
+ sHalfWidthMap.put('\uFF1C', "<");
+ sHalfWidthMap.put('\uFF1D', "=");
+ sHalfWidthMap.put('\uFF1E', ">");
+ sHalfWidthMap.put('\uFF1F', "?");
+ sHalfWidthMap.put('\uFF20', "@");
+ sHalfWidthMap.put('\uFF21', "A");
+ sHalfWidthMap.put('\uFF22', "B");
+ sHalfWidthMap.put('\uFF23', "C");
+ sHalfWidthMap.put('\uFF24', "D");
+ sHalfWidthMap.put('\uFF25', "E");
+ sHalfWidthMap.put('\uFF26', "F");
+ sHalfWidthMap.put('\uFF27', "G");
+ sHalfWidthMap.put('\uFF28', "H");
+ sHalfWidthMap.put('\uFF29', "I");
+ sHalfWidthMap.put('\uFF2A', "J");
+ sHalfWidthMap.put('\uFF2B', "K");
+ sHalfWidthMap.put('\uFF2C', "L");
+ sHalfWidthMap.put('\uFF2D', "M");
+ sHalfWidthMap.put('\uFF2E', "N");
+ sHalfWidthMap.put('\uFF2F', "O");
+ sHalfWidthMap.put('\uFF30', "P");
+ sHalfWidthMap.put('\uFF31', "Q");
+ sHalfWidthMap.put('\uFF32', "R");
+ sHalfWidthMap.put('\uFF33', "S");
+ sHalfWidthMap.put('\uFF34', "T");
+ sHalfWidthMap.put('\uFF35', "U");
+ sHalfWidthMap.put('\uFF36', "V");
+ sHalfWidthMap.put('\uFF37', "W");
+ sHalfWidthMap.put('\uFF38', "X");
+ sHalfWidthMap.put('\uFF39', "Y");
+ sHalfWidthMap.put('\uFF3A', "Z");
+ sHalfWidthMap.put('\uFF3B', "[");
+ sHalfWidthMap.put('\uFF3C', "\\");
+ sHalfWidthMap.put('\uFF3D', "]");
+ sHalfWidthMap.put('\uFF3E', "^");
+ sHalfWidthMap.put('\uFF3F', "_");
+ sHalfWidthMap.put('\uFF41', "a");
+ sHalfWidthMap.put('\uFF42', "b");
+ sHalfWidthMap.put('\uFF43', "c");
+ sHalfWidthMap.put('\uFF44', "d");
+ sHalfWidthMap.put('\uFF45', "e");
+ sHalfWidthMap.put('\uFF46', "f");
+ sHalfWidthMap.put('\uFF47', "g");
+ sHalfWidthMap.put('\uFF48', "h");
+ sHalfWidthMap.put('\uFF49', "i");
+ sHalfWidthMap.put('\uFF4A', "j");
+ sHalfWidthMap.put('\uFF4B', "k");
+ sHalfWidthMap.put('\uFF4C', "l");
+ sHalfWidthMap.put('\uFF4D', "m");
+ sHalfWidthMap.put('\uFF4E', "n");
+ sHalfWidthMap.put('\uFF4F', "o");
+ sHalfWidthMap.put('\uFF50', "p");
+ sHalfWidthMap.put('\uFF51', "q");
+ sHalfWidthMap.put('\uFF52', "r");
+ sHalfWidthMap.put('\uFF53', "s");
+ sHalfWidthMap.put('\uFF54', "t");
+ sHalfWidthMap.put('\uFF55', "u");
+ sHalfWidthMap.put('\uFF56', "v");
+ sHalfWidthMap.put('\uFF57', "w");
+ sHalfWidthMap.put('\uFF58', "x");
+ sHalfWidthMap.put('\uFF59', "y");
+ sHalfWidthMap.put('\uFF5A', "z");
+ sHalfWidthMap.put('\uFF5B', "{");
+ sHalfWidthMap.put('\uFF5C', "|");
+ sHalfWidthMap.put('\uFF5D', "}");
+ sHalfWidthMap.put('\uFF5E', "~");
+ sHalfWidthMap.put('\uFF61', "\uFF61");
+ sHalfWidthMap.put('\uFF62', "\uFF62");
+ sHalfWidthMap.put('\uFF63', "\uFF63");
+ sHalfWidthMap.put('\uFF64', "\uFF64");
+ sHalfWidthMap.put('\uFF65', "\uFF65");
+ sHalfWidthMap.put('\uFF66', "\uFF66");
+ sHalfWidthMap.put('\uFF67', "\uFF67");
+ sHalfWidthMap.put('\uFF68', "\uFF68");
+ sHalfWidthMap.put('\uFF69', "\uFF69");
+ sHalfWidthMap.put('\uFF6A', "\uFF6A");
+ sHalfWidthMap.put('\uFF6B', "\uFF6B");
+ sHalfWidthMap.put('\uFF6C', "\uFF6C");
+ sHalfWidthMap.put('\uFF6D', "\uFF6D");
+ sHalfWidthMap.put('\uFF6E', "\uFF6E");
+ sHalfWidthMap.put('\uFF6F', "\uFF6F");
+ sHalfWidthMap.put('\uFF70', "\uFF70");
+ sHalfWidthMap.put('\uFF71', "\uFF71");
+ sHalfWidthMap.put('\uFF72', "\uFF72");
+ sHalfWidthMap.put('\uFF73', "\uFF73");
+ sHalfWidthMap.put('\uFF74', "\uFF74");
+ sHalfWidthMap.put('\uFF75', "\uFF75");
+ sHalfWidthMap.put('\uFF76', "\uFF76");
+ sHalfWidthMap.put('\uFF77', "\uFF77");
+ sHalfWidthMap.put('\uFF78', "\uFF78");
+ sHalfWidthMap.put('\uFF79', "\uFF79");
+ sHalfWidthMap.put('\uFF7A', "\uFF7A");
+ sHalfWidthMap.put('\uFF7B', "\uFF7B");
+ sHalfWidthMap.put('\uFF7C', "\uFF7C");
+ sHalfWidthMap.put('\uFF7D', "\uFF7D");
+ sHalfWidthMap.put('\uFF7E', "\uFF7E");
+ sHalfWidthMap.put('\uFF7F', "\uFF7F");
+ sHalfWidthMap.put('\uFF80', "\uFF80");
+ sHalfWidthMap.put('\uFF81', "\uFF81");
+ sHalfWidthMap.put('\uFF82', "\uFF82");
+ sHalfWidthMap.put('\uFF83', "\uFF83");
+ sHalfWidthMap.put('\uFF84', "\uFF84");
+ sHalfWidthMap.put('\uFF85', "\uFF85");
+ sHalfWidthMap.put('\uFF86', "\uFF86");
+ sHalfWidthMap.put('\uFF87', "\uFF87");
+ sHalfWidthMap.put('\uFF88', "\uFF88");
+ sHalfWidthMap.put('\uFF89', "\uFF89");
+ sHalfWidthMap.put('\uFF8A', "\uFF8A");
+ sHalfWidthMap.put('\uFF8B', "\uFF8B");
+ sHalfWidthMap.put('\uFF8C', "\uFF8C");
+ sHalfWidthMap.put('\uFF8D', "\uFF8D");
+ sHalfWidthMap.put('\uFF8E', "\uFF8E");
+ sHalfWidthMap.put('\uFF8F', "\uFF8F");
+ sHalfWidthMap.put('\uFF90', "\uFF90");
+ sHalfWidthMap.put('\uFF91', "\uFF91");
+ sHalfWidthMap.put('\uFF92', "\uFF92");
+ sHalfWidthMap.put('\uFF93', "\uFF93");
+ sHalfWidthMap.put('\uFF94', "\uFF94");
+ sHalfWidthMap.put('\uFF95', "\uFF95");
+ sHalfWidthMap.put('\uFF96', "\uFF96");
+ sHalfWidthMap.put('\uFF97', "\uFF97");
+ sHalfWidthMap.put('\uFF98', "\uFF98");
+ sHalfWidthMap.put('\uFF99', "\uFF99");
+ sHalfWidthMap.put('\uFF9A', "\uFF9A");
+ sHalfWidthMap.put('\uFF9B', "\uFF9B");
+ sHalfWidthMap.put('\uFF9C', "\uFF9C");
+ sHalfWidthMap.put('\uFF9D', "\uFF9D");
+ sHalfWidthMap.put('\uFF9E', "\uFF9E");
+ sHalfWidthMap.put('\uFF9F', "\uFF9F");
+ sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
+ }
+
+ /**
+ * Return half-width version of that character if possible. Return null if not possible
+ * @param ch input character
+ * @return CharSequence object if the mapping for ch exists. Return null otherwise.
+ */
+ public static CharSequence tryGetHalfWidthText(char ch) {
+ if (sHalfWidthMap.containsKey(ch)) {
+ return sHalfWidthMap.get(ch);
+ } else {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java
index cf5664c..f16a7e4 100644
--- a/core/java/android/preference/CheckBoxPreference.java
+++ b/core/java/android/preference/CheckBoxPreference.java
@@ -149,14 +149,12 @@
* @param checked The checked state.
*/
public void setChecked(boolean checked) {
-
- mChecked = checked;
-
- persistBoolean(checked);
-
- notifyDependencyChange(shouldDisableDependents());
-
- notifyChanged();
+ if (mChecked != checked) {
+ mChecked = checked;
+ persistBoolean(checked);
+ notifyDependencyChange(shouldDisableDependents());
+ notifyChanged();
+ }
}
/**
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index db25cfa..b337d28 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -16,15 +16,17 @@
package android.preference;
+import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.ContentObserver;
+import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
-import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
-import android.preference.PreferenceManager;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
@@ -42,7 +44,7 @@
private static final String TAG = "VolumePreference";
private int mStreamType;
-
+
/** May be null if the dialog isn't visible. */
private SeekBarVolumizer mSeekBarVolumizer;
@@ -54,7 +56,7 @@
mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
a.recycle();
}
-
+
public void setStreamType(int streamType) {
mStreamType = streamType;
}
@@ -65,7 +67,7 @@
final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
-
+
getPreferenceManager().registerOnActivityStopListener(this);
// grab focus and key events so that pressing the volume buttons in the
@@ -76,6 +78,8 @@
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // If key arrives immediately after the activity has been cleaned up.
+ if (mSeekBarVolumizer == null) return true;
boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -100,7 +104,7 @@
if (!positiveResult && mSeekBarVolumizer != null) {
mSeekBarVolumizer.revertVolume();
}
-
+
cleanup();
}
@@ -113,19 +117,96 @@
*/
private void cleanup() {
getPreferenceManager().unregisterOnActivityStopListener(this);
-
+
if (mSeekBarVolumizer != null) {
+ Dialog dialog = getDialog();
+ if (dialog != null && dialog.isShowing()) {
+ // Stopped while dialog was showing, revert changes
+ mSeekBarVolumizer.revertVolume();
+ }
mSeekBarVolumizer.stop();
mSeekBarVolumizer = null;
}
+
}
-
+
protected void onSampleStarting(SeekBarVolumizer volumizer) {
if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
mSeekBarVolumizer.stopSample();
}
}
-
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ if (mSeekBarVolumizer != null) {
+ mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
+ }
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ if (mSeekBarVolumizer != null) {
+ mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
+ }
+ }
+
+ public static class VolumeStore {
+ public int volume = -1;
+ public int originalVolume = -1;
+ }
+
+ private static class SavedState extends BaseSavedState {
+ VolumeStore mVolumeStore = new VolumeStore();
+
+ public SavedState(Parcel source) {
+ super(source);
+ mVolumeStore.volume = source.readInt();
+ mVolumeStore.originalVolume = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mVolumeStore.volume);
+ dest.writeInt(mVolumeStore.originalVolume);
+ }
+
+ VolumeStore getVolumeStore() {
+ return mVolumeStore;
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
/**
* Turns a {@link SeekBar} into a volume control.
*/
@@ -139,7 +220,7 @@
private int mOriginalStreamVolume;
private Ringtone mRingtone;
- private int mLastProgress;
+ private int mLastProgress = -1;
private SeekBar mSeekBar;
private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
@@ -153,7 +234,7 @@
}
}
};
-
+
public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -207,7 +288,7 @@
postSetVolume(progress);
}
- private void postSetVolume(int progress) {
+ void postSetVolume(int progress) {
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeCallbacks(this);
@@ -249,5 +330,20 @@
}
postSetVolume(mSeekBar.getProgress());
}
+
+ public void onSaveInstanceState(VolumeStore volumeStore) {
+ if (mLastProgress >= 0) {
+ volumeStore.volume = mLastProgress;
+ volumeStore.originalVolume = mOriginalStreamVolume;
+ }
+ }
+
+ public void onRestoreInstanceState(VolumeStore volumeStore) {
+ if (volumeStore.volume != -1) {
+ mOriginalStreamVolume = volumeStore.originalVolume;
+ mLastProgress = volumeStore.volume;
+ postSetVolume(mLastProgress);
+ }
+ }
}
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 489d936..d57155c 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -174,7 +174,7 @@
return Calendar.Calendars.delete(cr,
Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
+ Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
- new String[] {account.mName, account.mType});
+ new String[] {account.name, account.type});
}
/**
@@ -473,6 +473,39 @@
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HAS_ATTENDEE_DATA = "hasAttendeeData";
+
+ /**
+ * Whether guests can modify the event.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_MODIFY = "guestsCanModify";
+
+ /**
+ * Whether guests can invite other guests.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
+
+ /**
+ * Whether guests can see the list of attendees.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
+
+ /**
+ * Email of the organizer (owner) of the event.
+ * <P>Type: STRING</P>
+ */
+ public static final String ORGANIZER = "organizer";
+
+ /**
+ * Whether the user can invite others to the event.
+ * The GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary guest,
+ * while CAN_INVITE_OTHERS indicates if the user can invite others (either through
+ * GUESTS_CAN_INVITE_OTHERS or because the user has modify access to the event).
+ * <P>Type: INTEGER (boolean, readonly)</P>
+ */
+ public static final String CAN_INVITE_OTHERS = "canInviteOthers";
}
/**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index c0dbf4d..181a529 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -22,15 +22,14 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
-import android.accounts.Account;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -38,26 +37,34 @@
/**
* The Contacts provider stores all information about contacts.
*/
+@Deprecated
public class Contacts {
private static final String TAG = "Contacts";
+ @Deprecated
public static final String AUTHORITY = "contacts";
/**
* The content:// style URL for this provider
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY);
/** Signifies an email address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_EMAIL = 1;
/** Signifies a postal address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_POSTAL = 2;
/** Signifies an IM address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_IM = 3;
/** Signifies an Organization row that is stored in the Organizations table */
+ @Deprecated
public static final int KIND_ORGANIZATION = 4;
/** Signifies an Phone row that is stored in the Phones table */
+ @Deprecated
public static final int KIND_PHONE = 5;
/**
@@ -68,35 +75,41 @@
/**
* Columns from the Settings table that other columns join into themselves.
*/
+ @Deprecated
public interface SettingsColumns {
/**
* The _SYNC_ACCOUNT to which this setting corresponds. This may be null.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
* The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
/**
* The key of this setting.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String KEY = "key";
/**
* The value of this setting.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String VALUE = "value";
}
/**
* The settings over all of the people
*/
+ @Deprecated
public static final class Settings implements BaseColumns, SettingsColumns {
/**
* no public constructor since this is a utility class
@@ -106,17 +119,20 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/settings");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "settings";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "key ASC";
/**
@@ -128,8 +144,10 @@
* This is a boolean setting. It is true if it is set and it is anything other than the
* emptry string or "0".
*/
+ @Deprecated
public static final String SYNC_EVERYTHING = "syncEverything";
+ @Deprecated
public static String getSetting(ContentResolver cr, String account, String key) {
// For now we only support a single account and the UI doesn't know what
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
@@ -159,6 +177,7 @@
}
}
+ @Deprecated
public static void setSetting(ContentResolver cr, String account, String key,
String value) {
ContentValues values = new ContentValues();
@@ -177,11 +196,13 @@
/**
* Columns from the People table that other tables join into themselves.
*/
+ @Deprecated
public interface PeopleColumns {
/**
* The person's name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
@@ -190,6 +211,7 @@
* Used for pronunciation and/or collation in some languages.
* <p>Type: TEXT</P>
*/
+ @Deprecated
public static final String PHONETIC_NAME = "phonetic_name";
/**
@@ -197,6 +219,7 @@
* else if email is not null email.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String DISPLAY_NAME = "display_name";
/**
@@ -205,30 +228,35 @@
* <P>Type: TEXT</p>
* @hide Used only in Contacts application for now.
*/
+ @Deprecated
public static final String SORT_STRING = "sort_string";
/**
* Notes about the person.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NOTES = "notes";
/**
* The number of times a person has been contacted
* <P>Type: INTEGER</P>
*/
+ @Deprecated
public static final String TIMES_CONTACTED = "times_contacted";
/**
* The last time a person was contacted.
* <P>Type: INTEGER</P>
*/
+ @Deprecated
public static final String LAST_TIME_CONTACTED = "last_time_contacted";
/**
* A custom ringtone associated with a person. Not always present.
* <P>Type: TEXT (URI to the ringtone)</P>
*/
+ @Deprecated
public static final String CUSTOM_RINGTONE = "custom_ringtone";
/**
@@ -236,24 +264,28 @@
* present.
* <P>Type: INTEGER (0 for false, 1 for true)</P>
*/
+ @Deprecated
public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
/**
* Is the contact starred?
* <P>Type: INTEGER (boolean)</P>
*/
+ @Deprecated
public static final String STARRED = "starred";
/**
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
+ @Deprecated
public static final String PHOTO_VERSION = "photo_version";
}
/**
* This table contains people.
*/
+ @Deprecated
public static final class People implements BaseColumns, SyncConstValue, PeopleColumns,
PhonesColumns, PresenceColumns {
/**
@@ -264,6 +296,7 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/people");
@@ -271,6 +304,7 @@
* The content:// style URL for filtering people by name. The filter
* argument should be passed as an additional path segment after this URI.
*/
+ @Deprecated
public static final Uri CONTENT_FILTER_URI =
Uri.parse("content://contacts/people/filter");
@@ -278,6 +312,7 @@
* The content:// style URL for the table that holds the deleted
* contacts.
*/
+ @Deprecated
public static final Uri DELETED_CONTENT_URI =
Uri.parse("content://contacts/deleted_people");
@@ -292,6 +327,7 @@
* schema and do not want to have to support this.
* @hide
*/
+ @Deprecated
public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
Uri.parse("content://contacts/people/with_email_or_im_filter");
@@ -299,23 +335,27 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC";
/**
* The ID of the persons preferred phone number.
* <P>Type: INTEGER (foreign key to phones table on the _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_PHONE_ID = "primary_phone";
/**
@@ -323,6 +363,7 @@
* <P>Type: INTEGER (foreign key to contact_methods table on the
* _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_EMAIL_ID = "primary_email";
/**
@@ -330,6 +371,7 @@
* <P>Type: INTEGER (foreign key to organizations table on the
* _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
/**
@@ -338,6 +380,7 @@
* @param resolver the ContentResolver to use
* @param personId the person who was contacted
*/
+ @Deprecated
public static void markAsContacted(ContentResolver resolver, long personId) {
Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
uri = Uri.withAppendedPath(uri, "update_contact_time");
@@ -351,6 +394,7 @@
/**
* @hide Used in vCard parser code.
*/
+ @Deprecated
public static long tryGetMyContactsGroupId(ContentResolver resolver) {
Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
@@ -374,6 +418,7 @@
* @return the URI of the group membership row
* @throws IllegalStateException if the My Contacts group can't be found
*/
+ @Deprecated
public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) {
long groupId = tryGetMyContactsGroupId(resolver);
if (groupId == 0) {
@@ -392,6 +437,7 @@
* @return the URI of the group membership row
* @throws IllegalStateException if the group can't be found
*/
+ @Deprecated
public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) {
long groupId = 0;
Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
@@ -421,6 +467,7 @@
* @param groupId the group to add the person to
* @return the URI of the group membership row
*/
+ @Deprecated
public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) {
ContentValues values = new ContentValues();
values.put(GroupMembership.PERSON_ID, personId);
@@ -439,6 +486,7 @@
* @param values the values to use when creating the contact
* @return the URI of the contact, or null if the operation fails
*/
+ @Deprecated
public static Uri createPersonInMyContactsGroup(ContentResolver resolver,
ContentValues values) {
@@ -455,6 +503,7 @@
return contactUri;
}
+ @Deprecated
public static Cursor queryGroups(ContentResolver resolver, long person) {
return resolver.query(GroupMembership.CONTENT_URI, null, "person=?",
new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER);
@@ -466,6 +515,7 @@
* @param person the Uri of the person whose photo is to be updated
* @param data the byte[] that represents the photo
*/
+ @Deprecated
public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) {
Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
ContentValues values = new ContentValues();
@@ -478,6 +528,7 @@
* If the person's photo isn't present returns the placeholderImageResource instead.
* @param person the person whose photo should be used
*/
+ @Deprecated
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) {
Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
@@ -504,6 +555,7 @@
* have a photo
* @param options the decoding options, can be set to null
*/
+ @Deprecated
public static Bitmap loadContactPhoto(Context context, Uri person,
int placeholderImageResource, BitmapFactory.Options options) {
if (person == null) {
@@ -530,6 +582,7 @@
/**
* A sub directory of a single person that contains all of their Phones.
*/
+ @Deprecated
public static final class Phones implements BaseColumns, PhonesColumns,
PeopleColumns {
/**
@@ -540,11 +593,13 @@
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "phones";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "number ASC";
}
@@ -552,6 +607,7 @@
* A subdirectory of a single person that contains all of their
* ContactMethods.
*/
+ @Deprecated
public static final class ContactMethods
implements BaseColumns, ContactMethodsColumns, PeopleColumns {
/**
@@ -562,17 +618,20 @@
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "contact_methods";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "data ASC";
}
/**
* The extensions for a person
*/
+ @Deprecated
public static class Extensions implements BaseColumns, ExtensionsColumns {
/**
* no public constructor since this is a utility class
@@ -582,17 +641,20 @@
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "extensions";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
}
@@ -600,17 +662,20 @@
/**
* Columns from the groups table.
*/
+ @Deprecated
public interface GroupsColumns {
/**
* The group name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
* Notes about the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NOTES = "notes";
/**
@@ -618,18 +683,21 @@
* for this group's account.
* <P>Type: INTEGER (boolean)</P>
*/
+ @Deprecated
public static final String SHOULD_SYNC = "should_sync";
/**
* The ID of this group if it is a System Group, null otherwise.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String SYSTEM_ID = "system_id";
}
/**
* This table contains the groups for an account.
*/
+ @Deprecated
public static final class Groups
implements BaseColumns, SyncConstValue, GroupsColumns {
/**
@@ -640,6 +708,7 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/groups");
@@ -647,6 +716,7 @@
* The content:// style URL for the table that holds the deleted
* groups.
*/
+ @Deprecated
public static final Uri DELETED_CONTENT_URI =
Uri.parse("content://contacts/deleted_groups");
@@ -654,71 +724,90 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* groups.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* group.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = NAME + " ASC";
/**
*
*/
+ @Deprecated
public static final String GROUP_ANDROID_STARRED = "Starred in Android";
/**
* The "My Contacts" system group.
*/
+ @Deprecated
public static final String GROUP_MY_CONTACTS = "Contacts";
}
/**
* Columns from the Phones table that other columns join into themselves.
*/
+ @Deprecated
public interface PhonesColumns {
/**
* The type of the the phone number.
* <P>Type: INTEGER (one of the constants below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_HOME = 1;
+ @Deprecated
public static final int TYPE_MOBILE = 2;
+ @Deprecated
public static final int TYPE_WORK = 3;
+ @Deprecated
public static final int TYPE_FAX_WORK = 4;
+ @Deprecated
public static final int TYPE_FAX_HOME = 5;
+ @Deprecated
public static final int TYPE_PAGER = 6;
+ @Deprecated
public static final int TYPE_OTHER = 7;
/**
* The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NUMBER = "number";
/**
* The normalized phone number
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NUMBER_KEY = "number_key";
/**
* Whether this is the primary phone number
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
@@ -727,6 +816,7 @@
* contact method belongs to. Phone numbers are stored separately from
* other contact methods to make caller ID lookup more efficient.
*/
+ @Deprecated
public static final class Phones
implements BaseColumns, PhonesColumns, PeopleColumns {
/**
@@ -734,6 +824,7 @@
*/
private Phones() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label, CharSequence[] labelArray) {
CharSequence display = "";
@@ -755,6 +846,7 @@
return display;
}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label) {
return getDisplayLabel(context, type, label, null);
@@ -763,12 +855,14 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/phones");
/**
* The content:// style URL for filtering phone numbers
*/
+ @Deprecated
public static final Uri CONTENT_FILTER_URL =
Uri.parse("content://contacts/phones/filter");
@@ -776,26 +870,31 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* phone.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
+ @Deprecated
public static final class GroupMembership implements BaseColumns, GroupsColumns {
/**
* no public constructor since this is a utility class
@@ -805,65 +904,77 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/groupmembership");
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri RAW_CONTENT_URI =
Uri.parse("content://contacts/groupmembershipraw");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "groupmembership";
+
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of all
* person groups.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person group.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/contactsgroupmembership";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "group_id ASC";
/**
* The row id of the accounts group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_ID = "group_id";
/**
* The sync id of the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_SYNC_ID = "group_sync_id";
/**
* The account of the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
/**
* The account type of the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
/**
* The row id of the person.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
@@ -871,57 +982,70 @@
* Columns from the ContactMethods table that other tables join into
* themseleves.
*/
+ @Deprecated
public interface ContactMethodsColumns {
/**
* The kind of the the contact method. For example, email address,
* postal address, etc.
* <P>Type: INTEGER (one of the values below)</P>
*/
+ @Deprecated
public static final String KIND = "kind";
/**
* The type of the contact method, must be one of the types below.
* <P>Type: INTEGER (one of the values below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_HOME = 1;
+ @Deprecated
public static final int TYPE_WORK = 2;
+ @Deprecated
public static final int TYPE_OTHER = 3;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
*/
+ @Deprecated
public static final int MOBILE_EMAIL_TYPE_INDEX = 2;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
* This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone.
*/
+ @Deprecated
public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL";
/**
* The user defined label for the the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The data for the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String DATA = "data";
/**
* Auxiliary data for the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String AUX_DATA = "aux_data";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
@@ -929,18 +1053,21 @@
* This table stores all non-phone contact methods and a reference to the
* person that the contact method belongs to.
*/
+ @Deprecated
public static final class ContactMethods
implements BaseColumns, ContactMethodsColumns, PeopleColumns {
/**
* The column with latitude data for postal locations
* <P>Type: REAL</P>
*/
+ @Deprecated
public static final String POSTAL_LOCATION_LATITUDE = DATA;
/**
* The column with longitude data for postal locations
* <P>Type: REAL</P>
*/
+ @Deprecated
public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA;
/**
@@ -951,23 +1078,34 @@
* - pre:<an integer, one of the protocols below>
* - custom:<a string>
*/
+ @Deprecated
public static final int PROTOCOL_AIM = 0;
+ @Deprecated
public static final int PROTOCOL_MSN = 1;
+ @Deprecated
public static final int PROTOCOL_YAHOO = 2;
+ @Deprecated
public static final int PROTOCOL_SKYPE = 3;
+ @Deprecated
public static final int PROTOCOL_QQ = 4;
+ @Deprecated
public static final int PROTOCOL_GOOGLE_TALK = 5;
+ @Deprecated
public static final int PROTOCOL_ICQ = 6;
+ @Deprecated
public static final int PROTOCOL_JABBER = 7;
+ @Deprecated
public static String encodePredefinedImProtocol(int protocol) {
return "pre:" + protocol;
}
+ @Deprecated
public static String encodeCustomImProtocol(String protocolString) {
return "custom:" + protocolString;
}
+ @Deprecated
public static Object decodeImProtocol(String encodedString) {
if (encodedString == null) {
return null;
@@ -995,6 +1133,7 @@
* provider is defined for the given protocol
* @hide
*/
+ @Deprecated
public static String lookupProviderNameFromId(int protocol) {
switch (protocol) {
case PROTOCOL_GOOGLE_TALK:
@@ -1022,6 +1161,7 @@
*/
private ContactMethods() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int kind,
int type, CharSequence label) {
CharSequence display = "";
@@ -1074,6 +1214,7 @@
* @param latitude the latitude for the address
* @param longitude the longitude for the address
*/
+ @Deprecated
public void addPostalLocation(Context context, long postalId,
double latitude, double longitude) {
final ContentResolver resolver = context.getContentResolver();
@@ -1093,12 +1234,14 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/contact_methods");
/**
* The content:// style URL for sub-directory of e-mail addresses.
*/
+ @Deprecated
public static final Uri CONTENT_EMAIL_URI =
Uri.parse("content://contacts/contact_methods/email");
@@ -1106,30 +1249,35 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
/**
* The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
* multiple {@link Contacts#KIND_EMAIL} entries.
*/
+ @Deprecated
public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
/**
* The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
* multiple {@link Contacts#KIND_POSTAL} entries.
*/
+ @Deprecated
public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_EMAIL} entry.
*/
+ @Deprecated
public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_POSTAL} entry.
*/
+ @Deprecated
public static final String CONTENT_POSTAL_ITEM_TYPE
= "vnd.android.cursor.item/postal-address";
@@ -1137,23 +1285,27 @@
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_IM} entry.
*/
+ @Deprecated
public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this contact method is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
/**
* The IM presence columns with some contacts specific columns mixed in.
*/
+ @Deprecated
public interface PresenceColumns extends Im.CommonPresenceColumns {
/**
* The IM service the presence is coming from. Formatted using either
@@ -1161,6 +1313,7 @@
* {@link Contacts.ContactMethods#encodeCustomImProtocol}.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_PROTOCOL = "im_protocol";
/**
@@ -1168,12 +1321,14 @@
* the {@link #IM_PROTOCOL}.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_HANDLE = "im_handle";
/**
* The IM account for the local user that the presence data came from.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_ACCOUNT = "im_account";
}
@@ -1181,11 +1336,13 @@
* Contains presence information about contacts.
* @hide
*/
+ @Deprecated
public static final class Presence
implements BaseColumns, PresenceColumns, PeopleColumns {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/presence");
@@ -1193,6 +1350,7 @@
* The ID of the person this presence item is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
@@ -1201,6 +1359,7 @@
* @param status the status to get the icon for
* @return the resource ID for the proper presence icon
*/
+ @Deprecated
public static final int getPresenceIconResourceId(int status) {
switch (status) {
case Contacts.People.AVAILABLE:
@@ -1228,6 +1387,7 @@
* @param icon the icon to to set
* @param serverStatus that status
*/
+ @Deprecated
public static final void setPresenceIcon(ImageView icon, int serverStatus) {
icon.setImageResource(getPresenceIconResourceId(serverStatus));
}
@@ -1236,57 +1396,69 @@
/**
* Columns from the Organizations table that other columns join into themselves.
*/
+ @Deprecated
public interface OrganizationColumns {
/**
* The type of the organizations.
* <P>Type: INTEGER (one of the constants below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_WORK = 1;
+ @Deprecated
public static final int TYPE_OTHER = 2;
/**
* The user provided label, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The name of the company for this organization.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String COMPANY = "company";
/**
* The title within this organization.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String TITLE = "title";
/**
* The person this organization is tied to.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
/**
* A sub directory of a single person that contains all of their Phones.
*/
+ @Deprecated
public static final class Organizations implements BaseColumns, OrganizationColumns {
/**
* no public constructor since this is a utility class
*/
private Organizations() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label) {
CharSequence display = "";
@@ -1310,34 +1482,40 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/organizations");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "organizations";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
}
/**
* Columns from the Photos table that other columns join into themselves.
*/
+ @Deprecated
public interface PhotosColumns {
/**
* The _SYNC_VERSION of the photo that was last downloaded
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LOCAL_VERSION = "local_version";
/**
* The person this photo is associated with.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
@@ -1345,12 +1523,14 @@
* You must specify this in the columns in order to use it in the where clause.
* <P>Type: INTEGER(boolean)</P>
*/
+ @Deprecated
public static final String DOWNLOAD_REQUIRED = "download_required";
/**
* non-zero if this photo is known to exist on the server
* <P>Type: INTEGER(boolean)</P>
*/
+ @Deprecated
public static final String EXISTS_ON_SERVER = "exists_on_server";
/**
@@ -1358,12 +1538,14 @@
* the previous attempt. If null then the previous attempt succeeded.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String SYNC_ERROR = "sync_error";
/**
* The image data, or null if there is no image.
* <P>Type: BLOB</P>
*/
+ @Deprecated
public static final String DATA = "data";
}
@@ -1371,6 +1553,7 @@
/**
* The photos over all of the people
*/
+ @Deprecated
public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
/**
* no public constructor since this is a utility class
@@ -1380,37 +1563,44 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/photos");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "photo";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "person ASC";
}
+ @Deprecated
public interface ExtensionsColumns {
/**
* The name of this extension. May not be null. There may be at most one row for each name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
* The value of this extension. May not be null.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String VALUE = "value";
}
/**
* The extensions for a person
*/
+ @Deprecated
public static final class Extensions implements BaseColumns, ExtensionsColumns {
/**
* no public constructor since this is a utility class
@@ -1420,6 +1610,7 @@
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/extensions");
@@ -1427,22 +1618,27 @@
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* phone.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
+
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "person, name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
@@ -1450,10 +1646,16 @@
* Contains helper classes used to create or manage {@link android.content.Intent Intents}
* that involve contacts.
*/
+ @Deprecated
public static final class Intents {
+ @Deprecated
+ public Intents() {
+ }
+
/**
* This is the intent that is fired when a search suggestion is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_CLICKED =
ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED;
@@ -1461,6 +1663,7 @@
* This is the intent that is fired when a search suggestion for dialing a number
* is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED;
@@ -1468,6 +1671,7 @@
* This is the intent that is fired when a search suggestion for creating a contact
* is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED;
@@ -1475,6 +1679,7 @@
* Starts an Activity that lets the user pick a contact to attach an image to.
* After picking the contact it launches the image cropper in face detection mode.
*/
+ @Deprecated
public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE;
/**
@@ -1500,6 +1705,7 @@
* Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
* prompting the user when the contact doesn't exist.
*/
+ @Deprecated
public static final String SHOW_OR_CREATE_CONTACT =
ContactsContract.Intents.SHOW_OR_CREATE_CONTACT;
@@ -1510,6 +1716,7 @@
* <p>
* Type: BOOLEAN
*/
+ @Deprecated
public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE;
/**
@@ -1519,6 +1726,7 @@
* <p>
* Type: STRING
*/
+ @Deprecated
public static final String EXTRA_CREATE_DESCRIPTION =
ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
@@ -1529,49 +1737,62 @@
*
* @hide pending API council review
*/
+ @Deprecated
public static final String EXTRA_TARGET_RECT = ContactsContract.Intents.EXTRA_TARGET_RECT;
/**
* Intents related to the Contacts app UI.
*/
+ @Deprecated
public static final class UI {
+ @Deprecated
+ public UI() {
+ }
+
/**
* The action for the default contacts list tab.
*/
+ @Deprecated
public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
/**
* The action for the contacts list tab.
*/
+ @Deprecated
public static final String LIST_GROUP_ACTION =
ContactsContract.Intents.UI.LIST_GROUP_ACTION;
/**
* When in LIST_GROUP_ACTION mode, this is the group to display.
*/
+ @Deprecated
public static final String GROUP_NAME_EXTRA_KEY =
ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
/**
* The action for the all contacts list tab.
*/
+ @Deprecated
public static final String LIST_ALL_CONTACTS_ACTION =
ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
/**
* The action for the contacts with phone numbers list tab.
*/
+ @Deprecated
public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
/**
* The action for the starred contacts list tab.
*/
+ @Deprecated
public static final String LIST_STARRED_ACTION =
ContactsContract.Intents.UI.LIST_STARRED_ACTION;
/**
* The action for the frequent contacts list tab.
*/
+ @Deprecated
public static final String LIST_FREQUENT_ACTION =
ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
@@ -1580,6 +1801,7 @@
* contacts in alphabetical order and then the frequent contacts in descending
* order of the number of times they have been contacted.
*/
+ @Deprecated
public static final String LIST_STREQUENT_ACTION =
ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
@@ -1587,6 +1809,7 @@
* A key for to be used as an intent extra to set the activity
* title to a custom String value.
*/
+ @Deprecated
public static final String TITLE_EXTRA_KEY =
ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
@@ -1598,6 +1821,7 @@
* <p>
* Output: Nothing.
*/
+ @Deprecated
public static final String FILTER_CONTACTS_ACTION =
ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
@@ -1605,6 +1829,7 @@
* Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
* intents to supply the text on which to filter.
*/
+ @Deprecated
public static final String FILTER_TEXT_EXTRA_KEY =
ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
}
@@ -1613,23 +1838,34 @@
* Convenience class that contains string constants used
* to create contact {@link android.content.Intent Intents}.
*/
+ @Deprecated
public static final class Insert {
+ @Deprecated
+ public Insert() {
+ }
+
/** The action code to use when adding a contact */
+ @Deprecated
public static final String ACTION = ContactsContract.Intents.Insert.ACTION;
+
/**
* If present, forces a bypass of quick insert mode.
*/
+ @Deprecated
public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE;
+
/**
* The extra field for the contact name.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String NAME = ContactsContract.Intents.Insert.NAME;
/**
* The extra field for the contact phonetic name.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String PHONETIC_NAME =
ContactsContract.Intents.Insert.PHONETIC_NAME;
@@ -1637,24 +1873,28 @@
* The extra field for the contact company.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY;
/**
* The extra field for the contact job title.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE;
/**
* The extra field for the contact notes.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String NOTES = ContactsContract.Intents.Insert.NOTES;
/**
* The extra field for the contact phone number.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String PHONE = ContactsContract.Intents.Insert.PHONE;
/**
@@ -1662,12 +1902,14 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE;
/**
* The extra field for the phone isprimary flag.
* <P>Type: boolean</P>
*/
+ @Deprecated
public static final String PHONE_ISPRIMARY =
ContactsContract.Intents.Insert.PHONE_ISPRIMARY;
@@ -1675,6 +1917,7 @@
* The extra field for an optional second contact phone number.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String SECONDARY_PHONE =
ContactsContract.Intents.Insert.SECONDARY_PHONE;
@@ -1683,6 +1926,7 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String SECONDARY_PHONE_TYPE =
ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE;
@@ -1690,6 +1934,7 @@
* The extra field for an optional third contact phone number.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String TERTIARY_PHONE =
ContactsContract.Intents.Insert.TERTIARY_PHONE;
@@ -1698,6 +1943,7 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String TERTIARY_PHONE_TYPE =
ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE;
@@ -1705,6 +1951,7 @@
* The extra field for the contact email address.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL;
/**
@@ -1712,12 +1959,14 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE;
/**
* The extra field for the email isprimary flag.
* <P>Type: boolean</P>
*/
+ @Deprecated
public static final String EMAIL_ISPRIMARY =
ContactsContract.Intents.Insert.EMAIL_ISPRIMARY;
@@ -1725,6 +1974,7 @@
* The extra field for an optional second contact email address.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String SECONDARY_EMAIL =
ContactsContract.Intents.Insert.SECONDARY_EMAIL;
@@ -1733,6 +1983,7 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String SECONDARY_EMAIL_TYPE =
ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE;
@@ -1740,6 +1991,7 @@
* The extra field for an optional third contact email address.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String TERTIARY_EMAIL =
ContactsContract.Intents.Insert.TERTIARY_EMAIL;
@@ -1748,6 +2000,7 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String TERTIARY_EMAIL_TYPE =
ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE;
@@ -1755,6 +2008,7 @@
* The extra field for the contact postal address.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL;
/**
@@ -1762,18 +2016,21 @@
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
+ @Deprecated
public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE;
/**
* The extra field for the postal isprimary flag.
* <P>Type: boolean</P>
*/
+ @Deprecated
public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY;
/**
* The extra field for an IM handle.
* <P>Type: String</P>
*/
+ @Deprecated
public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE;
/**
@@ -1781,12 +2038,14 @@
* <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
* or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
*/
+ @Deprecated
public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL;
/**
* The extra field for the IM isprimary flag.
* <P>Type: boolean</P>
*/
+ @Deprecated
public static final String IM_ISPRIMARY = ContactsContract.Intents.Insert.IM_ISPRIMARY;
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7a1a9e4..53b2aa8 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -16,15 +16,22 @@
package android.provider;
-import android.content.Intent;
+import android.accounts.Account;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
+import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.accounts.Account;
import android.os.RemoteException;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.text.TextUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
/**
* The contract between the contacts provider and applications. Contains definitions
@@ -184,17 +191,26 @@
/**
* Lookup value that reflects the {@link Groups#GROUP_VISIBLE} state of
- * any {@link GroupMembership} for this contact.
+ * any {@link CommonDataKinds.GroupMembership} for this contact.
*/
public static final String IN_VISIBLE_GROUP = "in_visible_group";
/**
* Contact presence status. See {@link android.provider.Im.CommonPresenceColumns}
- * for individual status definitions.
+ * for individual status definitions. This column is only returned if explicitly
+ * requested in the query projection.
+ * <p>Type: NUMBER</p>
*/
public static final String PRESENCE_STATUS = Presence.PRESENCE_STATUS;
/**
+ * Contact presence custom status. This column is only returned if explicitly
+ * requested in the query projection.
+ * <p>Type: TEXT</p>
+ */
+ public static final String PRESENCE_CUSTOM_STATUS = Presence.PRESENCE_CUSTOM_STATUS;
+
+ /**
* An indicator of whether this contact has at least one phone number. "1" if there is
* at least one phone number, "0" otherwise.
* <P>Type: INTEGER</P>
@@ -296,17 +312,50 @@
* The directory twig for this sub-table
*/
public static final String CONTENT_DIRECTORY = "suggestions";
+ }
+
+ /**
+ * A sub-directory of a single contact that contains the contact's primary photo.
+ */
+ public static final class Photo implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Photo() {}
/**
- * An optional query parameter that can be supplied to limit the number of returned
- * suggestions.
- * <p>
- * Type: INTEGER
- *
- * @deprecated Please use the "limit" parameter
+ * The directory twig for this sub-table
*/
- @Deprecated
- public static final String MAX_SUGGESTIONS = "max_suggestions";
+ public static final String CONTENT_DIRECTORY = "photo";
+ }
+
+ /**
+ * Opens an InputStream for the person's default photo and returns the
+ * photo as a Bitmap stream.
+ *
+ * @param contactUri the contact whose photo should be used
+ */
+ public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ Uri photoUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
+ if (photoUri == null) {
+ return null;
+ }
+ Cursor cursor = cr.query(photoUri,
+ new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
+ try {
+ if (cursor == null || !cursor.moveToNext()) {
+ return null;
+ }
+ byte[] data = cursor.getBlob(0);
+ if (data == null) {
+ return null;
+ }
+ return new ByteArrayInputStream(data);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
}
}
@@ -405,15 +454,24 @@
public static final int AGGREGATION_MODE_IMMEDITATE = 1;
/**
+ * If {@link #AGGREGATION_MODE} is {@link #AGGREGATION_MODE_SUSPENDED}, changes
+ * to the raw contact do not cause its aggregation to be revisited. Note that changing
+ * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
+ * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass. Any subsequent
+ * change to the raw contact's data will.
+ */
+ public static final int AGGREGATION_MODE_SUSPENDED = 2;
+
+ /**
* Aggregation mode: never aggregate this raw contact (note that the raw contact will not
* have a corresponding Aggregate and therefore will not be included in Aggregates
* query results.)
*/
- public static final int AGGREGATION_MODE_DISABLED = 2;
+ public static final int AGGREGATION_MODE_DISABLED = 3;
/**
* A sub-directory of a single raw contact that contains all of their {@link Data} rows.
- * To access this directory append
+ * To access this directory append {@link Data#CONTENT_DIRECTORY} to the contact URI.
*/
public static final class Data implements BaseColumns, DataColumns {
/**
@@ -541,13 +599,33 @@
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
}
+ private interface PhoneLookupColumns {
+ /**
+ * The phone number as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * The type of phone number, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "type";
+
+ /**
+ * The user defined label for the phone number.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "label";
+ }
+
/**
* A table that represents the result of looking up a phone number, for
- * example for caller ID. The table joins that data row for the phone number
- * with the raw contact that owns the number. To perform a lookup you must
- * append the number you want to find to {@link #CONTENT_FILTER_URI}.
+ * example for caller ID. To perform a lookup you must append the number you
+ * want to find to {@link #CONTENT_FILTER_URI}.
*/
- public static final class PhoneLookup implements BaseColumns, DataColumns, ContactsColumns {
+ public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
+ ContactsColumns, ContactOptionsColumns {
/**
* This utility class cannot be instantiated
*/
@@ -580,7 +658,11 @@
/**
* Reference to the {@link RawContacts#_ID} this presence references.
* <P>Type: INTEGER</P>
+ *
+ * TODO remove this from public API
+ * @hide
*/
+ @Deprecated
public static final String RAW_CONTACT_ID = "presence_raw_contact_id";
/**
@@ -589,17 +671,27 @@
*/
public static final String DATA_ID = "presence_data_id";
- /**
- * The IM service the presence is coming from. Formatted using either
- * {@link CommonDataKinds.Im#encodePredefinedImProtocol(int)} or
- * {@link CommonDataKinds.Im#encodeCustomImProtocol(String)}.
- * <P>Type: TEXT</P>
- */
+ @Deprecated
public static final String IM_PROTOCOL = "im_protocol";
/**
- * The IM handle the presence item is for. The handle is scoped to the
- * {@link #IM_PROTOCOL}.
+ * <p>Type: NUMBER</p>
+ */
+ public static final String PROTOCOL = "protocol";
+
+ /**
+ * Name of the custom protocol. Should be supplied along with the {@link #PROTOCOL} value
+ * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}. Should be null or
+ * omitted if {@link #PROTOCOL} value is not
+ * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.
+ *
+ * <p>Type: NUMBER</p>
+ */
+ public static final String CUSTOM_PROTOCOL = "custom_protocol";
+
+ /**
+ * The IM handle the presence item is for. The handle is scoped to
+ * {@link #PROTOCOL}.
* <P>Type: TEXT</P>
*/
public static final String IM_HANDLE = "im_handle";
@@ -881,6 +973,32 @@
* <P>Type: TEXT</P>
*/
public static final String NUMBER = DATA;
+
+ public static final CharSequence getDisplayLabel(Context context, int type,
+ CharSequence label, CharSequence[] labelArray) {
+ CharSequence display = "";
+
+ if (type != Phone.TYPE_CUSTOM) {
+ CharSequence[] labels = labelArray != null? labelArray
+ : context.getResources().getTextArray(
+ com.android.internal.R.array.phoneTypes);
+ try {
+ display = labels[type - 1];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ display = labels[Phone.TYPE_CUSTOM];
+ }
+ } else {
+ if (!TextUtils.isEmpty(label)) {
+ display = label;
+ }
+ }
+ return display;
+ }
+
+ public static final CharSequence getDisplayLabel(Context context, int type,
+ CharSequence label) {
+ return getDisplayLabel(context, type, label, null);
+ }
}
/**
@@ -1056,19 +1174,18 @@
public static final int TYPE_WORK = 2;
public static final int TYPE_OTHER = 3;
+ /**
+ * This column should be populated with one of the defined
+ * constants, e.g. {@link #PROTOCOL_YAHOO}. If the value of this
+ * column is {@link #PROTOCOL_CUSTOM}, the {@link #CUSTOM_PROTOCOL}
+ * should contain the name of the custom protocol.
+ */
public static final String PROTOCOL = "data5";
public static final String CUSTOM_PROTOCOL = "data6";
- /**
- * The predefined IM protocol types. The protocol can either be non-present, one
- * of these types, or a free-form string. These cases are encoded in the PROTOCOL
- * column as:
- * <ul>
- * <li>null</li>
- * <li>pre:<an integer, one of the protocols below></li>
- * <li>custom:<a string></li>
- * </ul>
+ /*
+ * The predefined IM protocol types.
*/
public static final int PROTOCOL_CUSTOM = -1;
public static final int PROTOCOL_AIM = 0;
@@ -1287,6 +1404,7 @@
}
}
+ // TODO: make this private before unhiding
public interface GroupsColumns {
/**
* The display title of this group.
@@ -1325,7 +1443,7 @@
/**
* The total number of {@link Contacts} that have
- * {@link GroupMembership} in this group. Read-only value that is only
+ * {@link CommonDataKinds.GroupMembership} in this group. Read-only value that is only
* present when querying {@link Groups#CONTENT_SUMMARY_URI}.
* <p>
* Type: INTEGER
@@ -1334,7 +1452,7 @@
/**
* The total number of {@link Contacts} that have both
- * {@link GroupMembership} in this group, and also have phone numbers.
+ * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers.
* Read-only value that is only present when querying
* {@link Groups#CONTENT_SUMMARY_URI}.
* <p>
@@ -1346,7 +1464,7 @@
* Flag indicating if the contacts belonging to this group should be
* visible in any user interface.
* <p>
- * Type: INTEGER
+ * Type: INTEGER (boolean)
*/
public static final String GROUP_VISIBLE = "group_visible";
@@ -1360,6 +1478,14 @@
* <P>Type: INTEGER</P>
*/
public static final String DELETED = "deleted";
+
+ /**
+ * Whether this group should be synced if the SYNC_EVERYTHING settings
+ * is false for this group's account.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String SHOULD_SYNC = "should_sync";
}
/**
@@ -1475,6 +1601,81 @@
public static final String RAW_CONTACT_ID = "raw_contact_id";
}
+ private interface SettingsColumns {
+ /**
+ * The name of the account instance to which this row belongs.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_NAME = "account_name";
+
+ /**
+ * The type of account to which this row belongs, which when paired with
+ * {@link #ACCOUNT_NAME} identifies a specific account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * Depending on the mode defined by the sync-adapter, this flag controls
+ * the top-level sync behavior for this data source.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String SHOULD_SYNC = "should_sync";
+
+ /**
+ * Flag indicating if contacts without any {@link CommonDataKinds.GroupMembership}
+ * entries should be visible in any user interface.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
+
+ /**
+ * Read-only count of {@link Contacts} from a specific source that have
+ * no {@link GroupMembership} entries.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String UNGROUPED_COUNT = "summ_count";
+
+ /**
+ * Read-only count of {@link Contacts} from a specific source that have
+ * no {@link GroupMembership} entries, and also have phone numbers.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String UNGROUPED_WITH_PHONES = "summ_phones";
+ }
+
+ /**
+ * Contacts-specific settings for various {@link Account}.
+ */
+ public static final class Settings implements SettingsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Settings() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "settings");
+
+ /**
+ * The MIME-type of {@link #CONTENT_URI} providing a directory of
+ * settings.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
+
+ /**
+ * The MIME-type of {@link #CONTENT_URI} providing a single setting.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
+ }
+
/**
* Contains helper classes used to create or manage {@link android.content.Intent Intents}
* that involve contacts.
@@ -1583,6 +1784,13 @@
public static final int MODE_LARGE = 3;
/**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to indicate
+ * a list of specific MIME-types to exclude and not display. Stored as a
+ * {@link String} array.
+ */
+ public static final String EXTRA_EXCLUDE_MIMES = "exclude_mimes";
+
+ /**
* Intents related to the Contacts app UI.
*/
public static final class UI {
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index 5702e7c..4425e51 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -1521,8 +1521,9 @@
/**
* Returns the number of conversation with a given label.
- * @deprecated
+ * @deprecated Use {@link #getLabelId} instead.
*/
+ @Deprecated
public int getNumConversations(String label) {
return getNumConversations(getLabelId(label));
}
@@ -1534,8 +1535,9 @@
/**
* Returns the number of unread conversation with a given label.
- * @deprecated
+ * @deprecated Use {@link #getLabelId} instead.
*/
+ @Deprecated
public int getNumUnreadConversations(String label) {
return getNumUnreadConversations(getLabelId(label));
}
@@ -2040,8 +2042,9 @@
}
/**
- * @deprecated
+ * @deprecated Always returns true.
*/
+ @Deprecated
public boolean getExpanded() {
return true;
}
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index b11abe8..f126c4d 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -138,6 +138,7 @@
public static final String ACTIVE_ACCOUNT_USERNAME = "account_username";
public static final String ACTIVE_ACCOUNT_PW = "account_pw";
public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked";
+ public static final String ACTIVE_ACCOUNT_KEEP_SIGNED_IN = "account_keepSignedIn";
public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus";
public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus";
@@ -931,6 +932,12 @@
* <P>Type: INTEGER</P>
*/
String IS_GROUP_CHAT = "is_muc";
+
+ /**
+ * A hint that the UI should show the sent time of this message
+ * <P>Type: INTEGER</P>
+ */
+ String DISPLAY_SENT_TIME = "show_ts";
}
/**
@@ -1461,7 +1468,7 @@
* <P>Type: TEXT</P>
*/
String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message";
-
+
/**
* A value from 0-9 indicating which quick-switch chat screen slot this
* chat is occupying. If none (for instance, this is the 12th active chat)
@@ -1620,6 +1627,9 @@
/** specifies the last heartbeat interval received from the server */
public static final String SETTING_HEARTBEAT_INTERVAL = "heartbeat_interval";
+ /** specifiy the JID resource used for Google Talk connection */
+ public static final String SETTING_JID_RESOURCE = "jid_resource";
+
/**
* Used for reliable message queue (RMQ). This is for storing the last rmq id received
* from the GTalk server
@@ -1861,6 +1871,14 @@
putLongValue(contentResolver, providerId, SETTING_HEARTBEAT_INTERVAL, interval);
}
+ /**
+ * A convenience method to set the jid resource.
+ */
+ public static void setJidResource(ContentResolver contentResolver,
+ long providerId, String jidResource) {
+ putStringValue(contentResolver, providerId, SETTING_JID_RESOURCE, jidResource);
+ }
+
public static class QueryMap extends ContentQueryMap {
private ContentResolver mContentResolver;
private long mProviderId;
@@ -2047,6 +2065,23 @@
}
/**
+ * Set the JID resource.
+ *
+ * @param jidResource the jid resource to be stored.
+ */
+ public void setJidResource(String jidResource) {
+ ProviderSettings.setJidResource(mContentResolver, mProviderId, jidResource);
+ }
+ /**
+ * Get the JID resource used for the Google Talk connection
+ *
+ * @return the JID resource stored.
+ */
+ public String getJidResource() {
+ return getString(SETTING_JID_RESOURCE, null);
+ }
+
+ /**
* Convenience function for retrieving a single settings value
* as a boolean.
*
diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java
index 6e95fb7..19f361b 100644
--- a/core/java/android/provider/LiveFolders.java
+++ b/core/java/android/provider/LiveFolders.java
@@ -45,7 +45,7 @@
* public static class MyLiveFolder extends Activity {
* public static final Uri CONTENT_URI = Uri.parse("content://my.app/live");
*
- * @Override
+ * &#064;Override
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
*
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 21e5865..49b5bb1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -164,6 +164,12 @@
public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
/**
+ * Specify the maximum allowed recording duration in seconds.
+ * @hide
+ */
+ public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
+
+ /**
* The name of the Intent-extra used to indicate a content resolver Uri to be used to
* store the requested image or video.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 85a2041..9e3008b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -413,8 +413,6 @@
private static final String TAG = "Settings";
- private static String sJidResource = null;
-
public static class SettingNotFoundException extends AndroidException {
public SettingNotFoundException(String msg) {
super(msg);
@@ -1524,18 +1522,17 @@
@Deprecated
public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL;
-// /**
-// * @deprecated Use {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}
-// * instead
-// */
+ /**
+ * @deprecated Use
+ * {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} instead
+ */
@Deprecated
public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT;
-// /**
-// * @deprecated Use
-// * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}
-// * instead
-// */
+ /**
+ * @deprecated Use
+ * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead
+ */
@Deprecated
public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
@@ -2932,6 +2929,21 @@
"gtalk_rmq2_include_stream_id";
/**
+ * when receiving a chat message from the server, the message could be an older message
+ * whose "time sent" is x seconds from now. If x is significant enough, we want to flag
+ * it so the UI can give it some special treatment when displaying the "time sent" for
+ * it. This setting is to control what x is.
+ */
+ public static final String GTALK_OLD_CHAT_MESSAGE_THRESHOLD_IN_SEC =
+ "gtalk_old_chat_msg_threshold_in_sec";
+
+ /**
+ * a setting to control the max connection history record GTalkService stores.
+ */
+ public static final String GTALK_MAX_CONNECTION_HISTORY_RECORDS =
+ "gtalk_max_conn_history_records";
+
+ /**
* This is gdata url to lookup album and picture info from picasa web.
*/
public static final String GTALK_PICASA_ALBUM_URL =
@@ -3090,6 +3102,18 @@
"vending_pd_resend_frequency_ms";
/**
+ * Size of buffer in bytes for Vending to use when reading cache files.
+ */
+ public static final String VENDING_DISK_INPUT_BUFFER_BYTES =
+ "vending_disk_input_buffer_bytes";
+
+ /**
+ * Size of buffer in bytes for Vending to use when writing cache files.
+ */
+ public static final String VENDING_DISK_OUTPUT_BUFFER_BYTES =
+ "vending_disk_output_buffer_bytes";
+
+ /**
* Frequency in milliseconds at which we should cycle through the promoted applications
* on the home screen or the categories page.
*/
@@ -3097,6 +3121,13 @@
"vending_promo_refresh_freq_ms";
/**
+ * Frequency in milliseconds when we should refresh the provisioning information from
+ * the carrier backend.
+ */
+ public static final String VENDING_CARRIER_PROVISIONING_REFRESH_FREQUENCY_MS =
+ "vending_carrier_ref_freq_ms";
+
+ /**
* URL that points to the legal terms of service to display in Settings.
* <p>
* This should be a https URL. For a pretty user-friendly URL, use
@@ -3380,6 +3411,13 @@
"google_calendar_sync_window_days";
/**
+ * How often to update the calendar sync window.
+ * The window will be advanced every n days.
+ */
+ public static final String GOOGLE_CALENDAR_SYNC_WINDOW_UPDATE_DAYS =
+ "google_calendar_sync_window_update_days";
+
+ /**
* @deprecated
* @hide
*/
@@ -3622,42 +3660,6 @@
}
/**
- * Returns the GTalk JID resource associated with this device.
- *
- * @return String the JID resource of the device. It uses the device IMEI in the computation
- * of the JID resource. If IMEI is not ready (i.e. telephony module not ready), we'll return
- * an empty string.
- * @hide
- */
- // TODO: we shouldn't not have a permenant Jid resource, as that's an easy target for
- // spams. We should change it once a while, like when we resubscribe to the subscription feeds
- // server.
- // (also, should this live in GTalkService?)
- public static synchronized String getJidResource() {
- if (sJidResource != null) {
- return sJidResource;
- }
-
- MessageDigest digest;
- try {
- digest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("this should never happen");
- }
-
- String deviceId = TelephonyManager.getDefault().getDeviceId();
- if (TextUtils.isEmpty(deviceId)) {
- return "";
- }
-
- byte[] hashedDeviceId = digest.digest(deviceId.getBytes());
- String id = new String(Base64.encodeBase64(hashedDeviceId), 0, 12);
- id = id.replaceAll("/", "_");
- sJidResource = JID_RESOURCE_PREFIX + id;
- return sJidResource;
- }
-
- /**
* Returns the device ID that we should use when connecting to the mobile gtalk server.
* This is a string like "android-0x1242", where the hex string is the Android ID obtained
* from the GoogleLoginService.
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index f94b442..8e9f402 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -119,8 +119,8 @@
String authority, String service) {
ContentValues values = new ContentValues();
values.put(SubscribedFeeds.Feeds.FEED, feed);
- values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName);
- values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.name);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.type);
values.put(SubscribedFeeds.Feeds.AUTHORITY, authority);
values.put(SubscribedFeeds.Feeds.SERVICE, service);
return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values);
@@ -134,7 +134,7 @@
where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account.mName, account.mType, feed, authority});
+ where.toString(), new String[] {account.name, account.type, feed, authority});
}
public static int deleteFeeds(ContentResolver resolver,
@@ -144,7 +144,7 @@
where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account.mName, account.mType, authority});
+ where.toString(), new String[] {account.name, account.type, authority});
}
/**
diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
index 7927e28..5c93af0 100644
--- a/core/java/android/provider/SyncStateContract.java
+++ b/core/java/android/provider/SyncStateContract.java
@@ -71,7 +71,7 @@
public static byte[] get(ContentProviderClient provider, Uri uri,
Account account) throws RemoteException {
Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
- new String[]{account.mName, account.mType}, null);
+ new String[]{account.name, account.type}, null);
try {
if (c.moveToNext()) {
return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
@@ -96,8 +96,8 @@
Account account, byte[] data) throws RemoteException {
ContentValues values = new ContentValues();
values.put(Columns.DATA, data);
- values.put(Columns.ACCOUNT_NAME, account.mName);
- values.put(Columns.ACCOUNT_TYPE, account.mType);
+ values.put(Columns.ACCOUNT_NAME, account.name);
+ values.put(Columns.ACCOUNT_TYPE, account.type);
provider.insert(uri, values);
}
@@ -116,8 +116,8 @@
values.put(Columns.DATA, data);
return ContentProviderOperation
.newInsert(uri)
- .withValue(Columns.ACCOUNT_NAME, account.mName)
- .withValue(Columns.ACCOUNT_TYPE, account.mType)
+ .withValue(Columns.ACCOUNT_NAME, account.name)
+ .withValue(Columns.ACCOUNT_TYPE, account.type)
.withValues(values)
.build();
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 7a6f6bb..0207330 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1264,6 +1264,21 @@
}
/**
+ * Returns true if the number is a Phone number
+ *
+ * @param number the input number to be tested
+ * @return true if number is a Phone number
+ */
+ public static boolean isPhoneNumber(String number) {
+ if (TextUtils.isEmpty(number)) {
+ return false;
+ }
+
+ Matcher match = Regex.PHONE_PATTERN.matcher(number);
+ return match.matches();
+ }
+
+ /**
* Contains all MMS messages in the MMS app's inbox.
*/
public static final class Inbox implements BaseMmsColumns {
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 96ce9d6..d9fcb53 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -23,6 +23,7 @@
package android.server;
import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
@@ -40,9 +41,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
import java.util.UUID;
public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
@@ -67,26 +68,27 @@
private static int mSinkCount;
-
private final Context mContext;
private final IntentFilter mIntentFilter;
- private HashMap<String, Integer> mAudioDevices;
+ private HashMap<BluetoothDevice, Integer> mAudioDevices;
private final AudioManager mAudioManager;
- private final BluetoothDeviceService mBluetoothService;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothIntent.DEVICE);
if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
BluetoothError.ERROR);
switch (state) {
- case BluetoothDevice.BLUETOOTH_STATE_ON:
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
onBluetoothEnable();
break;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
onBluetoothDisable();
break;
}
@@ -95,28 +97,28 @@
BluetoothError.ERROR);
switch(bondState) {
case BluetoothDevice.BOND_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO);
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO);
break;
case BluetoothDevice.BOND_BONDING:
case BluetoothDevice.BOND_NOT_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
break;
}
} else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
- if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
- isSinkDevice(address)) {
+ if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
+ isSinkDevice(device)) {
// This device is a preferred sink. Make an A2DP connection
// after a delay. We delay to avoid connection collisions,
// and to give other profiles such as HFP a chance to
// connect first.
- Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address);
+ Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, device);
mHandler.sendMessageDelayed(msg, 6000);
}
}
}
};
- public BluetoothA2dpService(Context context, BluetoothDeviceService bluetoothService) {
+ public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -130,12 +132,14 @@
throw new RuntimeException("Could not init BluetoothA2dpService");
}
+ mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
+
mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
mContext.registerReceiver(mReceiver, mIntentFilter);
- mAudioDevices = new HashMap<String, Integer>();
+ mAudioDevices = new HashMap<BluetoothDevice, Integer>();
if (mBluetoothService.isEnabled())
onBluetoothEnable();
@@ -155,18 +159,18 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_CONNECT_TO:
- String address = (String)msg.obj;
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
// check bluetooth is still on, device is still preferred, and
// nothing is currently connected
if (mBluetoothService.isEnabled() &&
- getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
+ getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
lookupSinksMatchingStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_CONNECTED,
BluetoothA2dp.STATE_PLAYING,
BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
- log("Auto-connecting A2DP to sink " + address);
- connectSink(address);
+ log("Auto-connecting A2DP to sink " + device);
+ connectSink(device);
}
break;
}
@@ -185,8 +189,8 @@
return -1;
}
- private boolean isSinkDevice(String address) {
- String uuids[] = mBluetoothService.getRemoteUuids(address);
+ private boolean isSinkDevice(BluetoothDevice device) {
+ String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
UUID uuid;
if (uuids != null) {
for (String deviceUuid: uuids) {
@@ -199,11 +203,11 @@
return false;
}
- private synchronized boolean addAudioSink (String address) {
- String path = mBluetoothService.getObjectPathFromAddress(address);
+ private synchronized boolean addAudioSink (BluetoothDevice device) {
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
String propValues[] = (String []) getSinkPropertiesNative(path);
if (propValues == null) {
- Log.e(TAG, "Error while getting AudioSink properties for device: " + address);
+ Log.e(TAG, "Error while getting AudioSink properties for device: " + device);
return false;
}
Integer state = null;
@@ -214,8 +218,8 @@
break;
}
}
- mAudioDevices.put(address, state);
- handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTED, state);
+ mAudioDevices.put(device, state);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state);
return true;
}
@@ -226,6 +230,7 @@
String [] paths = devices.split(",");
for (String path: paths) {
String address = mBluetoothService.getAddressFromObjectPath(path);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
String []uuids = mBluetoothService.getRemoteUuids(address);
if (uuids != null)
for (String uuid: uuids) {
@@ -233,7 +238,7 @@
if (BluetoothUuid.isAudioSink(remoteUuid) ||
BluetoothUuid.isAudioSource(remoteUuid) ||
BluetoothUuid.isAdvAudioDist(remoteUuid)) {
- addAudioSink(address);
+ addAudioSink(device);
break;
}
}
@@ -244,36 +249,34 @@
private synchronized void onBluetoothDisable() {
if (!mAudioDevices.isEmpty()) {
- String [] addresses = new String[mAudioDevices.size()];
- addresses = mAudioDevices.keySet().toArray(addresses);
- for (String address : addresses) {
- int state = getSinkState(address);
+ BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()];
+ devices = mAudioDevices.keySet().toArray(devices);
+ for (BluetoothDevice device : devices) {
+ int state = getSinkState(device);
switch (state) {
case BluetoothA2dp.STATE_CONNECTING:
case BluetoothA2dp.STATE_CONNECTED:
case BluetoothA2dp.STATE_PLAYING:
- disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(address));
- handleSinkStateChange(address,state, BluetoothA2dp.STATE_DISCONNECTED);
+ disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(
+ device.getAddress()));
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
break;
case BluetoothA2dp.STATE_DISCONNECTING:
- handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTING,
- BluetoothA2dp.STATE_DISCONNECTED);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING,
+ BluetoothA2dp.STATE_DISCONNECTED);
break;
}
}
mAudioDevices.clear();
}
- mAudioManager.setParameters(BLUETOOTH_ENABLED+"=false");
+ mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false");
}
- public synchronized int connectSink(String address) {
+ public synchronized int connectSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("connectSink(" + address + ")");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
+ if (DBG) log("connectSink(" + device + ")");
// ignore if there are any active sinks
if (lookupSinksMatchingStates(new int[] {
@@ -284,10 +287,10 @@
return BluetoothError.ERROR;
}
- if (mAudioDevices.get(address) == null && !addAudioSink(address))
+ if (mAudioDevices.get(device) == null && !addAudioSink(device))
return BluetoothError.ERROR;
- int state = mAudioDevices.get(address);
+ int state = mAudioDevices.get(device);
switch (state) {
case BluetoothA2dp.STATE_CONNECTED:
@@ -298,7 +301,7 @@
return BluetoothError.SUCCESS;
}
- String path = mBluetoothService.getObjectPathFromAddress(address);
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (path == null)
return BluetoothError.ERROR;
@@ -309,19 +312,17 @@
return BluetoothError.SUCCESS;
}
- public synchronized int disconnectSink(String address) {
+ public synchronized int disconnectSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("disconnectSink(" + address + ")");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- String path = mBluetoothService.getObjectPathFromAddress(address);
+ if (DBG) log("disconnectSink(" + device + ")");
+
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (path == null) {
return BluetoothError.ERROR;
}
- switch (getSinkState(address)) {
+ switch (getSinkState(device)) {
case BluetoothA2dp.STATE_DISCONNECTED:
return BluetoothError.ERROR;
case BluetoothA2dp.STATE_DISCONNECTING:
@@ -336,41 +337,36 @@
}
}
- public synchronized List<String> listConnectedSinks() {
+ public synchronized BluetoothDevice[] getConnectedSinks() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
- BluetoothA2dp.STATE_PLAYING});
+ Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+ new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING});
+ return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
- public synchronized int getSinkState(String address) {
+ public synchronized int getSinkState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- Integer state = mAudioDevices.get(address);
+ Integer state = mAudioDevices.get(device);
if (state == null)
return BluetoothA2dp.STATE_DISCONNECTED;
return state;
}
- public synchronized int getSinkPriority(String address) {
+ public synchronized int getSinkPriority(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.getBluetoothA2dpSinkPriorityKey(address),
+ Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
BluetoothA2dp.PRIORITY_OFF);
}
- public synchronized int setSinkPriority(String address, int priority) {
+ public synchronized int setSinkPriority(BluetoothDevice device, int priority) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) {
return BluetoothError.ERROR;
}
return Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), priority) ?
+ Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority) ?
BluetoothError.SUCCESS : BluetoothError.ERROR;
}
@@ -386,20 +382,22 @@
return;
}
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+
if (name.equals(PROPERTY_STATE)) {
int state = convertBluezSinkStringtoState(propValues[1]);
- if (mAudioDevices.get(address) == null) {
+ if (mAudioDevices.get(device) == null) {
// This is for an incoming connection for a device not known to us.
// We have authorized it and bluez state has changed.
- addAudioSink(address);
+ addAudioSink(device);
} else {
- int prevState = mAudioDevices.get(address);
- handleSinkStateChange(address, prevState, state);
+ int prevState = mAudioDevices.get(device);
+ handleSinkStateChange(device, prevState, state);
}
}
}
- private void handleSinkStateChange(String address, int prevState, int state) {
+ private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
if (state != prevState) {
if (state == BluetoothA2dp.STATE_DISCONNECTED ||
state == BluetoothA2dp.STATE_DISCONNECTING) {
@@ -413,28 +411,28 @@
} else if (state == BluetoothA2dp.STATE_CONNECTED) {
mSinkCount ++;
}
- mAudioDevices.put(address, state);
+ mAudioDevices.put(device, state);
Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothA2dp.SINK_STATE, state);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- if (DBG) log("A2DP state : address: " + address + " State:" + prevState + "->" + state);
+ if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
}
}
- private synchronized List<String> lookupSinksMatchingStates(int[] states) {
- List<String> sinks = new ArrayList<String>();
+ private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
+ Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
if (mAudioDevices.isEmpty()) {
return sinks;
}
- for (String path: mAudioDevices.keySet()) {
- int sinkState = getSinkState(path);
+ for (BluetoothDevice device: mAudioDevices.keySet()) {
+ int sinkState = getSinkState(device);
for (int state : states) {
if (state == sinkState) {
- sinks.add(path);
+ sinks.add(device);
break;
}
}
@@ -446,9 +444,9 @@
protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mAudioDevices.isEmpty()) return;
pw.println("Cached audio devices:");
- for (String address : mAudioDevices.keySet()) {
- int state = mAudioDevices.get(address);
- pw.println(address + " " + BluetoothA2dp.stateToString(state));
+ for (BluetoothDevice device : mAudioDevices.keySet()) {
+ int state = mAudioDevices.get(device);
+ pw.println(device + " " + BluetoothA2dp.stateToString(state));
}
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1704733..975c2ff 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
@@ -46,8 +47,10 @@
private Thread mThread;
private boolean mStarted;
private boolean mInterrupted;
+
private final HashMap<String, Integer> mPasskeyAgentRequestData;
- private final BluetoothDeviceService mBluetoothService;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
private final Context mContext;
private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
@@ -84,10 +87,12 @@
static { classInitNative(); }
private static native void classInitNative();
- /* pacakge */ BluetoothEventLoop(Context context, BluetoothDeviceService bluetoothService) {
+ /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+ BluetoothService bluetoothService) {
mBluetoothService = bluetoothService;
mContext = context;
mPasskeyAgentRequestData = new HashMap();
+ mAdapter = adapter;
initializeNativeDataNative();
}
@@ -137,7 +142,7 @@
}
if (classValue != null) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
intent.putExtra(BluetoothIntent.RSSI, rssiValue);
intent.putExtra(BluetoothIntent.NAME, name);
@@ -158,7 +163,7 @@
private void onDeviceDisappeared(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
@@ -251,7 +256,7 @@
if (pairable == null || discoverable == null)
return;
- int mode = BluetoothDeviceService.bluezStringToScanMode(
+ int mode = BluetoothService.bluezStringToScanMode(
pairable.equals("true"),
discoverable.equals("true"));
if (mode >= 0) {
@@ -299,15 +304,16 @@
Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
return;
}
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
if (name.equals("Name")) {
Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
intent.putExtra(BluetoothIntent.NAME, propValues[1]);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("Class")) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
@@ -318,7 +324,7 @@
} else {
intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
}
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("UUIDs")) {
@@ -351,7 +357,7 @@
address = address.toUpperCase();
mPasskeyAgentRequestData.put(address, new Integer(nativeData));
- if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+ if (mBluetoothService.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
// shutdown path
mBluetoothService.cancelPairingUserInput(address);
return null;
@@ -364,7 +370,7 @@
if (address == null) return;
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothIntent.PASSKEY, passkey);
intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
@@ -377,7 +383,7 @@
if (address == null) return;
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
return;
@@ -409,7 +415,7 @@
}
}
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
return;
@@ -424,11 +430,14 @@
boolean authorized = false;
UUID uuid = UUID.fromString(deviceUuid);
+ // Bluez sends the UUID of the local service being accessed, _not_ the
+ // remote service
if (mBluetoothService.isEnabled() &&
- (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(uuid)
+ (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
|| BluetoothUuid.isAdvAudioDist(uuid))) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
- authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
if (authorized) {
Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
} else {
@@ -437,6 +446,7 @@
} else {
Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
}
+ log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
return authorized;
}
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothService.java
similarity index 90%
rename from core/java/android/server/BluetoothDeviceService.java
rename to core/java/android/server/BluetoothService.java
index d2b4447..413f6a8 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -16,7 +16,7 @@
/**
* TODO: Move this to
- * java/services/com/android/server/BluetoothDeviceService.java
+ * java/services/com/android/server/BluetoothService.java
* and make the contructor package private again.
*
* @hide
@@ -25,11 +25,12 @@
package android.server;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -55,8 +56,8 @@
import java.util.Iterator;
import java.util.Map;
-public class BluetoothDeviceService extends IBluetoothDevice.Stub {
- private static final String TAG = "BluetoothDeviceService";
+public class BluetoothService extends IBluetooth.Stub {
+ private static final String TAG = "BluetoothService";
private static final boolean DBG = true;
private int mNativeData;
@@ -65,11 +66,11 @@
private boolean mIsAirplaneSensitive;
private int mBluetoothState;
private boolean mRestart = false; // need to call enable() after disable()
-
- private final BondState mBondState = new BondState(); // local cache of bondings
private boolean mIsDiscovering;
- private final IBatteryStats mBatteryStats;
+ private BluetoothAdapter mAdapter; // constant after init()
+ private final BondState mBondState = new BondState(); // local cache of bondings
+ private final IBatteryStats mBatteryStats;
private final Context mContext;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -78,14 +79,14 @@
private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
private static final int MESSAGE_FINISH_DISABLE = 2;
- private Map<String, String> mProperties;
- private HashMap <String, Map<String, String>> mRemoteDeviceProperties;
+ private final Map<String, String> mAdapterProperties;
+ private final HashMap <String, Map<String, String>> mDeviceProperties;
static {
classInitNative();
}
- public BluetoothDeviceService(Context context) {
+ public BluetoothService(Context context) {
mContext = context;
// Need to do this in place of:
@@ -93,11 +94,7 @@
// Since we can not import BatteryStatsService from here. This class really needs to be
// moved to java/services/com/android/server/
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
- }
- /** Must be called after construction, and before any other method.
- */
- public synchronized void init() {
initializeNativeDataNative();
if (isEnabledNative() == 1) {
@@ -105,12 +102,16 @@
disableNative();
}
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
+ mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF;
mIsDiscovering = false;
- mEventLoop = new BluetoothEventLoop(mContext, this);
+ mAdapterProperties = new HashMap<String, String>();
+ mDeviceProperties = new HashMap<String, Map<String,String>>();
registerForAirplaneMode();
- mProperties = new HashMap<String, String>();
- mRemoteDeviceProperties = new HashMap<String, Map<String,String>>();
+ }
+
+ public synchronized void initAfterRegistration() {
+ mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
}
@Override
@@ -127,7 +128,7 @@
public boolean isEnabled() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON;
+ return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON;
}
public int getBluetoothState() {
@@ -152,9 +153,9 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
switch (mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
return true;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
break;
default:
return false;
@@ -162,11 +163,11 @@
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF);
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF);
// Allow 3 seconds for profiles to gracefully disconnect
// TODO: Introduce a callback mechanism so that each profile can notify
- // BluetoothDeviceService when it is done shutting down
+ // BluetoothService when it is done shutting down
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
return true;
@@ -174,7 +175,7 @@
private synchronized void finishDisable(boolean saveSetting) {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
return;
}
mEventLoop.stop();
@@ -189,17 +190,17 @@
// update mode
Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mIsDiscovering = false;
- mProperties.clear();
+ mAdapterProperties.clear();
if (saveSetting) {
persistBluetoothOnSetting(false);
}
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF);
// Log bluetooth off to battery stats.
long ident = Binder.clearCallingIdentity();
@@ -236,13 +237,13 @@
if (mIsAirplaneSensitive && isAirplaneModeOn()) {
return false;
}
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) {
return false;
}
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON);
mEnableThread = new EnableThread(saveSetting);
mEnableThread.start();
return true;
@@ -250,7 +251,7 @@
/** Forcibly restart Bluetooth if it is on */
/* package */ synchronized void restart() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_ON) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) {
return;
}
mRestart = true;
@@ -356,8 +357,8 @@
mEnableThread = null;
setBluetoothState(res ?
- BluetoothDevice.BLUETOOTH_STATE_ON :
- BluetoothDevice.BLUETOOTH_STATE_OFF);
+ BluetoothAdapter.BLUETOOTH_STATE_ON :
+ BluetoothAdapter.BLUETOOTH_STATE_OFF);
if (res) {
// Update mode
@@ -410,7 +411,7 @@
));
public synchronized void loadBondState() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) {
return;
}
String []bonds = null;
@@ -442,7 +443,7 @@
if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
reason + ")");
Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothIntent.BOND_STATE, state);
intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
if (state == BluetoothDevice.BOND_NOT_BONDED) {
@@ -539,7 +540,7 @@
/*package*/synchronized void getAllProperties() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- mProperties.clear();
+ mAdapterProperties.clear();
String properties[] = (String [])getAdapterPropertiesNative();
// The String Array consists of key-value pairs.
@@ -568,17 +569,17 @@
} else {
newValue = properties[++i];
}
- mProperties.put(name, newValue);
+ mAdapterProperties.put(name, newValue);
}
// Add adapter object path property.
String adapterPath = getAdapterPathNative();
if (adapterPath != null)
- mProperties.put("ObjectPath", adapterPath + "/dev_");
+ mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
}
/* package */ synchronized void setProperty(String name, String value) {
- mProperties.put(name, value);
+ mAdapterProperties.put(name, value);
}
public synchronized boolean setName(String name) {
@@ -646,10 +647,10 @@
}
/*package*/ synchronized String getProperty (String name) {
- if (!mProperties.isEmpty())
- return mProperties.get(name);
+ if (!mAdapterProperties.isEmpty())
+ return mAdapterProperties.get(name);
getAllProperties();
- return mProperties.get(name);
+ return mAdapterProperties.get(name);
}
public synchronized String getAddress() {
@@ -678,7 +679,7 @@
if (!BluetoothDevice.checkBluetoothAddress(address)) {
return null;
}
- Map <String, String> properties = mRemoteDeviceProperties.get(address);
+ Map <String, String> properties = mDeviceProperties.get(address);
if (properties != null) return properties.get("Name");
return null;
}
@@ -805,7 +806,7 @@
}
/*package*/ boolean isRemoteDeviceInCache(String address) {
- return (mRemoteDeviceProperties.get(address) != null);
+ return (mDeviceProperties.get(address) != null);
}
/*package*/ String[] getRemoteDeviceProperties(String address) {
@@ -814,7 +815,7 @@
}
/*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
- Map<String, String> properties = mRemoteDeviceProperties.get(address);
+ Map<String, String> properties = mDeviceProperties.get(address);
if (properties != null) {
return properties.get(property);
} else {
@@ -835,7 +836,7 @@
/*
* We get a DeviceFound signal every time RSSI changes or name changes.
* Don't create a new Map object every time */
- Map<String, String> propertyValues = mRemoteDeviceProperties.get(address);
+ Map<String, String> propertyValues = mDeviceProperties.get(address);
if (propertyValues != null) {
propertyValues.clear();
} else {
@@ -864,19 +865,19 @@
}
propertyValues.put(name, newValue);
}
- mRemoteDeviceProperties.put(address, propertyValues);
+ mDeviceProperties.put(address, propertyValues);
}
/* package */ void removeRemoteDeviceProperties(String address) {
- mRemoteDeviceProperties.remove(address);
+ mDeviceProperties.remove(address);
}
/* package */ synchronized void setRemoteDeviceProperty(String address, String name,
String value) {
- Map <String, String> propVal = mRemoteDeviceProperties.get(address);
+ Map <String, String> propVal = mDeviceProperties.get(address);
if (propVal != null) {
propVal.put(name, value);
- mRemoteDeviceProperties.put(address, propVal);
+ mDeviceProperties.put(address, propVal);
} else {
Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
}
@@ -1005,6 +1006,8 @@
if (!BluetoothDevice.checkBluetoothAddress(address)) {
return false;
}
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
address = address.toUpperCase();
Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
if (data == null) {
@@ -1059,16 +1062,16 @@
pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
switch(mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
pw.println("\nBluetooth OFF\n");
return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON:
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON:
pw.println("\nBluetooth TURNING ON\n");
return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
pw.println("\nBluetooth TURNING OFF\n");
return;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
pw.println("\nBluetooth ON\n");
}
@@ -1079,15 +1082,26 @@
BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
pw.println("\n--Known devices--");
- for (String address : mRemoteDeviceProperties.keySet()) {
+ for (String address : mDeviceProperties.keySet()) {
+ int bondState = mBondState.getBondState(address);
pw.printf("%s %10s (%d) %s\n", address,
- toBondStateString(mBondState.getBondState(address)),
+ toBondStateString(bondState),
mBondState.getAttempt(address),
getRemoteName(address));
+ if (bondState == BluetoothDevice.BOND_BONDED) {
+ String[] uuids = getRemoteUuids(address);
+ if (uuids == null) {
+ pw.printf("\tuuids = null\n");
+ } else {
+ for (String uuid : uuids) {
+ pw.printf("\t" + uuid + "\n");
+ }
+ }
+ }
}
String value = getProperty("Devices");
- String []devicesObjectPath = null;
+ String[] devicesObjectPath = null;
if (value != null) {
devicesObjectPath = value.split(",");
}
@@ -1113,7 +1127,7 @@
pw.println("getState() = STATE_ERROR");
break;
}
- pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
+ pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
headset.close();
@@ -1121,20 +1135,20 @@
/* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
if (pairable && discoverable)
- return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
else if (pairable && !discoverable)
- return BluetoothDevice.SCAN_MODE_CONNECTABLE;
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
else
- return BluetoothDevice.SCAN_MODE_NONE;
+ return BluetoothAdapter.SCAN_MODE_NONE;
}
/* package */ static String scanModeToBluezString(int mode) {
switch (mode) {
- case BluetoothDevice.SCAN_MODE_NONE:
+ case BluetoothAdapter.SCAN_MODE_NONE:
return "off";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE:
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
return "connectable";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
return "discoverable";
}
return null;
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index 49718cb..9ee64af 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -58,6 +58,7 @@
// data[KEY_INITIAL_QUERY]: initial query
// data[KEY_LAUNCH_ACTIVITY]: launch activity
// data[KEY_APP_SEARCH_DATA]: app search data
+ // data[KEY_TRIGGER]: 0 = false, 1 = true
private static final int MSG_START_SEARCH = 1;
// Takes no arguments
private static final int MSG_STOP_SEARCH = 2;
@@ -69,7 +70,8 @@
private static final String KEY_INITIAL_QUERY = "q";
private static final String KEY_LAUNCH_ACTIVITY = "a";
private static final String KEY_APP_SEARCH_DATA = "d";
- private static final String KEY_IDENT= "i";
+ private static final String KEY_IDENT = "i";
+ private static final String KEY_TRIGGER = "t";
// Context used for getting search UI resources
private final Context mContext;
@@ -173,7 +175,8 @@
final Bundle appSearchData,
final boolean globalSearch,
final ISearchManagerCallback searchManagerCallback,
- int ident) {
+ int ident,
+ boolean trigger) {
if (DBG) debug("startSearch()");
Message msg = Message.obtain();
msg.what = MSG_START_SEARCH;
@@ -185,6 +188,7 @@
msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
msgData.putInt(KEY_IDENT, ident);
+ msgData.putInt(KEY_TRIGGER, trigger ? 1 : 0);
mSearchUiThread.sendMessage(msg);
// be a little more eager in setting this so isVisible will return the correct value if
// called immediately after startSearch
@@ -268,8 +272,9 @@
boolean globalSearch = msg.arg2 != 0;
ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
int ident = msgData.getInt(KEY_IDENT);
+ boolean trigger = msgData.getInt(KEY_TRIGGER) != 0;
performStartSearch(initialQuery, selectInitialQuery, launchActivity,
- appSearchData, globalSearch, searchManagerCallback, ident);
+ appSearchData, globalSearch, searchManagerCallback, ident, trigger);
}
}
@@ -284,7 +289,8 @@
Bundle appSearchData,
boolean globalSearch,
ISearchManagerCallback searchManagerCallback,
- int ident) {
+ int ident,
+ boolean trigger) {
if (DBG) debug("performStartSearch()");
registerBroadcastReceiver();
@@ -301,6 +307,9 @@
mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
globalSearch);
mVisible = true;
+ if (trigger) {
+ mSearchDialog.launchQuerySearch();
+ }
}
/**
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index afed4a4..5e0b3d2 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -233,7 +233,31 @@
appSearchData,
globalSearch,
searchManagerCallback,
- ident);
+ ident,
+ false); // don't trigger
+ }
+
+ /**
+ * Launches the search UI and triggers the search, as if the user had clicked on the
+ * search button within the dialog.
+ *
+ * @see SearchManager#triggerSearch(String, android.content.ComponentName, android.os.Bundle)
+ */
+ public void triggerSearch(String query,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ ISearchManagerCallback searchManagerCallback,
+ boolean globalSearch,
+ int ident) {
+ getSearchDialog().startSearch(
+ query,
+ false,
+ launchActivity,
+ appSearchData,
+ globalSearch,
+ searchManagerCallback,
+ ident,
+ true); // triger search after launching
}
/**
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index c615957..a2add73 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -26,6 +26,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.util.Log;
@@ -230,14 +231,16 @@
: webSearchInfoList.get(ii - search_count);
ActivityInfo ai = info.activityInfo;
// Check first to avoid duplicate entries.
- if (newSearchablesMap.get(new ComponentName(ai.packageName, ai.name)) == null) {
- SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
- if (searchable != null) {
- newSearchablesList.add(searchable);
- newSearchablesMap.put(searchable.getSearchActivity(), searchable);
- if (searchable.shouldIncludeInGlobalSearch()) {
- newSearchablesInGlobalSearchList.add(searchable);
- }
+ if (newSearchablesMap.containsKey(new ComponentName(ai.packageName, ai.name))) {
+ continue;
+ }
+ SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
+ if (searchable != null) {
+ newSearchablesList.add(searchable);
+ newSearchablesMap.put(searchable.getSearchActivity(), searchable);
+ if (searchable.shouldIncludeInGlobalSearch()
+ && isWhitelistedForGlobalSearch(pm, searchable.getSearchActivity())) {
+ newSearchablesInGlobalSearchList.add(searchable);
}
}
}
@@ -289,6 +292,25 @@
}
/**
+ * Determines whether an activity may be included in quick search box. For now this is
+ * restricted to system installed apps.
+ *
+ * TODO: remove when we are ready to enable global search for third party applications.
+ *
+ * @param pm The package manager.
+ * @param searchActivity The component of the search activity.
+ * @return True if the search activity may include its search suggestions in quick search box.
+ */
+ private boolean isWhitelistedForGlobalSearch(PackageManager pm, ComponentName searchActivity) {
+ try {
+ ActivityInfo ai = pm.getActivityInfo(searchActivity, 0);
+ return ((ai.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
* Checks if the given activity component is present in the system and if so makes it the
* preferred activity for handling ACTION_WEB_SEARCH.
* @param component Name of the component to check and set as preferred.
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index eb58c3b..bc7a1d7 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -23,5 +23,6 @@
*/
oneway interface IWallpaperService {
void attach(IWallpaperConnection connection,
- IBinder windowToken, int reqWidth, int reqHeight);
+ IBinder windowToken, int windowType, boolean isPreview,
+ int reqWidth, int reqHeight);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 595b10c..629e97e 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -30,6 +30,7 @@
import android.util.Log;
import android.view.Gravity;
import android.view.IWindowSession;
+import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
@@ -58,6 +59,8 @@
private static final int MSG_UPDATE_SURFACE = 10000;
private static final int MSG_VISIBILITY_CHANGED = 10010;
private static final int MSG_WALLPAPER_OFFSETS = 10020;
+ private static final int MSG_WINDOW_RESIZED = 10030;
+ private static final int MSG_TOUCH_EVENT = 10040;
/**
* The actual implementation of a wallpaper. A wallpaper service may
@@ -86,6 +89,8 @@
int mType;
int mCurWidth;
int mCurHeight;
+ int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ int mCurWindowFlags = mWindowFlags;
boolean mDestroyReportNeeded;
final Rect mVisibleInsets = new Rect();
final Rect mWinFrame = new Rect();
@@ -99,6 +104,7 @@
boolean mOffsetMessageEnqueued;
float mPendingXOffset;
float mPendingYOffset;
+ MotionEvent mPendingMove;
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
@@ -130,6 +136,35 @@
};
final BaseIWindow mWindow = new BaseIWindow() {
+ @Override
+ public boolean onDispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ synchronized (mLock) {
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (mPendingMove != null) {
+ mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
+ mPendingMove.recycle();
+ }
+ mPendingMove = event;
+ } else {
+ mPendingMove = null;
+ }
+ Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
+ event);
+ mCaller.sendMessage(msg);
+ }
+ return false;
+ }
+
+ @Override
+ public void resized(int w, int h, Rect coveredInsets,
+ Rect visibleInsets, boolean reportDraw) {
+ Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+ reportDraw ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
public void dispatchAppVisibility(boolean visible) {
Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
visible ? 1 : 0);
@@ -177,6 +212,31 @@
}
/**
+ * Returns true if this engine is running in preview mode -- that is,
+ * it is being shown to the user before they select it as the actual
+ * wallpaper.
+ */
+ public boolean isPreview() {
+ return mIWallpaperEngine.mIsPreview;
+ }
+
+ /**
+ * Control whether this wallpaper will receive raw touch events
+ * from the window manager as the user interacts with the window
+ * that is currently displaying the wallpaper. By default they
+ * are turned off. If enabled, the events will be received in
+ * {@link #onTouchEvent(MotionEvent)}.
+ */
+ public void setTouchEventsEnabled(boolean enabled) {
+ mWindowFlags = enabled
+ ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ if (mCreated) {
+ updateSurface(false, false);
+ }
+ }
+
+ /**
* Called once to initialize the engine. After returning, the
* engine's surface will be created by the framework.
*/
@@ -200,6 +260,16 @@
}
/**
+ * Called as the user performs touch-screen interaction with the
+ * window that is currently showing this wallpaper. Note that the
+ * events you receive here are driven by the actual application the
+ * user is interacting with, so if it is slow you will get viewer
+ * move events.
+ */
+ public void onTouchEvent(MotionEvent event) {
+ }
+
+ /**
* Called to inform you of the wallpaper's offsets changing
* within its contain, corresponding to the container's
* call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float)
@@ -230,7 +300,7 @@
public void onSurfaceDestroyed(SurfaceHolder holder) {
}
- void updateSurface(boolean force) {
+ void updateSurface(boolean forceRelayout, boolean forceReport) {
int myWidth = mSurfaceHolder.getRequestedWidth();
if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
int myHeight = mSurfaceHolder.getRequestedHeight();
@@ -238,9 +308,11 @@
final boolean creating = !mCreated;
final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
- final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+ boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
- if (force || creating || formatChanged || sizeChanged || typeChanged) {
+ final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
+ if (forceRelayout || creating || formatChanged || sizeChanged
+ || typeChanged || flagsChanged) {
if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged);
@@ -251,26 +323,25 @@
mFormat = mSurfaceHolder.getRequestedFormat();
mType = mSurfaceHolder.getRequestedType();
- // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
- // Places the window relative
mLayout.x = 0;
mLayout.y = 0;
mLayout.width = myWidth;
mLayout.height = myHeight;
mLayout.format = mFormat;
- mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- ;
+
+ mCurWindowFlags = mWindowFlags;
+ mLayout.flags = mWindowFlags
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ ;
mLayout.memoryType = mType;
mLayout.token = mWindowToken;
if (!mCreated) {
- mLayout.type = WindowManager.LayoutParams.TYPE_WALLPAPER;
+ mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.LEFT|Gravity.TOP;
mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
}
@@ -286,8 +357,16 @@
if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
- mCurWidth = mWinFrame.width();
- mCurHeight = mWinFrame.height();
+ int w = mWinFrame.width();
+ if (mCurWidth != w) {
+ sizeChanged = true;
+ mCurWidth = w;
+ }
+ int h = mWinFrame.height();
+ if (mCurHeight != h) {
+ sizeChanged = true;
+ mCurHeight = h;
+ }
mSurfaceHolder.mSurfaceLock.unlock();
@@ -312,7 +391,14 @@
}
}
}
- if (creating || formatChanged || sizeChanged) {
+ if (forceReport || creating || formatChanged || sizeChanged) {
+ if (DEBUG) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating
+ + " formatChanged=" + formatChanged
+ + " sizeChanged=" + sizeChanged, e);
+ }
onSurfaceChanged(mSurfaceHolder, mFormat,
mCurWidth, mCurHeight);
if (callbacks != null) {
@@ -338,6 +424,7 @@
}
void attach(IWallpaperEngineWrapper wrapper) {
+ if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
mIWallpaperEngine = wrapper;
mCaller = wrapper.mCaller;
mConnection = wrapper.mConnection;
@@ -353,7 +440,7 @@
onCreate(mSurfaceHolder);
mInitializing = false;
- updateSurface(false);
+ updateSurface(false, false);
}
void detach() {
@@ -387,6 +474,8 @@
final IWallpaperConnection mConnection;
final IBinder mWindowToken;
+ final int mWindowType;
+ final boolean mIsPreview;
int mReqWidth;
int mReqHeight;
@@ -394,10 +483,12 @@
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
- int reqWidth, int reqHeight) {
+ int windowType, boolean isPreview, int reqWidth, int reqHeight) {
mCaller = new HandlerCaller(context, this);
mConnection = conn;
mWindowToken = windowToken;
+ mWindowType = windowType;
+ mIsPreview = isPreview;
mReqWidth = reqWidth;
mReqHeight = reqHeight;
@@ -429,7 +520,7 @@
return;
}
case MSG_UPDATE_SURFACE:
- mEngine.updateSurface(false);
+ mEngine.updateSurface(true, false);
break;
case MSG_VISIBILITY_CHANGED:
if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
@@ -452,6 +543,26 @@
final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
mEngine.onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
} break;
+ case MSG_WINDOW_RESIZED: {
+ final boolean reportDraw = message.arg1 != 0;
+ mEngine.updateSurface(true, false);
+ if (reportDraw) {
+ try {
+ mEngine.mSession.finishDrawing(mEngine.mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ } break;
+ case MSG_TOUCH_EVENT: {
+ MotionEvent ev = (MotionEvent)message.obj;
+ synchronized (mEngine.mLock) {
+ if (mEngine.mPendingMove == ev) {
+ mEngine.mPendingMove = null;
+ }
+ }
+ mEngine.onTouchEvent(ev);
+ ev.recycle();
+ } break;
default :
Log.w(TAG, "Unknown message type " + message.what);
}
@@ -469,10 +580,10 @@
mTarget = context;
}
- public void attach(IWallpaperConnection conn,
- IBinder windowToken, int reqWidth, int reqHeight) {
- new IWallpaperEngineWrapper(
- mTarget, conn, windowToken, reqWidth, reqHeight);
+ public void attach(IWallpaperConnection conn, IBinder windowToken,
+ int windowType, boolean isPreview, int reqWidth, int reqHeight) {
+ new IWallpaperEngineWrapper(mTarget, conn, windowToken,
+ windowType, isPreview, reqWidth, reqHeight);
}
}
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
deleted file mode 100644
index 2da2258..0000000
--- a/core/java/android/speech/IRecognitionListener.aidl
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech;
-
-import android.os.Bundle;
-import android.speech.RecognitionResult;
-
-/**
- * Listener for speech recognition events, used with RecognitionService.
- * This gives you both the final recognition results, as well as various
- * intermediate events that can be used to show visual feedback to the user.
- * {@hide}
- */
-interface IRecognitionListener {
- /** Called when the endpointer is ready for the user to start speaking. */
- void onReadyForSpeech(in Bundle noiseParams);
-
- /** The user has started to speak. */
- void onBeginningOfSpeech();
-
- /** The sound level in the audio stream has changed. */
- void onRmsChanged(in float rmsdB);
-
- /**
- * More sound has been received. Buffer is a byte buffer containing
- * a sequence of 16-bit shorts.
- */
- void onBufferReceived(in byte[] buffer);
-
- /** Called after the user stops speaking. */
- void onEndOfSpeech();
-
- /**
- * A network or recognition error occurred. The code is defined in
- * {@link android.speech.RecognitionResult}
- */
- void onError(in int error);
-
- /**
- * Called when recognition results are ready.
- * @param results: an ordered list of the most likely results (N-best list).
- * @param key: a key associated with the results. The same results can
- * be retrieved asynchronously later using the key, if available.
- */
- void onResults(in List<RecognitionResult> results, long key);
-}
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
deleted file mode 100644
index a18c380..0000000
--- a/core/java/android/speech/IRecognitionService.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech;
-
-import android.content.Intent;
-import android.speech.IRecognitionListener;
-import android.speech.RecognitionResult;
-
-// A Service interface to speech recognition. Call startListening when
-// you want to begin capturing audio; RecognitionService will automatically
-// determine when the user has finished speaking, stream the audio to the
-// recognition servers, and notify you when results are ready.
-/** {@hide} */
-interface IRecognitionService {
- // Start listening for speech. Can only call this from one thread at once.
- // see RecognizerIntent.java for constants used to specify the intent.
- void startListening(in Intent recognizerIntent,
- in IRecognitionListener listener);
-
- List<RecognitionResult> getRecognitionResults(in long key);
-
- void cancel();
-}
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
deleted file mode 100644
index 978106b..0000000
--- a/core/java/android/speech/RecognitionResult.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * 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.speech;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * RecognitionResult is a passive object that stores a single recognized
- * query and its search result.
- * TODO: revisit and improve. May be we should have a separate result
- * object for each type, and put them (type/value) in bundle?
- *
- * {@hide}
- */
-public class RecognitionResult implements Parcelable {
- /**
- * Status of the recognize request.
- */
- public static final int NETWORK_TIMEOUT = 1; // Network operation timed out.
- public static final int NETWORK_ERROR = 2; // Other networkrelated errors.
- public static final int AUDIO_ERROR = 3; // Audio recording error.
- public static final int SERVER_ERROR = 4; // Server sends error status.
- public static final int CLIENT_ERROR = 5; // Other client side errors.
- public static final int SPEECH_TIMEOUT = 6; // No speech input
- public static final int NO_MATCH = 7; // No recognition result matched.
- public static final int SERVICE_BUSY = 8; // RecognitionService busy.
-
- /**
- * Type of the recognition results.
- */
- public static final int RAW_RECOGNITION_RESULT = 0;
- public static final int WEB_SEARCH_RESULT = 1;
- public static final int CONTACT_RESULT = 2;
-
- /**
- * A factory method to create a raw RecognitionResult
- *
- * @param sentence the recognized text.
- */
- public static RecognitionResult newRawRecognitionResult(String sentence) {
- return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
- }
-
- /**
- * A factory method to create RecognitionResult for contacts.
- *
- * @param contact the contact name.
- * @param phoneType the phone type.
- * @param callAction whether this result included a command to "call", or just the contact name.
- */
- public static RecognitionResult newContactResult(String contact, int phoneType,
- boolean callAction) {
- return new RecognitionResult(CONTACT_RESULT, contact, phoneType, callAction);
- }
-
- /**
- * A factory method to create a RecognitionResult for Web Search Query.
- *
- * @param query the query string.
- * @param html the html page of the search result.
- * @param url the url that performs the search with the query.
- */
- public static RecognitionResult newWebResult(String query, String html, String url) {
- return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
- }
-
- public static final Parcelable.Creator<RecognitionResult> CREATOR
- = new Parcelable.Creator<RecognitionResult>() {
-
- public RecognitionResult createFromParcel(Parcel in) {
- return new RecognitionResult(in);
- }
-
- public RecognitionResult[] newArray(int size) {
- return new RecognitionResult[size];
- }
- };
-
- /**
- * Result type.
- */
- public final int mResultType;
-
- /**
- * The recognized string when mResultType is WEB_SEARCH_RESULT.
- * The name of the contact when mResultType is CONTACT_RESULT.
- */
- public final String mText;
-
- /**
- * The HTML result page for the query. If this is null, then the
- * application must use the url field to get the HTML result page.
- */
- public final String mHtml;
-
- /**
- * The url to get the result page for the query string. The
- * application must use this url instead of performing the search
- * with the query.
- */
- public final String mUrl;
-
- /**
- * Phone number type. This is valid only when mResultType == CONTACT_RESULT.
- */
- public final int mPhoneType;
-
- /**
- * Whether a contact recognition result included a command to "call". This is valid only
- * when mResultType == CONTACT_RESULT.
- */
- public final boolean mCallAction;
-
- private RecognitionResult(int type, String query, String html, String url) {
- mResultType = type;
- mText = query;
- mHtml = html;
- mUrl = url;
- mPhoneType = -1;
- mCallAction = false;
- }
-
- private RecognitionResult(int type, String query, int phoneType, boolean callAction) {
- mResultType = type;
- mText = query;
- mPhoneType = phoneType;
- mHtml = null;
- mUrl = null;
- mCallAction = callAction;
- }
-
- private RecognitionResult(Parcel in) {
- mResultType = in.readInt();
- mText = in.readString();
- mHtml= in.readString();
- mUrl= in.readString();
- mPhoneType = in.readInt();
- mCallAction = (in.readInt() == 1);
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mResultType);
- out.writeString(mText);
- out.writeString(mHtml);
- out.writeString(mUrl);
- out.writeInt(mPhoneType);
- out.writeInt(mCallAction ? 1 : 0);
- }
-
-
- @Override
- public String toString() {
- String resultType[] = { "RAW", "WEB", "CONTACT" };
- return "[type=" + resultType[mResultType] +
- ", text=" + mText+ ", mUrl=" + mUrl + ", html=" + mHtml + "]";
- }
-
- public int describeContents() {
- // no special description
- return 0;
- }
-}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
deleted file mode 100644
index a8c7868..0000000
--- a/core/java/android/speech/RecognitionServiceUtil.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.speech;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.speech.RecognitionResult;
-import android.util.Log;
-
-import java.util.List;
-
-/**
- * Utils for Google's network-based speech recognizer, which lets you perform
- * speech-to-text translation through RecognitionService. IRecognitionService
- * and IRecognitionListener are the core interfaces; you begin recognition
- * through IRecognitionService and subscribe to callbacks about when the user
- * stopped speaking, results come in, errors, etc. through IRecognitionListener.
- * RecognitionServiceUtil includes default IRecognitionListener and
- * ServiceConnection implementations to reduce the amount of boilerplate.
- *
- * The Service provides no user interface. See RecognitionActivity if you
- * want the standard voice search UI.
- *
- * Below is a small skeleton of how to use the recognizer:
- *
- * ServiceConnection conn = new RecognitionServiceUtil.Connection();
- * mContext.bindService(RecognitionServiceUtil.sDefaultIntent,
- * conn, Context.BIND_AUTO_CREATE);
- * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() {
- * public void onResults(List<String> results) {
- * // Do something with recognition transcripts
- * }
- * }
- *
- * // Must wait for conn.mService to be populated, then call below
- * conn.mService.startListening(null, listener);
- *
- * {@hide}
- */
-public class RecognitionServiceUtil {
- public static final Intent sDefaultIntent = new Intent(
- RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
-
- // Recognize request parameters
- public static final String USE_LOCATION = "useLocation";
- public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
-
- // Bundles
- public static final String NOISE_LEVEL = "NoiseLevel";
- public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
-
- private RecognitionServiceUtil() {}
-
- /**
- * IRecognitionListener which does nothing in response to recognition
- * callbacks. You can subclass from this and override only the methods
- * whose events you want to respond to.
- */
- public static class NullListener extends IRecognitionListener.Stub {
- public void onReadyForSpeech(Bundle bundle) {}
- public void onBeginningOfSpeech() {}
- public void onRmsChanged(float rmsdB) {}
- public void onBufferReceived(byte[] buf) {}
- public void onEndOfSpeech() {}
- public void onError(int error) {}
- public void onResults(List<RecognitionResult> results, long key) {}
- }
-
- /**
- * Basic ServiceConnection which just records mService variable.
- */
- public static class Connection implements ServiceConnection {
- public IRecognitionService mService;
-
- public synchronized void onServiceConnected(ComponentName name, IBinder service) {
- mService = IRecognitionService.Stub.asInterface(service);
- }
-
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- }
-}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 4405a53..a6d76d6 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -61,7 +61,7 @@
/**
- * Denotes the language is available exactly as specified by the locale
+ * Denotes the language is available exactly as specified by the locale.
*/
public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
@@ -176,7 +176,7 @@
// intents to ask engine to install data or check its data
/**
- * Broadcast Action: Triggers the platform Text-To-Speech engine to
+ * Activity Action: Triggers the platform Text-To-Speech engine to
* start the activity that installs the resource files on the device
* that are required for TTS to be operational. Since the installation
* of the data can be interrupted or declined by the user, the application
@@ -184,18 +184,20 @@
* and if need be, should check installation status with
* {@link #ACTION_CHECK_TTS_DATA}.
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_INSTALL_TTS_DATA =
"android.speech.tts.engine.INSTALL_TTS_DATA";
/**
- * {@hide}
+ * Broadcast Action: broadcast to signal the completion of the installation of
+ * the data files used by the synthesis engine. Success or failure is indicated in the
+ * {@link #EXTRA_TTS_DATA_INSTALLED} extra.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TTS_DATA_INSTALLED =
"android.speech.tts.engine.TTS_DATA_INSTALLED";
/**
- * Broadcast Action: Starts the activity from the platform Text-To-Speech
+ * Activity Action: Starts the activity from the platform Text-To-Speech
* engine to verify the proper installation and availability of the
* resource files on the system. Upon completion, the activity will
* return one of the following codes:
@@ -217,7 +219,7 @@
* and YYY is the 3-letter ISO country code.</li>
* </ul>
*/
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CHECK_TTS_DATA =
"android.speech.tts.engine.CHECK_TTS_DATA";
@@ -241,11 +243,11 @@
// extras for a TTS engine's data installation
/**
- * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent
- * which indicates whether the TTS data installation requested with
- * {@link #ACTION_INSTALL_TTS_DATA} completed successfully or not. The value is
- * {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
- * {@hide}
+ * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent.
+ * It indicates whether the data files for the synthesis engine were successfully
+ * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA}
+ * intent. The possible values for this extra are
+ * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
*/
public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
diff --git a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
index a0513f1..f2a2733 100644
--- a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
@@ -28,6 +28,7 @@
import android.syncml.pim.VBuilder;
import android.syncml.pim.VNode;
import android.syncml.pim.VParser;
+import android.text.TextUtils;
import android.util.CharsetUtils;
import android.util.Log;
@@ -403,7 +404,10 @@
String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
String encoding = paramMap.getAsString("ENCODING");
- if (targetCharset == null || targetCharset.length() == 0) {
+ Log.d("@@@", String.format("targetCharset: \"%s\", encoding: \"%s\"",
+ targetCharset, encoding));
+
+ if (TextUtils.isEmpty(targetCharset)) {
targetCharset = mTargetCharset;
}
diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java
index 6dad852d..9a590dd 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser.java
@@ -17,7 +17,6 @@
package android.syncml.pim.vcard;
import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VParser;
import android.util.Config;
import android.util.Log;
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 2145d7c..22d95d1 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -43,11 +43,25 @@
*
* @param instrumentation the instrumentation to use with this instance
*/
- public void injectInsrumentation(Instrumentation instrumentation) {
+ public void injectInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
/**
+ * Injects instrumentation into this test case. This method is
+ * called by the test runner during test setup.
+ *
+ * @param instrumentation the instrumentation to use with this instance
+ *
+ * @deprecated Incorrect spelling,
+ * use {@link #injectInstrumentation(android.app.Instrumentation) instead.
+ */
+ @Deprecated
+ public void injectInsrumentation(Instrumentation instrumentation) {
+ injectInstrumentation(instrumentation);
+ }
+
+ /**
* Inheritors can access the instrumentation using this.
* @return instrumentation
*/
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java
index 2ab949e..7a78ffb 100644
--- a/core/java/android/test/InstrumentationTestSuite.java
+++ b/core/java/android/test/InstrumentationTestSuite.java
@@ -65,7 +65,7 @@
public void runTest(Test test, TestResult result) {
if (test instanceof InstrumentationTestCase) {
- ((InstrumentationTestCase) test).injectInsrumentation(mInstrumentation);
+ ((InstrumentationTestCase) test).injectInstrumentation(mInstrumentation);
}
// run the test as usual
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 843754b..944f735 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -19,6 +19,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
+import android.text.style.ParagraphStyle;
import android.util.FloatMath;
/**
@@ -262,6 +263,14 @@
TextUtils.recycle(temp);
+ if (boring && text instanceof Spanned) {
+ Spanned sp = (Spanned) text;
+ Object[] styles = sp.getSpans(0, text.length(), ParagraphStyle.class);
+ if (styles.length > 0) {
+ boring = false;
+ }
+ }
+
if (boring) {
Metrics fm = metrics;
if (fm == null) {
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 86ef5f6..74b9463 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -36,6 +36,7 @@
/**
* @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead.
*/
+ @Deprecated
public ImageSpan(Bitmap b) {
this(null, b, ALIGN_BOTTOM);
}
@@ -43,6 +44,7 @@
/**
* @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead.
*/
+ @Deprecated
public ImageSpan(Bitmap b, int verticalAlignment) {
this(null, b, verticalAlignment);
}
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
index 9571041..924b49d 100644
--- a/core/java/android/util/Config.java
+++ b/core/java/android/util/Config.java
@@ -34,25 +34,25 @@
*/
/**
- * Always the inverse of DEBUG.
+ * @deprecated Use {@link #DEBUG} instead.
*/
@Deprecated
public static final boolean RELEASE = !DEBUG;
/**
- * Always false.
+ * @deprecated Always false.
*/
@Deprecated
public static final boolean PROFILE = false;
/**
- * Always false.
+ * @deprecated Always false.
*/
@Deprecated
public static final boolean LOGV = false;
/**
- * Always true.
+ * @deprecated Always true.
*/
@Deprecated
public static final boolean LOGD = true;
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index dd5a440..74f01cc 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -24,6 +24,9 @@
/**
* A structure describing general information about a display, such as its
* size, density, and font scaling.
+ * <p>To access the DisplayMetrics members, initialize an object like this:</p>
+ * <pre> DisplayMetrics metrics = new DisplayMetrics();
+ * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
*/
public class DisplayMetrics {
/**
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index ec2036e..ebc5f7b 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,8 +46,8 @@
void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
boolean reportDraw);
void dispatchKey(in KeyEvent event);
- void dispatchPointer(in MotionEvent event, long eventTime);
- void dispatchTrackball(in MotionEvent event, long eventTime);
+ void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
+ void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index e8bfa6a..b2f0c60 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -552,6 +552,44 @@
}
/**
+ * Create a new MotionEvent, copying from an existing one, but not including
+ * any historical point information.
+ */
+ static public MotionEvent obtainNoHistory(MotionEvent o) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = o.mDeviceId;
+ ev.mEdgeFlags = o.mEdgeFlags;
+ ev.mDownTime = o.mDownTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
+ ev.mAction = o.mAction;
+ ev.mNumPointers = o.mNumPointers;
+ ev.mRawX = o.mRawX;
+ ev.mRawY = o.mRawY;
+ ev.mMetaState = o.mMetaState;
+ ev.mXPrecision = o.mXPrecision;
+ ev.mYPrecision = o.mYPrecision;
+
+ ev.mNumSamples = 1;
+ ev.mTimeSamples[0] = o.mTimeSamples[0];
+
+ final int NP = (ev.mNumPointers=o.mNumPointers);
+ if (ev.mPointerIdentifiers.length >= NP) {
+ System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
+ } else {
+ ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
+ }
+
+ final int ND = NP * NUM_SAMPLE_DATA;
+ if (ev.mDataSamples.length >= ND) {
+ System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
+ } else {
+ ev.mDataSamples = (float[])o.mDataSamples.clone();
+ }
+
+ return ev;
+ }
+
+ /**
* Recycle the MotionEvent, to be re-used by a later caller. After calling
* this function you must not ever touch the event again.
*/
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
index db024b4..8b3cdd4 100644
--- a/core/java/android/view/RawInputEvent.java
+++ b/core/java/android/view/RawInputEvent.java
@@ -171,6 +171,9 @@
public static final int ABS_MT_BLOB_ID = 0x38;
public static final int ABS_MAX = 0x3f;
+ // Switch events
+ public static final int SW_LID = 0x00;
+
public static final int SYN_REPORT = 0;
public static final int SYN_CONFIG = 1;
public static final int SYN_MT_REPORT = 2;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 9ec1013..5cecac3 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -246,7 +246,7 @@
};
/**
- * Sets the display metrics used to provide canva's width/height in comaptibility mode.
+ * Sets the display metrics used to provide canva's width/height in compatibility mode.
*/
void setCompatibleDisplayMetrics(DisplayMetrics metrics, Translator translator) {
mCompatibleDisplayMetrics = metrics;
@@ -275,7 +275,8 @@
public native void clear();
/** draw into a surface */
- public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException {
+ public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException
+ {
/* the dirty rectangle may be expanded to the surface's size, if
* for instance it has been resized or if the bits were lost, since
* the last call.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 3b64945..ea879ed9 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -481,7 +481,8 @@
}
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
//if (mSession != null && mSurface != null) {
// try {
@@ -491,7 +492,8 @@
//}
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
//if (mSession != null && mSurface != null) {
// try {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 4623bb5..fe3f47f 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -686,7 +686,6 @@
attachInfo.mKeepScreenOn = false;
viewVisibilityChanged = false;
host.dispatchAttachedToWindow(attachInfo, 0);
- getRunQueue().executeActions(attachInfo.mHandler);
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
@@ -719,6 +718,10 @@
boolean insetsChanged = false;
if (mLayoutRequested) {
+ // Execute enqueued actions on every layout in case a view that was detached
+ // enqueued an action after being detached
+ getRunQueue().executeActions(attachInfo.mHandler);
+
if (mFirst) {
host.fitSystemWindows(mAttachInfo.mContentInsets);
// make sure touch mode code executes by setting cached value
@@ -1637,8 +1640,8 @@
break;
case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent)msg.obj;
-
- boolean didFinish;
+ boolean callWhenDone = msg.arg1 != 0;
+
if (event == null) {
try {
long timeBeforeGettingEvents;
@@ -1654,9 +1657,7 @@
}
} catch (RemoteException e) {
}
- didFinish = true;
- } else {
- didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
+ callWhenDone = false;
}
if (event != null && mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
@@ -1728,7 +1729,7 @@
}
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -1743,7 +1744,7 @@
}
} break;
case DISPATCH_TRACKBALL:
- deliverTrackballEvent((MotionEvent)msg.obj);
+ deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
break;
case DISPATCH_APP_VISIBILITY:
handleAppVisibility(msg.arg1 != 0);
@@ -1985,16 +1986,13 @@
}
- private void deliverTrackballEvent(MotionEvent event) {
- boolean didFinish;
+ private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
if (event == null) {
try {
event = sWindowSession.getPendingTrackballMove(mWindow);
} catch (RemoteException e) {
}
- didFinish = true;
- } else {
- didFinish = false;
+ callWhenDone = false;
}
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
@@ -2012,7 +2010,7 @@
}
} finally {
if (handled) {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2128,7 +2126,7 @@
mLastTrackballTime = curTime;
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2591,15 +2589,19 @@
sendMessageAtTime(msg, event.getEventTime());
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Message msg = obtainMessage(DISPATCH_POINTER);
msg.obj = event;
+ msg.arg1 = callWhenDone ? 1 : 0;
sendMessageAtTime(msg, eventTime);
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Message msg = obtainMessage(DISPATCH_TRACKBALL);
msg.obj = event;
+ msg.arg1 = callWhenDone ? 1 : 0;
sendMessageAtTime(msg, eventTime);
}
@@ -2772,23 +2774,25 @@
}
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
if (MEASURE_LATENCY) {
// Note: eventTime is in milliseconds
ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000);
}
- viewRoot.dispatchPointer(event, eventTime);
+ viewRoot.dispatchPointer(event, eventTime, callWhenDone);
} else {
new EventCompletion(mMainLooper, this, null, true, event);
}
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
- viewRoot.dispatchTrackball(event, eventTime);
+ viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
} else {
new EventCompletion(mMainLooper, this, null, false, event);
}
@@ -3141,7 +3145,7 @@
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
- mActions.clear();
+ actions.clear();
}
}
@@ -3155,7 +3159,6 @@
if (o == null || getClass() != o.getClass()) return false;
HandlerAction that = (HandlerAction) o;
-
return !(action != null ? !action.equals(that.action) : that.action != null);
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 02e0515..1932765 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -237,7 +237,6 @@
/**
* This is called whenever the current window attributes change.
*
-
*/
public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);
@@ -252,13 +251,29 @@
public void onContentChanged();
/**
- * This hook is called whenever the window focus changes.
+ * This hook is called whenever the window focus changes. See
+ * {@link View#onWindowFocusChanged(boolean)
+ * View.onWindowFocusChanged(boolean)} for more information.
*
* @param hasFocus Whether the window now has focus.
*/
public void onWindowFocusChanged(boolean hasFocus);
/**
+ * Called when the window has been attached to the window manager.
+ * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
+ * for more information.
+ */
+ public void onAttachedToWindow();
+
+ /**
+ * Called when the window has been attached to the window manager.
+ * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}
+ * for more information.
+ */
+ public void onDetachedFromWindow();
+
+ /**
* Called when a panel is being closed. If another logical subsequent
* panel is being opened (and this panel is being closed to make room for the subsequent
* panel), this method will NOT be called.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index f4e9900..ea08f33 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -344,6 +344,12 @@
public final int TRANSIT_TASK_TO_FRONT = 10;
/** A window in an existing task is being put below all other tasks. */
public final int TRANSIT_TASK_TO_BACK = 11;
+ /** A window in a new activity is being opened on top of an existing one,
+ * and both are on top of the wallpaper. */
+ public final int TRANSIT_WALLPAPER_ACTIVITY_OPEN = 12;
+ /** The window in the top-most activity is being closed to reveal the
+ * previous activity, and both are on top of he wallpaper. */
+ public final int TRANSIT_WALLPAPER_ACTIVITY_CLOSE = 13;
/** Screen turned off because of power button */
public final int OFF_BECAUSE_OF_USER = 1;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index a662760..2f5e601 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -319,7 +319,7 @@
*
* @param durationMillis Duration in milliseconds
*
- * @throw java.lang.IllegalArgumentException if the duration is < 0
+ * @throws java.lang.IllegalArgumentException if the duration is < 0
*
* @attr ref android.R.styleable#Animation_duration
*/
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index afa2c35..ce27fd7f9 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -343,17 +343,16 @@
switch (msg.what) {
case FRAME_COMPLETED: {
if (mSettings.getSavePassword() && hasPasswordField()) {
- if (DebugFlags.BROWSER_FRAME) {
- Assert.assertNotNull(mCallbackProxy.getBackForwardList()
- .getCurrentItem());
- }
- WebAddress uri = new WebAddress(
- mCallbackProxy.getBackForwardList().getCurrentItem()
- .getUrl());
- String schemePlusHost = uri.mScheme + uri.mHost;
- String[] up = mDatabase.getUsernamePassword(schemePlusHost);
- if (up != null && up[0] != null) {
- setUsernamePassword(up[0], up[1]);
+ WebHistoryItem item = mCallbackProxy.getBackForwardList()
+ .getCurrentItem();
+ if (item != null) {
+ WebAddress uri = new WebAddress(item.getUrl());
+ String schemePlusHost = uri.mScheme + uri.mHost;
+ String[] up =
+ mDatabase.getUsernamePassword(schemePlusHost);
+ if (up != null && up[0] != null) {
+ setUsernamePassword(up[0], up[1]);
+ }
}
}
CacheManager.trimCacheIfNeeded();
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 96bf46e..41e604d 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -177,6 +177,17 @@
}
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param newViewingMode One of the values described in WebView as possible
+ * values for the viewing mode
+ */
+ /* package */ void uiOnChangeViewingMode(int newViewingMode) {
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onChangeViewingMode(mWebView, newViewingMode);
+ }
+ }
+
+ /**
* Called by the UI side. Calling overrideUrlLoading from the WebCore
* side will post a message to call this method.
*/
@@ -423,12 +434,14 @@
((Long) map.get("currentQuota")).longValue();
long totalUsedQuota =
((Long) map.get("totalUsedQuota")).longValue();
+ long estimatedSize =
+ ((Long) map.get("estimatedSize")).longValue();
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
mWebChromeClient.onExceededDatabaseQuota(url,
- databaseIdentifier, currentQuota, totalUsedQuota,
- quotaUpdater);
+ databaseIdentifier, currentQuota, estimatedSize,
+ totalUsedQuota, quotaUpdater);
}
break;
@@ -1184,6 +1197,7 @@
* @param databaseIdentifier The identifier of the database that the
* transaction that caused the overflow was running on.
* @param currentQuota The current quota the origin is allowed.
+ * @param estimatedSize The estimated size of the database.
* @param totalUsedQuota is the sum of all origins' quota.
* @param quotaUpdater An instance of a class encapsulating a callback
* to WebViewCore to run when the decision to allow or deny more
@@ -1191,7 +1205,8 @@
*/
public void onExceededDatabaseQuota(
String url, String databaseIdentifier, long currentQuota,
- long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ long estimatedSize, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
if (mWebChromeClient == null) {
quotaUpdater.updateQuota(currentQuota);
return;
@@ -1202,6 +1217,7 @@
map.put("databaseIdentifier", databaseIdentifier);
map.put("url", url);
map.put("currentQuota", currentQuota);
+ map.put("estimatedSize", estimatedSize);
map.put("totalUsedQuota", totalUsedQuota);
map.put("quotaUpdater", quotaUpdater);
exceededQuota.obj = map;
diff --git a/core/java/android/webkit/ContentLoader.java b/core/java/android/webkit/ContentLoader.java
index f6d7f69..27cd6b5 100644
--- a/core/java/android/webkit/ContentLoader.java
+++ b/core/java/android/webkit/ContentLoader.java
@@ -105,8 +105,7 @@
if (mContentType != null) {
headers.setContentType("text/html");
}
- // override the cache-control header set by StreamLoader as content can
- // change, we don't want WebKit to cache it
+ // content can change, we don't want WebKit to cache it
headers.setCacheControl("no-store, no-cache");
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index d188a39..fca591f 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -833,22 +833,24 @@
// "secure" is a known attribute doesn't use "=";
// while sites like live.com uses "secure="
- if (length - index > SECURE_LENGTH
+ if (length - index >= SECURE_LENGTH
&& cookieString.substring(index, index + SECURE_LENGTH).
equalsIgnoreCase(SECURE)) {
index += SECURE_LENGTH;
cookie.secure = true;
+ if (index == length) break;
if (cookieString.charAt(index) == EQUAL) index++;
continue;
}
// "httponly" is a known attribute doesn't use "=";
// while sites like live.com uses "httponly="
- if (length - index > HTTP_ONLY_LENGTH
+ if (length - index >= HTTP_ONLY_LENGTH
&& cookieString.substring(index,
index + HTTP_ONLY_LENGTH).
equalsIgnoreCase(HTTP_ONLY)) {
index += HTTP_ONLY_LENGTH;
+ if (index == length) break;
if (cookieString.charAt(index) == EQUAL) index++;
// FIXME: currently only parse the attribute
continue;
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 81ed367..c1eeb3b 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -128,6 +128,18 @@
/* package */
static boolean handleLocalFile(String url, LoadListener loadListener,
WebSettings settings) {
+ // Attempt to decode the percent-encoded url before passing to the
+ // local loaders.
+ try {
+ url = new String(URLUtil.decode(url.getBytes()));
+ } catch (IllegalArgumentException e) {
+ loadListener.error(EventHandler.ERROR_BAD_URL,
+ loadListener.getContext().getString(
+ com.android.internal.R.string.httpErrorBadUrl));
+ // Return true here so we do not trigger an unsupported scheme
+ // error.
+ return true;
+ }
if (URLUtil.isAssetUrl(url)) {
FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
true, settings.getAllowFileAccess());
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 21bcdf17..ddc2da1 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -90,7 +90,7 @@
break;
case REFRESH_PLUGINS:
nativeUpdatePluginDirectories(PluginManager.getInstance(null)
- .getPluginDirecoties(), ((Boolean) msg.obj)
+ .getPluginDirectories(), ((Boolean) msg.obj)
.booleanValue());
break;
}
@@ -182,7 +182,7 @@
* Returns an array of plugin directoies
*/
private String[] getPluginDirectories() {
- return PluginManager.getInstance(null).getPluginDirecoties();
+ return PluginManager.getInstance(null).getPluginDirectories();
}
/**
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 7fff014..43c76a8 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -99,6 +99,7 @@
private boolean mAuthFailed; // indicates that the prev. auth failed
private CacheLoader mCacheLoader;
private CacheManager.CacheResult mCacheResult;
+ private boolean mFromCache = false;
private HttpAuthHeader mAuthHeader;
private int mErrorID = OK;
private String mErrorDescription;
@@ -409,11 +410,10 @@
mStatusCode == HTTP_MOVED_PERMANENTLY ||
mStatusCode == HTTP_TEMPORARY_REDIRECT) &&
mNativeLoader != 0) {
- // Content arriving from a StreamLoader (eg File, Cache or Data)
- // will not be cached as they have the header:
- // cache-control: no-store
- mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
- headers, mMimeType, false);
+ if (!mFromCache && URLUtil.isNetworkUrl(mUrl)) {
+ mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
+ headers, mMimeType, false);
+ }
if (mCacheResult != null) {
mCacheResult.encoding = mEncoding;
}
@@ -626,6 +626,7 @@
* serviced by the Cache. */
/* package */ void setCacheLoader(CacheLoader c) {
mCacheLoader = c;
+ mFromCache = true;
}
/**
@@ -642,6 +643,8 @@
// Go ahead and set the cache loader to null in case the result is
// null.
mCacheLoader = null;
+ // reset the flag
+ mFromCache = false;
if (result != null) {
// The contents of the cache may need to be revalidated so just
@@ -662,6 +665,7 @@
}
// Load the cached file
mCacheLoader.load();
+ mFromCache = true;
return true;
}
}
@@ -681,6 +685,17 @@
" primary error: " + error.getPrimaryError() +
" certificate: " + error.getCertificate());
}
+ // Check the cached preference table before sending a message. This
+ // will prevent waiting for an already available answer.
+ if (Network.getInstance(mContext).checkSslPrefTable(this, error)) {
+ return true;
+ }
+ // Do not post a message for a synchronous request. This will cause a
+ // deadlock. Just bail on the request.
+ if (isSynchronous()) {
+ mRequestHandle.handleSslErrorResponse(false);
+ return true;
+ }
sendMessageInternal(obtainMessage(MSG_SSL_ERROR, error));
// if it has been canceled, return false so that the network thread
// won't be blocked. If it is not canceled, save the mRequestHandle
diff --git a/core/java/android/webkit/MockGeolocation.java b/core/java/android/webkit/MockGeolocation.java
new file mode 100644
index 0000000..028cb19
--- /dev/null
+++ b/core/java/android/webkit/MockGeolocation.java
@@ -0,0 +1,59 @@
+/*
+ * 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.webkit;
+
+/**
+ * This class is simply a container for the methods used to configure WebKit's
+ * mock Geolocation service for use in LayoutTests.
+ * @hide Pending API council review.
+ */
+public final class MockGeolocation {
+
+ // Global instance of a MockGeolocation
+ private static MockGeolocation sMockGeolocation;
+
+ /**
+ * Set the position for the mock Geolocation service.
+ */
+ public void setPosition(double latitude, double longitude, double accuracy) {
+ // This should only ever be called on the WebKit thread.
+ nativeSetPosition(latitude, longitude, accuracy);
+ }
+
+ /**
+ * Set the error for the mock Geolocation service.
+ */
+ public void setError(int code, String message) {
+ // This should only ever be called on the WebKit thread.
+ nativeSetError(code, message);
+ }
+
+ /**
+ * Get the global instance of MockGeolocation.
+ * @return The global MockGeolocation instance.
+ */
+ public static MockGeolocation getInstance() {
+ if (sMockGeolocation == null) {
+ sMockGeolocation = new MockGeolocation();
+ }
+ return sMockGeolocation;
+ }
+
+ // Native functions
+ private static native void nativeSetPosition(double latitude, double longitude, double accuracy);
+ private static native void nativeSetError(int code, String message);
+}
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 0b9e596..af0cb1e 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -304,6 +304,14 @@
}
}
+ /* package */ boolean checkSslPrefTable(LoadListener loader,
+ SslError error) {
+ if (loader != null && error != null) {
+ return mSslErrorHandler.checkSslPrefTable(loader, error);
+ }
+ return false;
+ }
+
/**
* Handles authentication requests on their way up to the user (the user
* must provide credentials).
diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java
index 302bea2..34a30a9 100644
--- a/core/java/android/webkit/Plugin.java
+++ b/core/java/android/webkit/Plugin.java
@@ -27,7 +27,7 @@
* Represents a plugin (Java equivalent of the PluginPackageAndroid
* C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/)
*
- * @deprecated This interface was inteded to be used by Gears. Since Gears was
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@Deprecated
@@ -43,7 +43,8 @@
private PreferencesClickHandler mHandler;
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public Plugin(String name,
@@ -58,7 +59,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public String toString() {
@@ -66,7 +68,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public String getName() {
@@ -74,7 +77,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public String getPath() {
@@ -82,7 +86,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public String getFileName() {
@@ -90,7 +95,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public String getDescription() {
@@ -98,7 +104,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void setName(String name) {
@@ -106,7 +113,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void setPath(String path) {
@@ -114,7 +122,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void setFileName(String fileName) {
@@ -122,7 +131,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void setDescription(String description) {
@@ -130,7 +140,8 @@
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void setClickHandler(PreferencesClickHandler handler) {
@@ -140,7 +151,8 @@
/**
* Invokes the click handler for this plugin.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void dispatchClickEvent(Context context) {
@@ -152,7 +164,8 @@
/**
* Default click handler. The plugins should implement their own.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
private class DefaultClickHandler implements PreferencesClickHandler,
@@ -172,7 +185,8 @@
}
}
/**
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public void onClick(DialogInterface dialog, int which) {
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index d9b196a..2dd445e 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -28,7 +28,7 @@
* status code. The PluginData class is the container for all these
* parts.
*
- * @deprecated This class was inteded to be used by Gears. Since Gears was
+ * @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@Deprecated
@@ -63,7 +63,8 @@
* lowercase header name to [ unmodified header name, header value]
* @param length The HTTP response status code.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public PluginData(
@@ -82,7 +83,8 @@
*
* @return An InputStream instance with the plugin content.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public InputStream getInputStream() {
@@ -94,7 +96,8 @@
*
* @return the length of the plugin content.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public long getContentLength() {
@@ -109,7 +112,8 @@
* mapping is 'lowercase header name' to ['unmodified header
* name', header value].
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public Map<String, String[]> getHeaders() {
@@ -121,7 +125,8 @@
*
* @return The HTTP statue code, e.g 200.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public int getStatusCode() {
diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java
index 5b65b9a..a61b07b 100644
--- a/core/java/android/webkit/PluginList.java
+++ b/core/java/android/webkit/PluginList.java
@@ -25,7 +25,7 @@
* populated when the plugins are initialized (at
* browser startup, at the moment).
*
- * @deprecated This interface was inteded to be used by Gears. Since Gears was
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@Deprecated
@@ -35,7 +35,8 @@
/**
* Public constructor. Initializes the list of plugins.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public PluginList() {
@@ -45,7 +46,8 @@
/**
* Returns the list of plugins as a java.util.List.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public synchronized List getList() {
@@ -55,7 +57,8 @@
/**
* Adds a plugin to the list.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public synchronized void addPlugin(Plugin plugin) {
@@ -67,7 +70,8 @@
/**
* Removes a plugin from the list.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public synchronized void removePlugin(Plugin plugin) {
@@ -80,7 +84,8 @@
/**
* Clears the plugin list.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public synchronized void clear() {
@@ -90,7 +95,8 @@
/**
* Dispatches the click event to the appropriate plugin.
*
- * @deprecated
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public synchronized void pluginClicked(Context context, int position) {
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index 370d3d2..32eea5f 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -91,7 +91,7 @@
.sendToTarget();
}
- String[] getPluginDirecoties() {
+ String[] getPluginDirectories() {
ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
@@ -147,11 +147,7 @@
}
directories.add(directory);
}
- // hack for gears for now
- String gears = mContext.getDir("plugins", 0).getPath();
- if (!directories.contains(gears)) {
- directories.add(gears);
- }
+
return directories.toArray(new String[directories.size()]);
}
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 5011244..90ed65d 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -58,7 +58,9 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_RESPONSE:
- handleSslErrorResponse(msg.arg1 == 1);
+ LoadListener loader = (LoadListener) msg.obj;
+ handleSslErrorResponse(loader, loader.sslError(),
+ msg.arg1 == 1);
fastProcessQueuedSslErrors();
break;
}
@@ -76,7 +78,7 @@
* Saves this handler's state into a map.
* @return True iff succeeds.
*/
- /* package */ boolean saveState(Bundle outState) {
+ /* package */ synchronized boolean saveState(Bundle outState) {
boolean success = (outState != null);
if (success) {
// TODO?
@@ -90,7 +92,7 @@
* Restores this handler's state from a map.
* @return True iff succeeds.
*/
- /* package */ boolean restoreState(Bundle inState) {
+ /* package */ synchronized boolean restoreState(Bundle inState) {
boolean success = (inState != null);
if (success) {
success = inState.containsKey("ssl-error-handler");
@@ -127,6 +129,28 @@
}
/**
+ * Check the preference table for a ssl error that has already been shown
+ * to the user.
+ */
+ /* package */ synchronized boolean checkSslPrefTable(LoadListener loader,
+ SslError error) {
+ final String host = loader.host();
+ final int primary = error.getPrimaryError();
+
+ if (DebugFlags.SSL_ERROR_HANDLER) {
+ Assert.assertTrue(host != null && primary != 0);
+ }
+
+ if (mSslPrefTable.containsKey(host)) {
+ if (primary <= mSslPrefTable.getInt(host)) {
+ handleSslErrorResponse(loader, error, true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Processes queued SSL-error confirmation requests in
* a tight loop while there is no need to ask the user.
*/
@@ -144,7 +168,9 @@
if (loader != null) {
// if this loader has been cancelled
if (loader.cancelled()) {
- // go to the following loader in the queue
+ // go to the following loader in the queue. Make sure this
+ // loader has been removed from the queue.
+ mLoaderQueue.remove(loader);
return true;
}
@@ -154,18 +180,12 @@
Assert.assertNotNull(error);
}
- int primary = error.getPrimaryError();
- String host = loader.host();
-
- if (DebugFlags.SSL_ERROR_HANDLER) {
- Assert.assertTrue(host != null && primary != 0);
- }
-
- if (mSslPrefTable.containsKey(host)) {
- if (primary <= mSslPrefTable.getInt(host)) {
- handleSslErrorResponse(true);
- return true;
- }
+ // checkSslPrefTable will handle the ssl error response if the
+ // answer is available. It does not remove the loader from the
+ // queue.
+ if (checkSslPrefTable(loader, error)) {
+ mLoaderQueue.remove(loader);
+ return true;
}
// if we do not have information on record, ask
@@ -182,7 +202,7 @@
* Proceed with the SSL certificate.
*/
public void proceed() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0));
+ sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0, mLoaderQueue.poll()));
}
/**
@@ -190,16 +210,17 @@
* the error.
*/
public void cancel() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0));
+ sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0, mLoaderQueue.poll()));
}
/**
* Handles SSL error(s) on the way down from the user.
*/
- /* package */ synchronized void handleSslErrorResponse(boolean proceed) {
- LoadListener loader = mLoaderQueue.poll();
+ /* package */ synchronized void handleSslErrorResponse(LoadListener loader,
+ SslError error, boolean proceed) {
if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(loader);
+ Assert.assertNotNull(error);
}
if (DebugFlags.SSL_ERROR_HANDLER) {
@@ -211,7 +232,7 @@
if (!loader.cancelled()) {
if (proceed) {
// update the user's SSL error preference table
- int primary = loader.sslError().getPrimaryError();
+ int primary = error.getPrimaryError();
String host = loader.host();
if (DebugFlags.SSL_ERROR_HANDLER) {
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index eab3350..623ff29 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -157,7 +157,6 @@
if (mContentLength > 0) {
headers.setContentLength(mContentLength);
}
- headers.setCacheControl(NO_STORE);
buildHeaders(headers);
mHandler.headers(headers);
}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 5ed42e9..232ed36 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -172,6 +172,7 @@
* requests from a file url.
* @deprecated Cookieless proxy is no longer supported.
*/
+ @Deprecated
public static boolean isCookielessProxyUrl(String url) {
return (null != url) && url.startsWith(PROXY_BASE);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index 6e2a482..eca5acd 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -25,7 +25,7 @@
import java.util.Map;
/**
- * @deprecated This class was inteded to be used by Gears. Since Gears was
+ * @deprecated This class was intended to be used by Gears. Since Gears was
* deprecated, so is this class.
*/
@Deprecated
@@ -48,7 +48,8 @@
*
* @param disabled true to disable the cache
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized void setUrlInterceptDisabled(boolean disabled) {
@@ -60,7 +61,8 @@
*
* @return return if it is disabled
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized boolean urlInterceptDisabled() {
@@ -74,7 +76,8 @@
* @param handler The new UrlInterceptHandler object
* @return true if the handler was not previously registered.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized boolean registerHandler(
@@ -93,7 +96,8 @@
* @param handler A previously registered UrlInterceptHandler.
* @return true if the handler was found and removed from the list.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized boolean unregisterHandler(
@@ -107,7 +111,8 @@
*
* @return A CacheResult containing surrogate content.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized CacheResult getSurrogate(
@@ -133,7 +138,8 @@
*
* @return A PluginData instance containing surrogate content.
*
- * @deprecated
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized PluginData getPluginData(
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index c10bc97..ad4ba05 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -23,6 +23,15 @@
public class WebChromeClient {
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param view The WebView that initiated the callback.
+ * @param newViewingMode One of the values described in WebView as possible
+ * values for the viewing mode
+ * @hide
+ */
+ public void onChangeViewingMode(WebView view, int newViewingMode) {}
+
+ /**
* Tell the host application the current progress of loading a page.
* @param view The WebView that initiated the callback.
* @param newProgress Current page loading progress, represented by
@@ -206,13 +215,14 @@
* @param databaseIdentifier The identifier of the database that caused the
* quota overflow.
* @param currentQuota The current quota for the origin.
+ * @param estimatedSize The estimated size of the database.
* @param totalUsedQuota is the sum of all origins' quota.
* @param quotaUpdater A callback to inform the WebCore thread that a new
* quota is available. This callback must always be executed at some
* point to ensure that the sleeping WebCore thread is woken up.
*/
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
- long currentQuota, long totalUsedQuota,
+ long currentQuota, long estimatedSize, long totalUsedQuota,
WebStorage.QuotaUpdater quotaUpdater) {
// This default implementation passes the current quota back to WebCore.
// WebCore will interpret this that new quota was declined.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index eeac1d2..e8b2702 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -167,10 +167,12 @@
private boolean mDatabaseEnabled = false;
private boolean mDomStorageEnabled = false;
private boolean mWorkersEnabled = false; // only affects V8.
+ private boolean mGeolocationEnabled = false;
// HTML5 configuration parameters
private long mAppCacheMaxSize = Long.MAX_VALUE;
private String mAppCachePath = "";
private String mDatabasePath = "";
+ private String mGeolocationDatabasePath = "";
// Don't need to synchronize the get/set methods as they
// are basic types, also none of these values are used in
// native WebCore code.
@@ -977,6 +979,21 @@
}
/**
+ * Set the path where the Geolocation permissions database should be saved.
+ * This will update WebCore when the Sync runs in the C++ side.
+ * @param databasePath String path to the directory where the Geolocation
+ * permissions database should be saved. May be the empty string but
+ * should never be null.
+ * @hide pending api council approval
+ */
+ public synchronized void setGeolocationDatabasePath(String databasePath) {
+ if (databasePath != null && !databasePath.equals(mDatabasePath)) {
+ mGeolocationDatabasePath = databasePath;
+ postSync();
+ }
+ }
+
+ /**
* Tell the WebView to enable Application Caches API.
* @param flag True if the WebView should enable Application Caches.
* @hide pending api council approval
@@ -1082,6 +1099,18 @@
}
/**
+ * Sets whether Geolocation is enabled.
+ * @param flag Whether Geolocation should be enabled.
+ * @hide pending api council approval
+ */
+ public synchronized void setGeolocationEnabled(boolean flag) {
+ if (mGeolocationEnabled != flag) {
+ mGeolocationEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
* Return true if javascript is enabled. <b>Note: The default is false.</b>
* @return True if javascript is enabled.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index be9daa5..196c66b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -521,6 +521,49 @@
// follow the links. Double tap will toggle between zoom overview mode and
// the last zoom scale.
boolean mInZoomOverview = false;
+
+ // The viewing mode of this webview. Reported back to the WebChromeClient
+ // so we can hide and display the title bar as appropriate.
+ private int mViewingMode;
+ /**
+ * Not supporting overview vs reading mode
+ * @hide
+ */
+ public final static int NO_VIEWING_MODE = 0;
+ /**
+ * Zoom overview mode. The page is zoomed all the way out, mInZoomOverview
+ * is true, and the title bar is showing. Double tapping will change to
+ * reading mode.
+ * @hide
+ */
+ public final static int OVERVIEW_MODE = 1;
+ /**
+ * Reading mode. The page is at the level specified by the user,
+ * mInZoomOverview is false, and the title bar is not showing. Double
+ * tapping will change to zoom overview mode.
+ * @hide
+ */
+ public final static int READING_MODE = 2;
+ /**
+ * Modified reading mode, which shows the title bar. mInZoomOverview is
+ * false, and double tapping will change to zoom overview mode. However,
+ * if the scrolling will change to reading mode. Used when swiping a
+ * tab into view which was in reading mode, unless it was a mobile site
+ * with zero scroll.
+ * @hide
+ */
+ public final static int READING_MODE_WITH_TITLE_BAR = 3;
+ /**
+ * Another modified reading mode. For loading a mobile site, or swiping a
+ * tab into view which was displaying a mobile site in reading mode
+ * with zero scroll
+ * @hide
+ */
+ public final static int TITLE_BAR_DISMISS_MODE = 4;
+ // Whether the current site is a mobile site. Determined when we receive
+ // NEW_PICTURE_MSG_ID to help determine how to handle double taps
+ private boolean mMobileSite;
+
// ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
// engadget always have wider mContentWidth no matter what viewport size is.
int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH;
@@ -1134,6 +1177,7 @@
if (mInZoomOverview) {
b.putFloat("lastScale", mLastScale);
}
+ b.putBoolean("mobile", mMobileSite);
return true;
}
return false;
@@ -1179,12 +1223,20 @@
// correctly
mActualScale = scale;
float lastScale = b.getFloat("lastScale", -1.0f);
+ mMobileSite = b.getBoolean("mobile", false);
if (lastScale > 0) {
mInZoomOverview = true;
+ mViewingMode = OVERVIEW_MODE;
mLastScale = lastScale;
} else {
mInZoomOverview = false;
+ if (mMobileSite && (mScrollX | mScrollY) == 0) {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ } else {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ }
}
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
invalidate();
return true;
}
@@ -3673,8 +3725,10 @@
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
// Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
+ if (mZoomScale == 0) { // unless we're already zooming
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ }
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
@@ -3692,6 +3746,12 @@
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR
+ || mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
+
sendOurVisibleRect();
}
@@ -3906,6 +3966,13 @@
deltaY = newScrollY - mScrollY;
boolean done = false;
if (deltaX == 0 && deltaY == 0) {
+ // The user attempted to pan the page, so dismiss the title
+ // bar
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR
+ || mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -4680,26 +4747,56 @@
}
}
+ /**
+ * Called when the Tabs are used to slide this WebView's tab into view.
+ * @hide
+ */
+ public void slideIntoFocus() {
+ if (mViewingMode == READING_MODE) {
+ if (!mMobileSite || (mScrollX | mScrollY) != 0) {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ } else {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ }
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
+ }
+
private void doDoubleTap() {
- if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false ||
+ mViewingMode == NO_VIEWING_MODE) {
return;
}
+ if (mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ // mInZoomOverview will not change, so change the viewing mode
+ // and return
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ return;
+ }
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR && mMobileSite) {
+ scrollTo(0,0);
+ }
+ // READING_MODE_WITH_TITLE_BAR will go to OVERVIEW_MODE here.
mZoomCenterX = mLastTouchX;
mZoomCenterY = mLastTouchY;
mInZoomOverview = !mInZoomOverview;
- if (mInZoomOverview) {
- if (getSettings().getBuiltInZoomControls()) {
- if (mZoomButtonsController.isVisible()) {
- mZoomButtonsController.setVisible(false);
- }
- } else {
- if (mZoomControlRunnable != null) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
- }
+ mViewingMode = mInZoomOverview ? OVERVIEW_MODE : READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ // remove the zoom control after double tap
+ if (getSettings().getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
}
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+ if (mInZoomOverview) {
zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
} else {
// mLastTouchX and mLastTouchY are the point in the current viewport
@@ -5030,13 +5127,27 @@
} else {
mMaxZoomScale = restoreState.mMaxScale;
}
- if (useWideViewport && restoreState.mViewScale == 0) {
- mInZoomOverview = ENABLE_DOUBLETAP_ZOOM
- && settings.getLoadWithOverviewMode();
- }
setNewZoomScale(mLastScale, false);
setContentScrollTo(restoreState.mScrollX,
restoreState.mScrollY);
+ if (!ENABLE_DOUBLETAP_ZOOM
+ || !settings.getLoadWithOverviewMode()) {
+ mMobileSite = false;
+ mViewingMode = NO_VIEWING_MODE;
+ } else {
+ mMobileSite = restoreState.mMobileSite;
+ if (useWideViewport
+ && restoreState.mViewScale == 0) {
+ mViewingMode = OVERVIEW_MODE;
+ mInZoomOverview = true;
+ } else if (mMobileSite
+ && (mScrollX | mScrollY) == 0) {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ } else {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ }
+ }
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
// As we are on a new page, remove the WebTextView. This
// is necessary for page loads driven by webkit, and in
// particular when the user was on a password field, so
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 0720beb..25cb249 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -258,20 +258,23 @@
* @param url The URL that caused the overflow.
* @param databaseIdentifier The identifier of the database.
* @param currentQuota The current quota for the origin.
+ * @param estimatedSize The estimated size of the database.
*/
protected void exceededDatabaseQuota(String url,
String databaseIdentifier,
- long currentQuota) {
+ long currentQuota,
+ long estimatedSize) {
// Inform the callback proxy of the quota overflow. Send an object
// that encapsulates a call to the nativeSetDatabaseQuota method to
// awaken the sleeping webcore thread when a decision from the
// client to allow or deny quota is available.
mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
- currentQuota, getUsedQuota(), new WebStorage.QuotaUpdater() {
- public void updateQuota(long quota) {
- nativeSetNewStorageLimit(quota);
- }
- });
+ currentQuota, estimatedSize, getUsedQuota(),
+ new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetNewStorageLimit(quota);
+ }
+ });
}
/**
@@ -1505,6 +1508,7 @@
float mTextWrapScale;
int mScrollX;
int mScrollY;
+ boolean mMobileSite;
}
static class DrawData {
@@ -1778,12 +1782,27 @@
mBrowserFrame.didFirstLayout();
- // reset the scroll position as it is a new page now
- mWebkitScrollX = mWebkitScrollY = 0;
+ if (mWebView == null) return;
- // for non-standard load, we only adjust scale if mRestoredScale > 0
- if (mWebView == null || (mRestoredScale == 0 && !standardLoad)) return;
+ setupViewport(standardLoad || mRestoredScale > 0);
+ // reset the scroll position, the restored offset and scales
+ mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY
+ = mRestoredScale = mRestoredScreenWidthScale = 0;
+ }
+
+ // called by JNI
+ private void updateViewport() {
+ // if updateViewport is called before first layout, wait until first
+ // layout to update the viewport. In the rare case, this is called after
+ // first layout, force an update as we have just parsed the viewport
+ // meta tag.
+ if (mBrowserFrame.firstLayoutDone()) {
+ setupViewport(true);
+ }
+ }
+
+ private void setupViewport(boolean updateRestoreState) {
// set the viewport settings from WebKit
setViewportSettingsFromNative();
@@ -1834,6 +1853,9 @@
mViewportWidth = 0;
}
+ // if mViewportWidth is 0, it means device-width, always update.
+ if (mViewportWidth != 0 && !updateRestoreState) return;
+
// now notify webview
int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale);
mRestoreState = new RestoreState();
@@ -1841,6 +1863,7 @@
mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
mRestoreState.mScrollX = mRestoredX;
mRestoreState.mScrollY = mRestoredY;
+ mRestoreState.mMobileSite = (0 == mViewportWidth);
if (mRestoredScale > 0) {
if (mRestoredScreenWidthScale > 0) {
mRestoreState.mTextWrapScale =
@@ -1884,25 +1907,29 @@
data.mScale = -1.0f;
mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
EventHub.VIEW_SIZE_CHANGED, data));
- } else if (mSettings.getUseWideViewPort() && mCurrentViewWidth > 0) {
- WebView.ViewSizeData data = new WebView.ViewSizeData();
- // mViewScale as 0 means it is in zoom overview mode. So we don't
- // know the exact scale. If mRestoredScale is non-zero, use it;
- // otherwise just use mTextWrapScale as the initial scale.
- data.mScale = mRestoreState.mViewScale == 0
- ? (mRestoredScale > 0 ? mRestoredScale
- : mRestoreState.mTextWrapScale)
- : mRestoreState.mViewScale;
- data.mWidth = Math.round(webViewWidth / data.mScale);
- data.mHeight = mCurrentViewHeight * data.mWidth
- / mCurrentViewWidth;
- data.mTextWrapWidth = Math.round(webViewWidth
- / mRestoreState.mTextWrapScale);
- mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
- EventHub.VIEW_SIZE_CHANGED, data));
+ } else if (mSettings.getUseWideViewPort()) {
+ if (mCurrentViewWidth == 0) {
+ // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView
+ // to WebViewCore
+ mWebView.mLastWidthSent = 0;
+ } else {
+ WebView.ViewSizeData data = new WebView.ViewSizeData();
+ // mViewScale as 0 means it is in zoom overview mode. So we don't
+ // know the exact scale. If mRestoredScale is non-zero, use it;
+ // otherwise just use mTextWrapScale as the initial scale.
+ data.mScale = mRestoreState.mViewScale == 0
+ ? (mRestoredScale > 0 ? mRestoredScale
+ : mRestoreState.mTextWrapScale)
+ : mRestoreState.mViewScale;
+ data.mWidth = Math.round(webViewWidth / data.mScale);
+ data.mHeight = mCurrentViewHeight * data.mWidth
+ / mCurrentViewWidth;
+ data.mTextWrapWidth = Math.round(webViewWidth
+ / mRestoreState.mTextWrapScale);
+ mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
+ EventHub.VIEW_SIZE_CHANGED, data));
+ }
}
- // reset restored offset, scale
- mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
}
// called by JNI
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index eea97dc..67721c9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -546,6 +546,7 @@
private void initAbsListView() {
// Setting focusable in touch mode will set the focusable property to true
+ setClickable(true);
setFocusableInTouchMode(true);
setWillNotDraw(false);
setAlwaysDrawnWithCacheEnabled(false);
@@ -1433,6 +1434,10 @@
* this is a long press.
*/
void keyPressed() {
+ if (!isEnabled() || !isClickable()) {
+ return;
+ }
+
Drawable selector = mSelector;
Rect selectorRect = mSelectorRect;
if (selector != null && (isFocused() || touchModeDrawsInPressedState())
@@ -1450,8 +1455,8 @@
Drawable d = selector.getCurrent();
if (d != null && d instanceof TransitionDrawable) {
if (longClickable) {
- ((TransitionDrawable) d).startTransition(ViewConfiguration
- .getLongPressTimeout());
+ ((TransitionDrawable) d).startTransition(
+ ViewConfiguration.getLongPressTimeout());
} else {
((TransitionDrawable) d).resetTransition();
}
@@ -1732,18 +1737,29 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
- if (isPressed() && mSelectedPosition >= 0 && mAdapter != null &&
+ if (!isEnabled()) {
+ return true;
+ }
+ if (isClickable() && isPressed() &&
+ mSelectedPosition >= 0 && mAdapter != null &&
mSelectedPosition < mAdapter.getCount()) {
+
final View view = getChildAt(mSelectedPosition - mFirstPosition);
performItemClick(view, mSelectedPosition, mSelectedRowId);
setPressed(false);
if (view != null) view.setPressed(false);
return true;
}
+ break;
}
return super.onKeyUp(keyCode, event);
}
@@ -1892,6 +1908,12 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ if (!isEnabled()) {
+ // A disabled view that is clickable still consumes the touch
+ // events, it just doesn't respond to them.
+ return isClickable() || isLongClickable();
+ }
+
if (mFastScroller != null) {
boolean intercepted = mFastScroller.onTouchEvent(ev);
if (intercepted) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index f92eb99..2a0e5e5 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -64,10 +64,10 @@
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.SeekBar, defStyle, 0);
Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
- setThumb(thumb);
+ setThumb(thumb); // will guess mThumbOffset if thumb != null...
+ // ...but allow layout to override this
int thumbOffset =
- a.getDimensionPixelOffset(com.android.internal.R.styleable.SeekBar_thumbOffset, 0);
- setThumbOffset(thumbOffset);
+ a.getDimensionPixelOffset(com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
a.recycle();
a = context.obtainStyledAttributes(attrs,
@@ -77,13 +77,21 @@
}
/**
- * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar
+ * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
+ * <p>
+ * If the thumb is a valid drawable (i.e. not null), half its width will be
+ * used as the new thumb offset (@see #setThumbOffset(int)).
*
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
if (thumb != null) {
thumb.setCallback(this);
+
+ // Assuming the thumb drawable is symmetric, set the thumb offset
+ // such that the thumb will hang halfway off either edge of the
+ // progress bar.
+ mThumbOffset = (int)thumb.getIntrinsicWidth() / 2;
}
mThumb = thumb;
invalidate();
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 5360621..6abb2ae4 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -33,6 +33,7 @@
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ExpandableListConnector.PositionMetadata;
/**
@@ -916,7 +917,14 @@
@Override
ContextMenuInfo createContextMenuInfo(View view, int flatListPosition, long id) {
- PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
+ // Adjust for and handle for header views
+ final int adjustedPosition = flatListPosition - getHeaderViewsCount();
+ if (adjustedPosition < 0) {
+ // Return normal info for header view context menus
+ return new AdapterContextMenuInfo(view, flatListPosition, id);
+ }
+
+ PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
ExpandableListPosition pos = pm.position;
pm.recycle();
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 2da777a..67c0def 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -55,7 +55,7 @@
private int mThumbY;
private RectF mOverlayPos;
- private int mOverlaySize = 104;
+ private int mOverlaySize;
private AbsListView mList;
private boolean mScrollCompleted;
@@ -119,10 +119,10 @@
private void useThumbDrawable(Context context, Drawable drawable) {
mThumbDrawable = drawable;
- mThumbW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- 64, context.getResources().getDisplayMetrics());
- mThumbH = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- 52, context.getResources().getDisplayMetrics());
+ mThumbW = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_thumb_width);
+ mThumbH = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_thumb_height);
mChangedBounds = true;
}
@@ -138,7 +138,9 @@
mScrollCompleted = true;
getSectionsFromIndexer();
-
+
+ mOverlaySize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_overlay_size);
mOverlayPos = new RectF();
mScrollFade = new ScrollFade();
mPaint = new Paint();
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 02a137d..993b7cb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1428,7 +1428,8 @@
throw new IllegalStateException("The content of the adapter has changed but "
+ "ListView did not receive a notification. Make sure the content of "
+ "your adapter is not modified from a background thread, but only "
- + "from the UI thread.");
+ + "from the UI thread. [in ListView(" + getId() + ", " + getClass()
+ + ") with Adapter(" + mAdapter.getClass() + ")]");
}
setSelectedPositionInt(mNextSelectedPosition);
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 0c9d980..446a992 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -250,6 +250,29 @@
}
/**
+ * Disable pause or seek buttons if the stream cannot be paused or seeked.
+ * This requires the control interface to be a MediaPlayerControlExt
+ */
+ private void disableUnsupportedButtons() {
+ try {
+ if (mPauseButton != null && !mPlayer.canPause()) {
+ mPauseButton.setEnabled(false);
+ }
+ if (mRewButton != null && !mPlayer.canSeekBackward()) {
+ mRewButton.setEnabled(false);
+ }
+ if (mFfwdButton != null && !mPlayer.canSeekForward()) {
+ mFfwdButton.setEnabled(false);
+ }
+ } catch (IncompatibleClassChangeError ex) {
+ // We were given an old version of the interface, that doesn't have
+ // the canPause/canSeekXYZ methods. This is OK, it just means we
+ // assume the media can be paused and seeked, and so we don't disable
+ // the buttons.
+ }
+ }
+
+ /**
* Show the controller on screen. It will go away
* automatically after 'timeout' milliseconds of inactivity.
* @param timeout The timeout in milliseconds. Use 0 to show
@@ -259,6 +282,10 @@
if (!mShowing && mAnchor != null) {
setProgress();
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ }
+ disableUnsupportedButtons();
int [] anchorpos = new int[2];
mAnchor.getLocationOnScreen(anchorpos);
@@ -392,6 +419,9 @@
keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ }
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
@@ -421,17 +451,13 @@
};
private void updatePausePlay() {
- if (mRoot == null)
- return;
-
- ImageButton button = (ImageButton) mRoot.findViewById(com.android.internal.R.id.pause);
- if (button == null)
+ if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying()) {
- button.setImageResource(com.android.internal.R.drawable.ic_media_pause);
+ mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_pause);
} else {
- button.setImageResource(com.android.internal.R.drawable.ic_media_play);
+ mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_play);
}
}
@@ -516,7 +542,7 @@
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
-
+ disableUnsupportedButtons();
super.setEnabled(enabled);
}
@@ -579,5 +605,8 @@
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
- };
+ boolean canPause();
+ boolean canSeekBackward();
+ boolean canSeekForward();
+ }
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 90fbb77..548dee9 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -817,6 +817,7 @@
* @param p the layout parameters of the popup's content view
*/
private void invokePopup(WindowManager.LayoutParams p) {
+ p.packageName = mContext.getPackageName();
mWindowManager.addView(mPopupView, p);
}
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 103d44d..ee3b91e 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -68,7 +68,7 @@
initTabHost();
}
- private final void initTabHost() {
+ private void initTabHost() {
setFocusableInTouchMode(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
@@ -101,8 +101,8 @@
throw new RuntimeException(
"Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs'");
}
-
- // KeyListener to attach to all tabs. Detects non-navigation keys
+
+ // KeyListener to attach to all tabs. Detects non-navigation keys
// and relays them to the tab content.
mTabKeyListener = new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -114,14 +114,14 @@
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_ENTER:
return false;
-
+
}
mTabContent.requestFocus(View.FOCUS_FORWARD);
return mTabContent.dispatchKeyEvent(event);
}
-
+
};
-
+
mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() {
public void onTabSelectionChanged(int tabIndex, boolean clicked) {
setCurrentTab(tabIndex);
@@ -134,7 +134,8 @@
mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent);
if (mTabContent == null) {
throw new RuntimeException(
- "Your TabHost must have a FrameLayout whose id attribute is 'android.R.id.tabcontent'");
+ "Your TabHost must have a FrameLayout whose id attribute is "
+ + "'android.R.id.tabcontent'");
}
}
@@ -176,7 +177,7 @@
if (!isInTouchMode) {
// leaving touch mode.. if nothing has focus, let's give it to
// the indicator of the current tab
- if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) {
+ if (mCurrentView != null && (!mCurrentView.hasFocus() || mCurrentView.isFocused())) {
mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
}
}
@@ -283,7 +284,7 @@
playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
return true;
}
- return handled;
+ return handled;
}
@@ -312,7 +313,7 @@
// Call the tab widget's focusCurrentTab(), instead of just
// selecting the tab.
mTabWidget.focusCurrentTab(mCurrentTab);
-
+
// tab content
mCurrentView = spec.mContentStrategy.getContentView();
@@ -367,7 +368,7 @@
public interface TabContentFactory {
/**
* Callback to make the tab contents
- *
+ *
* @param tag
* Which tab was selected.
* @return The view to display the contents of the selected tab.
@@ -501,6 +502,8 @@
View tabIndicator = inflater.inflate(R.layout.tab_indicator,
mTabWidget, // tab widget is the parent
false); // no inflate params
+ // TODO: Move this to xml when bug 2068024 is resolved.
+ tabIndicator.getBackground().setDither(true);
final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
tv.setText(mLabel);
@@ -528,6 +531,8 @@
View tabIndicator = inflater.inflate(R.layout.tab_indicator,
mTabWidget, // tab widget is the parent
false); // no inflate params
+ // TODO: Move this to xml when bug 2068024 is resolved.
+ tabIndicator.getBackground().setDither(true);
final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
tv.setText(mLabel);
@@ -637,7 +642,7 @@
}
}
mLaunchedView = wd;
-
+
// XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
// focus if none of their children have it. They need focus to be able to
// display menu items.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 47f5c6c..889f37f 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -30,7 +30,7 @@
/**
- *
+ *
* Displays a list of tab labels representing each page in the parent's tab
* collection. The container object for this widget is
* {@link android.widget.TabHost TabHost}. When the user selects a tab, this
@@ -64,21 +64,36 @@
super(context, attrs);
initTabWidget();
- TypedArray a =
+ TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget,
defStyle, 0);
a.recycle();
}
-
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mStripMoved = true;
super.onSizeChanged(w, h, oldw, oldh);
}
+ @Override
+ protected int getChildDrawingOrder(int childCount, int i) {
+ // Always draw the selected tab last, so that drop shadows are drawn
+ // in the correct z-order.
+ if (i == childCount - 1) {
+ return mSelectedTab;
+ } else if (i >= mSelectedTab) {
+ return i + 1;
+ } else {
+ return i;
+ }
+ }
+
private void initTabWidget() {
setOrientation(LinearLayout.HORIZONTAL);
+ mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
+
mBottomLeftStrip = mContext.getResources().getDrawable(
com.android.internal.R.drawable.tab_bottom_left);
mBottomRightStrip = mContext.getResources().getDrawable(
@@ -156,7 +171,7 @@
}
super.childDrawableStateChanged(child);
}
-
+
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
@@ -169,17 +184,17 @@
}
View selectedChild = getChildTabViewAt(mSelectedTab);
-
+
mBottomLeftStrip.setState(selectedChild.getDrawableState());
mBottomRightStrip.setState(selectedChild.getDrawableState());
-
+
if (mStripMoved) {
Rect selBounds = new Rect(); // Bounds of the selected tab indicator
selBounds.left = selectedChild.getLeft();
selBounds.right = selectedChild.getRight();
final int myHeight = getHeight();
mBottomLeftStrip.setBounds(
- Math.min(0, selBounds.left
+ Math.min(0, selBounds.left
- mBottomLeftStrip.getIntrinsicWidth()),
myHeight - mBottomLeftStrip.getIntrinsicHeight(),
selBounds.left,
@@ -187,12 +202,12 @@
mBottomRightStrip.setBounds(
selBounds.right,
myHeight - mBottomRightStrip.getIntrinsicHeight(),
- Math.max(getWidth(),
+ Math.max(getWidth(),
selBounds.right + mBottomRightStrip.getIntrinsicWidth()),
myHeight);
mStripMoved = false;
}
-
+
mBottomLeftStrip.draw(canvas);
mBottomRightStrip.draw(canvas);
}
@@ -202,26 +217,26 @@
* This method is used to bring a tab to the front of the Widget,
* and is used to post to the rest of the UI that a different tab
* has been brought to the foreground.
- *
- * Note, this is separate from the traditional "focus" that is
- * employed from the view logic.
- *
- * For instance, if we have a list in a tabbed view, a user may be
- * navigating up and down the list, moving the UI focus (orange
- * highlighting) through the list items. The cursor movement does
- * not effect the "selected" tab though, because what is being
- * scrolled through is all on the same tab. The selected tab only
- * changes when we navigate between tabs (moving from the list view
+ *
+ * Note, this is separate from the traditional "focus" that is
+ * employed from the view logic.
+ *
+ * For instance, if we have a list in a tabbed view, a user may be
+ * navigating up and down the list, moving the UI focus (orange
+ * highlighting) through the list items. The cursor movement does
+ * not effect the "selected" tab though, because what is being
+ * scrolled through is all on the same tab. The selected tab only
+ * changes when we navigate between tabs (moving from the list view
* to the next tabbed view, in this example).
- *
+ *
* To move both the focus AND the selected tab at once, please use
- * {@link #setCurrentTab}. Normally, the view logic takes care of
- * adjusting the focus, so unless you're circumventing the UI,
+ * {@link #setCurrentTab}. Normally, the view logic takes care of
+ * adjusting the focus, so unless you're circumventing the UI,
* you'll probably just focus your interest here.
- *
+ *
* @param index The tab that you want to indicate as the selected
* tab (tab brought to the front of the widget)
- *
+ *
* @see #focusCurrentTab
*/
public void setCurrentTab(int index) {
@@ -234,19 +249,19 @@
getChildTabViewAt(mSelectedTab).setSelected(true);
mStripMoved = true;
}
-
+
/**
* Sets the current tab and focuses the UI on it.
- * This method makes sure that the focused tab matches the selected
- * tab, normally at {@link #setCurrentTab}. Normally this would not
- * be an issue if we go through the UI, since the UI is responsible
- * for calling TabWidget.onFocusChanged(), but in the case where we
- * are selecting the tab programmatically, we'll need to make sure
+ * This method makes sure that the focused tab matches the selected
+ * tab, normally at {@link #setCurrentTab}. Normally this would not
+ * be an issue if we go through the UI, since the UI is responsible
+ * for calling TabWidget.onFocusChanged(), but in the case where we
+ * are selecting the tab programmatically, we'll need to make sure
* focus keeps up.
- *
- * @param index The tab that you want focused (highlighted in orange)
+ *
+ * @param index The tab that you want focused (highlighted in orange)
* and selected (tab brought to the front of the widget)
- *
+ *
* @see #setCurrentTab
*/
public void focusCurrentTab(int index) {
@@ -254,18 +269,18 @@
// set the tab
setCurrentTab(index);
-
+
// change the focus if applicable.
if (oldTab != index) {
getChildTabViewAt(index).requestFocus();
}
}
-
+
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
int count = getTabCount();
-
+
for (int i = 0; i < count; i++) {
View child = getChildTabViewAt(i);
child.setEnabled(enabled);
@@ -318,7 +333,7 @@
getChildTabViewAt(mSelectedTab).requestFocus();
return;
}
-
+
if (hasFocus) {
int i = 0;
int numTabs = getTabCount();
@@ -354,7 +369,7 @@
/**
* Informs the TabHost which tab was selected. It also indicates
* if the tab was clicked/pressed or just focused into.
- *
+ *
* @param tabIndex index of the tab that was selected
* @param clicked whether the selection changed due to a touch/click
* or due to focus entering the tab through navigation. Pass true
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e0a268e..a611d5a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7222,6 +7222,7 @@
if (word != null) {
Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
i.putExtra("word", word);
+ i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(i);
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 5bc2507..549f984 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -23,6 +23,7 @@
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaPlayer;
+import android.media.Metadata;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
@@ -34,7 +35,7 @@
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.widget.MediaController.MediaPlayerControl;
+import android.widget.MediaController.*;
import java.io.IOException;
@@ -81,6 +82,9 @@
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
private int mSeekWhenPrepared; // recording the seek position while preparing
+ private boolean mCanPause;
+ private boolean mCanSeekBack;
+ private boolean mCanSeekForward;
public VideoView(Context context) {
super(context);
@@ -259,6 +263,22 @@
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
+
+ // Get the capabilities of the player for this stream
+ Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
+ MediaPlayer.BYPASS_METADATA_FILTER);
+
+ if (data != null) {
+ mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
+ || data.getBoolean(Metadata.PAUSE_AVAILABLE);
+ mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
+ || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
+ mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
+ || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
+ } else {
+ mCanPause = mCanSeekForward = mCanSeekForward = true;
+ }
+
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
@@ -267,6 +287,7 @@
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
+
int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
if (seekToPosition != 0) {
seekTo(seekToPosition);
@@ -580,4 +601,16 @@
mCurrentState != STATE_IDLE &&
mCurrentState != STATE_PREPARING);
}
+
+ public boolean canPause() {
+ return mCanPause;
+ }
+
+ public boolean canSeekBackward() {
+ return mCanSeekBack;
+ }
+
+ public boolean canSeekForward() {
+ return mCanSeekForward;
+ }
}
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 77d6e20..4c9451e 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -21,8 +21,8 @@
import android.app.IActivityManager;
import android.app.ProgressDialog;
import android.app.AlertDialog;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -179,13 +179,13 @@
final ITelephony phone =
ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- final IBluetoothDevice bluetooth =
- IBluetoothDevice.Stub.asInterface(ServiceManager.checkService(
+ final IBluetooth bluetooth =
+ IBluetooth.Stub.asInterface(ServiceManager.checkService(
Context.BLUETOOTH_SERVICE));
try {
bluetoothOff = bluetooth == null ||
- bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
if (!bluetoothOff) {
Log.w(TAG, "Disabling Bluetooth...");
bluetooth.disable(false); // disable but don't persist new state
@@ -213,7 +213,7 @@
if (!bluetoothOff) {
try {
bluetoothOff =
- bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
} catch (RemoteException ex) {
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
bluetoothOff = true;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a449e5f..2da72df 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -978,10 +978,13 @@
} else if (mBtHeadset != null) {
return getCurrentBluetoothPingCount() - mBluetoothPingStart;
}
- return -1;
+ return 0;
}
public void setBtHeadset(BluetoothHeadset headset) {
+ if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
+ mBluetoothPingStart = getCurrentBluetoothPingCount();
+ }
mBtHeadset = headset;
}
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index e4c473d..5825024 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -97,6 +97,14 @@
return mH.hasMessages(what);
}
+ public void removeMessages(int what) {
+ mH.removeMessages(what);
+ }
+
+ public void removeMessages(int what, Object obj) {
+ mH.removeMessages(what, obj);
+ }
+
public void sendMessage(Message msg) {
mH.sendMessage(msg);
}
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index bfe8696..c4eb31f 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -21,7 +21,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.service.wallpaper.WallpaperService;
-import android.util.Log;
+import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.content.Context;
import android.content.IntentFilter;
@@ -67,14 +67,15 @@
private final Object mLock = new Object();
private final Rect mBounds = new Rect();
Drawable mBackground;
- int mXOffset;
- int mYOffset;
+ float mXOffset;
+ float mYOffset;
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
+ //setTouchEventsEnabled(true);
}
@Override
@@ -83,10 +84,15 @@
}
@Override
+ public void onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ }
+
+ @Override
public void onOffsetsChanged(float xOffset, float yOffset,
int xPixels, int yPixels) {
- mXOffset = xPixels;
- mYOffset = yPixels;
+ mXOffset = xOffset;
+ mYOffset = yOffset;
drawFrame();
}
@@ -110,11 +116,20 @@
SurfaceHolder sh = getSurfaceHolder();
Canvas c = sh.lockCanvas();
if (c != null) {
- //final Rect frame = sh.getSurfaceFrame();
+ final Rect frame = sh.getSurfaceFrame();
synchronized (mLock) {
final Drawable background = mBackground;
- //background.setBounds(frame);
- c.translate(mXOffset, mYOffset);
+ final int dw = frame.width();
+ final int dh = frame.height();
+ final int bw = mBackground.getIntrinsicWidth();
+ final int bh = mBackground.getIntrinsicHeight();
+ final int availw = bw-dw;
+ final int availh = bh-dh;
+ int xPixels = availw > 0
+ ? -(int)(availw*mXOffset+.5f) : -(availw/2);
+ int yPixels = availh > 0
+ ? -(int)(availh*mYOffset+.5f) : -(availh/2);
+ c.translate(xPixels, yPixels);
c.drawColor(0xff000000);
background.draw(c);
}
@@ -128,9 +143,6 @@
mBounds.left = mBounds.top = 0;
mBounds.right = mBackground.getIntrinsicWidth();
mBounds.bottom = mBackground.getIntrinsicHeight();
- int offx = (getDesiredMinimumWidth() - mBounds.right) / 2;
- int offy = (getDesiredMinimumHeight() - mBounds.bottom) / 2;
- mBounds.offset(offx, offy);
mBackground.setBounds(mBounds);
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index a030db7..f4f6297 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -32,23 +32,47 @@
}
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public boolean onDispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ event.recycle();
+ return false;
+ }
+
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
try {
if (event == null) {
event = mSession.getPendingPointerMove(this);
- } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) {
- mSession.finishKey(this);
+ onDispatchPointer(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchPointer(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchPointer(event, eventTime, false);
}
} catch (RemoteException ex) {
}
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public boolean onDispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ event.recycle();
+ return false;
+ }
+
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
try {
if (event == null) {
event = mSession.getPendingTrackballMove(this);
- } else if (event.getAction() != MotionEvent.ACTION_OUTSIDE) {
- mSession.finishKey(this);
+ onDispatchTrackball(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchTrackball(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchTrackball(event, eventTime, false);
}
} catch (RemoteException ex) {
}
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 30349b3..8bae3e4 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -39,6 +39,7 @@
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.Presence;
import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.SocialContract.Activities;
import android.util.AttributeSet;
@@ -80,6 +81,8 @@
protected Uri mContactUri;
protected Uri mStatusUri;
+ protected String[] mExcludeMimes = null;
+
protected ContentResolver mContentResolver;
/**
@@ -116,7 +119,7 @@
//Projection used for looking up contact id from phone number
protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
- RawContacts.CONTACT_ID,
+ PhoneLookup._ID,
};
protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
@@ -292,6 +295,15 @@
}
/**
+ * Set a list of specific MIME-types to exclude and not display. For
+ * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
+ * profile icon.
+ */
+ public void setExcludeMimes(String[] excludeMimes) {
+ mExcludeMimes = excludeMimes;
+ }
+
+ /**
* Convenience method for binding all available data from an existing
* contact.
*
@@ -336,9 +348,8 @@
public void bindFromEmail(String emailAddress) {
Cursor c = null;
try {
- c = mContentResolver.query(Uri.withAppendedPath(
- RawContacts.CONTENT_FILTER_EMAIL_URI, Uri.encode(emailAddress)),
- EMAIL_LOOKUP_PROJECTION, null, null, null);
+ c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri
+ .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null);
if (c != null && c.moveToFirst()) {
long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
bindFromContactId(contactId);
@@ -428,6 +439,10 @@
final Rect target = getTargetRect(view);
intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
+ if (mExcludeMimes != null) {
+ // Exclude specific MIME-types when requested
+ intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes);
+ }
mContext.startActivity(intent);
break;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f0b311c..58056bd 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -316,20 +316,14 @@
/**
* Set the state of whether the device is permanently locked, meaning the user
- * must authenticate via other means. If false, that means the user has gone
- * out of permanent lock, so the existing (forgotten) lock pattern needs to
- * be cleared.
+ * must authenticate via other means.
+ *
* @param locked Whether the user is permanently locked out until they verify their
* credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
* attempts.
*/
public void setPermanentlyLocked(boolean locked) {
setBoolean(LOCKOUT_PERMANENT_KEY, locked);
-
- if (!locked) {
- setLockPatternEnabled(false);
- saveLockPattern(null);
- }
}
/**
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index 74af7650..df91ea6 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -1021,6 +1021,7 @@
+ "content://mms/drafts, content://mms/outbox, "
+ "content://mms/temp.");
}
+ PDU_CACHE_INSTANCE.purge(uri);
PduHeaders header = pdu.getPduHeaders();
PduBody body = null;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 36d2684..015268b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -114,7 +114,7 @@
android_bluetooth_BluetoothAudioGateway.cpp \
android_bluetooth_BluetoothSocket.cpp \
android_bluetooth_ScoSocket.cpp \
- android_server_BluetoothDeviceService.cpp \
+ android_server_BluetoothService.cpp \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
android_message_digest_sha1.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 63dc9e8..f61e247 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -146,7 +146,7 @@
extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env);
extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
-extern int register_android_server_BluetoothDeviceService(JNIEnv* env);
+extern int register_android_server_BluetoothService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -525,6 +525,7 @@
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
+ char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
bool checkJni = false;
bool checkDexSum = false;
@@ -597,16 +598,10 @@
mOptions.add(opt);
//options[curOpt++].optionString = "-verbose:class";
-#ifdef CUSTOM_RUNTIME_HEAP_MAX
-#define __make_max_heap_opt(val) #val
-#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
- opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
-#undef __make_max_heap_opt
-#undef _make_max_heap_opt
-#else
- /* limit memory use to 16MB */
- opt.optionString = "-Xmx16m";
-#endif
+ strcpy(heapsizeOptsBuf, "-Xmx");
+ property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
+ //LOGI("Heap size: %s", heapsizeOptsBuf);
+ opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
/*
@@ -1241,7 +1236,7 @@
REG_JNI(register_android_bluetooth_BluetoothAudioGateway),
REG_JNI(register_android_bluetooth_BluetoothSocket),
REG_JNI(register_android_bluetooth_ScoSocket),
- REG_JNI(register_android_server_BluetoothDeviceService),
+ REG_JNI(register_android_server_BluetoothService),
REG_JNI(register_android_server_BluetoothEventLoop),
REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_message_digest_sha1),
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 21dde63..238ece1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -141,6 +141,25 @@
return SkTypeface::CreateFromFile(str.c_str());
}
+#define MIN_GAMMA (0.1f)
+#define MAX_GAMMA (10.0f)
+static float pinGamma(float gamma) {
+ if (gamma < MIN_GAMMA) {
+ gamma = MIN_GAMMA;
+ } else if (gamma > MAX_GAMMA) {
+ gamma = MAX_GAMMA;
+ }
+ return gamma;
+}
+
+extern void skia_set_text_gamma(float, float);
+
+static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma,
+ jfloat whiteGamma) {
+ // Comment this out for release builds. This is only used during development
+ skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma));
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@@ -151,7 +170,8 @@
{ "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
(void*)Typeface_createFromAsset },
{ "nativeCreateFromFile", "(Ljava/lang/String;)I",
- (void*)Typeface_createFromFile }
+ (void*)Typeface_createFromFile },
+ { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
};
int register_android_graphics_Typeface(JNIEnv* env);
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 14da1fd..a185d8d 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -211,10 +211,6 @@
method_onSinkPropertyChanged,
env->NewStringUTF(c_path),
str_array);
- for (int i = 0; i < env->GetArrayLength(str_array); i++) {
- env->DeleteLocalRef(env->GetObjectArrayElement(str_array, i));
- }
- env->DeleteLocalRef(str_array);
result = DBUS_HANDLER_RESULT_HANDLED;
return result;
} else {
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 527bf07..1bfabd7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -57,6 +57,8 @@
typedef event_loop_native_data_t native_data_t;
+#define EVENT_LOOP_REFS 10
+
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object,
field_mNativeData));
@@ -679,6 +681,7 @@
native_data_t *nat;
JNIEnv *env;
DBusError err;
+ DBusHandlerResult ret;
dbus_error_init(&err);
@@ -694,6 +697,7 @@
dbus_message_get_interface(msg), dbus_message_get_member(msg),
dbus_message_get_path(msg));
+ env->PushLocalFrame(EVENT_LOOP_REFS);
if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"DeviceFound")) {
@@ -711,10 +715,9 @@
method_onDeviceFound,
env->NewStringUTF(c_address),
str_array);
- env->DeleteLocalRef(str_array);
} else
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"DeviceDisappeared")) {
@@ -726,7 +729,7 @@
env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
env->NewStringUTF(c_address));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"DeviceCreated")) {
@@ -739,7 +742,7 @@
method_onDeviceCreated,
env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"DeviceRemoved")) {
@@ -752,8 +755,7 @@
method_onDeviceRemoved,
env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
-
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"PropertyChanged")) {
@@ -775,9 +777,8 @@
env->CallVoidMethod(nat->me,
method_onPropertyChanged,
str_array);
- env->DeleteLocalRef(str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Device",
"PropertyChanged")) {
@@ -788,12 +789,17 @@
method_onDevicePropertyChanged,
env->NewStringUTF(remote_device_path),
str_array);
- env->DeleteLocalRef(str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
-
+ goto success;
}
- return a2dp_event_filter(msg, env);
+
+ ret = a2dp_event_filter(msg, env);
+ env->PopLocalFrame(NULL);
+ return ret;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
// Called by dbus during WaitForAndDispatchEventNative()
@@ -811,6 +817,8 @@
if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
nat->vm->GetEnv((void**)&env, nat->envVer);
+ env->PushLocalFrame(EVENT_LOOP_REFS);
+
if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "Cancel")) {
@@ -820,11 +828,11 @@
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "Authorize")) {
@@ -835,7 +843,7 @@
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
LOGV("... object_path = %s", object_path);
@@ -850,7 +858,7 @@
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
@@ -859,12 +867,12 @@
"org.bluez.Error.Rejected", "Authorization rejected");
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
}
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "RequestPinCode")) {
char *object_path;
@@ -872,14 +880,14 @@
DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_message_ref(msg); // increment refcount because we pass to java
env->CallVoidMethod(nat->me, method_onRequestPinCode,
env->NewStringUTF(object_path),
int(msg));
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "RequestPasskey")) {
char *object_path;
@@ -887,13 +895,14 @@
DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_message_ref(msg); // increment refcount because we pass to java
env->CallVoidMethod(nat->me, method_onRequestPasskey,
env->NewStringUTF(object_path),
int(msg));
+ goto success;
} else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "RequestConfirmation")) {
char *object_path;
@@ -903,7 +912,7 @@
DBUS_TYPE_UINT32, &passkey,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_message_ref(msg); // increment refcount because we pass to java
@@ -911,23 +920,30 @@
env->NewStringUTF(object_path),
passkey,
int(msg));
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "Release")) {
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else {
LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
}
+failure:
+ env->PopLocalFrame(NULL);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
}
#endif
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothService.cpp
similarity index 98%
rename from core/jni/android_server_BluetoothDeviceService.cpp
rename to core/jni/android_server_BluetoothService.cpp
index 444e628..d1901b4 100644
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -16,7 +16,7 @@
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
-#define LOG_TAG "BluetoothDeviceService.cpp"
+#define LOG_TAG "BluetoothService.cpp"
#include "android_bluetooth_common.h"
#include "android_runtime/AndroidRuntime.h"
@@ -46,10 +46,11 @@
namespace android {
#define BLUETOOTH_CLASS_ERROR 0xFF000000
+#define PROPERTIES_NREFS 10
#ifdef HAVE_BLUETOOTH
// We initialize these variables when we load class
-// android.server.BluetoothDeviceService
+// android.server.BluetoothService
static jfieldID field_mNativeData;
static jfieldID field_mEventLoop;
@@ -576,11 +577,16 @@
LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return NULL;
}
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
DBusMessageIter iter;
jobjectArray str_array = NULL;
if (dbus_message_iter_init(reply, &iter))
str_array = parse_remote_device_properties(env, &iter);
dbus_message_unref(reply);
+
+ env->PopLocalFrame(NULL);
+
return str_array;
}
#endif
@@ -607,11 +613,15 @@
LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return NULL;
}
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
DBusMessageIter iter;
jobjectArray str_array = NULL;
if (dbus_message_iter_init(reply, &iter))
str_array = parse_adapter_properties(env, &iter);
dbus_message_unref(reply);
+
+ env->PopLocalFrame(NULL);
return str_array;
}
#endif
@@ -732,9 +742,9 @@
(void *)cancelPairingUserInputNative},
};
-int register_android_server_BluetoothDeviceService(JNIEnv *env) {
+int register_android_server_BluetoothService(JNIEnv *env) {
return AndroidRuntime::registerNativeMethods(env,
- "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
+ "android/server/BluetoothService", sMethods, NELEM(sMethods));
}
} /* namespace android */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 608c1ff..35042f1d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -49,7 +49,6 @@
<protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" />
<protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_LOW" />
<protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" />
- <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
<protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
<protected-broadcast android:name="android.intent.action.REBOOT" />
diff --git a/core/res/res/anim/wallpaper_activity_close_enter.xml b/core/res/res/anim/wallpaper_activity_close_enter.xml
new file mode 100644
index 0000000..fc6e332
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_enter.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale="2.0" android:toXScale="1.0"
+ android:fromYScale="2.0" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="-150%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_close_exit.xml b/core/res/res/anim/wallpaper_activity_close_exit.xml
new file mode 100644
index 0000000..edd00fd
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale=".5"
+ android:fromYScale="1.0" android:toYScale=".5"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="0%" android:toXDelta="100%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_enter.xml b/core/res/res/anim/wallpaper_activity_open_enter.xml
new file mode 100644
index 0000000..5b44d97
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="100%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_exit.xml b/core/res/res/anim/wallpaper_activity_open_exit.xml
new file mode 100644
index 0000000..fa39bee
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_exit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale="1.0" android:toXScale="2.0"
+ android:fromYScale="1.0" android:toYScale="2.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="0" android:toXDelta="-150%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/color/tab_indicator_text.xml b/core/res/res/color/tab_indicator_text.xml
index ce321db..5f5c2a4 100644
--- a/core/res/res/color/tab_indicator_text.xml
+++ b/core/res/res/color/tab_indicator_text.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true" android:color="#323232"/>
- <item android:color="#FFF"/> <!-- not selected -->
+ <item android:state_selected="true" android:color="#ffffff"/>
+ <item android:color="#808080"/> <!-- not selected -->
</selector>
diff --git a/core/res/res/drawable/contact_picture_bg.9.png b/core/res/res/drawable/contact_picture_bg.9.png
deleted file mode 100644
index ae9c709..0000000
--- a/core/res/res/drawable/contact_picture_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/dark_header.9.png b/core/res/res/drawable/dark_header.9.png
index 8fa5f09..7242b61 100644
--- a/core/res/res/drawable/dark_header.9.png
+++ b/core/res/res/drawable/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/dark_header_dither.xml b/core/res/res/drawable/dark_header_dither.xml
new file mode 100644
index 0000000..0741fa4
--- /dev/null
+++ b/core/res/res/drawable/dark_header_dither.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/dark_header"
+ android:dither="true"
+/>
diff --git a/core/res/res/drawable/divider_horizontal_bright.9.png b/core/res/res/drawable/divider_horizontal_bright.9.png
index 144fc22..395227a 100644
--- a/core/res/res/drawable/divider_horizontal_bright.9.png
+++ b/core/res/res/drawable/divider_horizontal_bright.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
index 30c9b2b..5c537ee 100644
--- a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
+++ b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dark.9.png b/core/res/res/drawable/divider_horizontal_dark.9.png
index 08838ca..548d0bd 100644
--- a/core/res/res/drawable/divider_horizontal_dark.9.png
+++ b/core/res/res/drawable/divider_horizontal_dark.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
index ce21acd..8f35315 100644
--- a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
+++ b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright.9.png b/core/res/res/drawable/divider_vertical_bright.9.png
index da6e4ec..395227a 100644
--- a/core/res/res/drawable/divider_vertical_bright.9.png
+++ b/core/res/res/drawable/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable/divider_vertical_bright_opaque.9.png
new file mode 100644
index 0000000..5c537ee
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark.9.png b/core/res/res/drawable/divider_vertical_dark.9.png
new file mode 100644
index 0000000..548d0bd
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable/divider_vertical_dark_opaque.9.png
new file mode 100644
index 0000000..8f35315
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark.xml b/core/res/res/drawable/fasttrack_badge_dark.xml
new file mode 100644
index 0000000..c60d403
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_dark_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_dark_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
new file mode 100644
index 0000000..52bb08c
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
new file mode 100644
index 0000000..84a6783
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light.xml b/core/res/res/drawable/fasttrack_badge_light.xml
new file mode 100644
index 0000000..fd81258
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_light_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_light_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/fasttrack_badge_light_normal.9.png b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
new file mode 100644
index 0000000..595b179
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
new file mode 100644
index 0000000..8e3f557
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle.xml b/core/res/res/drawable/fasttrack_badge_middle.xml
new file mode 100644
index 0000000..6df230a
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_middle_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_middle_pressed" />
+
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/fasttrack_badge_middle_normal.9.png b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png
new file mode 100644
index 0000000..07df063
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png
new file mode 100644
index 0000000..ded95f6
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/light_header.9.png b/core/res/res/drawable/light_header.9.png
index ad5dce1..fcd9e2d 100644
--- a/core/res/res/drawable/light_header.9.png
+++ b/core/res/res/drawable/light_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/light_header_dither.xml b/core/res/res/drawable/light_header_dither.xml
new file mode 100644
index 0000000..c54b6c2
--- /dev/null
+++ b/core/res/res/drawable/light_header_dither.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/light_header"
+ android:dither="true"
+/>
diff --git a/core/res/res/drawable/stat_sys_data_connected_1x.png b/core/res/res/drawable/stat_sys_data_connected_1x.png
new file mode 100644
index 0000000..130724f
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png b/core/res/res/drawable/stat_sys_data_connected_1xrtt.png
deleted file mode 100644
index c2fbbdf..0000000
--- a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_evdo.png b/core/res/res/drawable/stat_sys_data_connected_evdo.png
deleted file mode 100644
index db9f282..0000000
--- a/core/res/res/drawable/stat_sys_data_connected_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_h.png b/core/res/res/drawable/stat_sys_data_connected_h.png
new file mode 100644
index 0000000..7d5413a
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png b/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png
deleted file mode 100755
index 11c2eae..0000000
--- a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_dormant_evdo.png b/core/res/res/drawable/stat_sys_data_dormant_evdo.png
deleted file mode 100755
index 811fcb5..0000000
--- a/core/res/res/drawable/stat_sys_data_dormant_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_1x.png b/core/res/res/drawable/stat_sys_data_in_1x.png
new file mode 100644
index 0000000..3155e632
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_1xrtt.png b/core/res/res/drawable/stat_sys_data_in_1xrtt.png
deleted file mode 100644
index a421a8a..0000000
--- a/core/res/res/drawable/stat_sys_data_in_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_evdo.png b/core/res/res/drawable/stat_sys_data_in_evdo.png
deleted file mode 100644
index 54f55ba..0000000
--- a/core/res/res/drawable/stat_sys_data_in_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_h.png b/core/res/res/drawable/stat_sys_data_in_h.png
new file mode 100644
index 0000000..695b80c
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_1x.png b/core/res/res/drawable/stat_sys_data_inandout_1x.png
new file mode 100644
index 0000000..1017e3b
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png b/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png
deleted file mode 100644
index 1a94cdf..0000000
--- a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_evdo.png b/core/res/res/drawable/stat_sys_data_inandout_evdo.png
deleted file mode 100644
index 7aa6f00..0000000
--- a/core/res/res/drawable/stat_sys_data_inandout_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_h.png b/core/res/res/drawable/stat_sys_data_inandout_h.png
new file mode 100644
index 0000000..467acd1
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_1x.png b/core/res/res/drawable/stat_sys_data_out_1x.png
new file mode 100644
index 0000000..5418791
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_1xrtt.png b/core/res/res/drawable/stat_sys_data_out_1xrtt.png
deleted file mode 100644
index 74fd351..0000000
--- a/core/res/res/drawable/stat_sys_data_out_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_evdo.png b/core/res/res/drawable/stat_sys_data_out_evdo.png
deleted file mode 100644
index 21e19a7..0000000
--- a/core/res/res/drawable/stat_sys_data_out_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_h.png b/core/res/res/drawable/stat_sys_data_out_h.png
new file mode 100644
index 0000000..da50305
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_0_cdma.png b/core/res/res/drawable/stat_sys_signal_0_cdma.png
deleted file mode 100644
index 0ef7d53..0000000
--- a/core/res/res/drawable/stat_sys_signal_0_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_1_cdma.png b/core/res/res/drawable/stat_sys_signal_1_cdma.png
deleted file mode 100644
index f4839d4..0000000
--- a/core/res/res/drawable/stat_sys_signal_1_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_2_cdma.png b/core/res/res/drawable/stat_sys_signal_2_cdma.png
deleted file mode 100644
index e25a99c..0000000
--- a/core/res/res/drawable/stat_sys_signal_2_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_3_cdma.png b/core/res/res/drawable/stat_sys_signal_3_cdma.png
deleted file mode 100644
index d828d99..0000000
--- a/core/res/res/drawable/stat_sys_signal_3_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_4_cdma.png b/core/res/res/drawable/stat_sys_signal_4_cdma.png
deleted file mode 100644
index 53a31ea..0000000
--- a/core/res/res/drawable/stat_sys_signal_4_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_0.png b/core/res/res/drawable/stat_sys_signal_cdma_0.png
deleted file mode 100755
index 0ef7d53..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_1.png b/core/res/res/drawable/stat_sys_signal_cdma_1.png
deleted file mode 100755
index f4839d4..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_1.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_2.png b/core/res/res/drawable/stat_sys_signal_cdma_2.png
deleted file mode 100755
index e25a99c..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_2.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_3.png b/core/res/res/drawable/stat_sys_signal_cdma_3.png
deleted file mode 100755
index d828d99..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_3.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_4.png b/core/res/res/drawable/stat_sys_signal_cdma_4.png
deleted file mode 100755
index 53a31ea..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_4.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_0.png b/core/res/res/drawable/stat_sys_signal_evdo_0.png
deleted file mode 100755
index 1b8aec7..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_1.png b/core/res/res/drawable/stat_sys_signal_evdo_1.png
deleted file mode 100755
index 7ce01fd..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_1.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_2.png b/core/res/res/drawable/stat_sys_signal_evdo_2.png
deleted file mode 100755
index 890cd59..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_2.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_3.png b/core/res/res/drawable/stat_sys_signal_evdo_3.png
deleted file mode 100755
index 712c640..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_3.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_4.png b/core/res/res/drawable/stat_sys_signal_evdo_4.png
deleted file mode 100755
index f0537dd..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_4.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_focus.9.png b/core/res/res/drawable/tab_focus.9.png
index 2806da9..d9bcc57a 100755
--- a/core/res/res/drawable/tab_focus.9.png
+++ b/core/res/res/drawable/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_focus_bar_left.9.png b/core/res/res/drawable/tab_focus_bar_left.9.png
index 21421cb..2536d94 100755
--- a/core/res/res/drawable/tab_focus_bar_left.9.png
+++ b/core/res/res/drawable/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_focus_bar_right.9.png b/core/res/res/drawable/tab_focus_bar_right.9.png
index b6304d9..2536d94 100755
--- a/core/res/res/drawable/tab_focus_bar_right.9.png
+++ b/core/res/res/drawable/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_press.9.png b/core/res/res/drawable/tab_press.9.png
index 3fb717c..3332660 100755
--- a/core/res/res/drawable/tab_press.9.png
+++ b/core/res/res/drawable/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_press_bar_left.9.png b/core/res/res/drawable/tab_press_bar_left.9.png
index 95ef2d3..d2c75e3 100755
--- a/core/res/res/drawable/tab_press_bar_left.9.png
+++ b/core/res/res/drawable/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_press_bar_right.9.png b/core/res/res/drawable/tab_press_bar_right.9.png
index 7ae938b5..d2c75e3 100755
--- a/core/res/res/drawable/tab_press_bar_right.9.png
+++ b/core/res/res/drawable/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_selected.9.png b/core/res/res/drawable/tab_selected.9.png
index f929d99..54190ea 100644
--- a/core/res/res/drawable/tab_selected.9.png
+++ b/core/res/res/drawable/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_selected_bar_left.9.png b/core/res/res/drawable/tab_selected_bar_left.9.png
index 58e2d35..d20f3a2 100755
--- a/core/res/res/drawable/tab_selected_bar_left.9.png
+++ b/core/res/res/drawable/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_selected_bar_right.9.png b/core/res/res/drawable/tab_selected_bar_right.9.png
index 0c9c8dd..d20f3a2 100755
--- a/core/res/res/drawable/tab_selected_bar_right.9.png
+++ b/core/res/res/drawable/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_unselected.9.png b/core/res/res/drawable/tab_unselected.9.png
index 9036c1d..1b8a69c9 100644
--- a/core/res/res/drawable/tab_unselected.9.png
+++ b/core/res/res/drawable/tab_unselected.9.png
Binary files differ
diff --git a/core/res/res/layout-ja/contact_header_name.xml b/core/res/res/layout-ja/contact_header_name.xml
index 20df5c6..9dceeb6 100644
--- a/core/res/res/layout-ja/contact_header_name.xml
+++ b/core/res/res/layout-ja/contact_header_name.xml
@@ -27,8 +27,8 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- android:textColor="@android:color/secondary_text_light"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
/>
<TextView android:id="@+id/phonetic_name"
@@ -36,8 +36,7 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
- android:textColor="@android:color/secondary_text_light"
+ android:textAppearance="?android:attr/textAppearanceSmall"
/>
</LinearLayout>
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index 73e379b..ba91e00 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -15,26 +15,27 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/banner"
+ android:id="@+id/banner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:background="@drawable/contact_header_bg"
+ android:background="@drawable/title_bar_tall"
android:paddingRight="5dip"
android:gravity="center_vertical">
<ImageView android:id="@+id/photo"
- android:layout_width="64dip"
- android:layout_height="64dip"
- android:layout_marginRight="7dip"
- android:layout_marginLeft="2dip"
+ android:layout_width="48dip"
+ android:layout_height="52dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginLeft="10dip"
android:scaleType="fitCenter"
- android:background="@drawable/contact_picture_bg"/>
+ android:background="@drawable/fasttrack_badge_middle"/>
<LinearLayout
android:layout_width="0dip"
- android:layout_height="fill_parent"
+ android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginTop="5dip"
android:orientation="vertical">
<!-- "Name" field is locale-specific. -->
@@ -42,9 +43,11 @@
<TextView android:id="@+id/status"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:maxLines="2"/>
+ android:maxLines="2"
+ android:ellipsize="end"/>
</LinearLayout>
diff --git a/core/res/res/layout/contact_header_name.xml b/core/res/res/layout/contact_header_name.xml
index 9039702..9a56fb4 100644
--- a/core/res/res/layout/contact_header_name.xml
+++ b/core/res/res/layout/contact_header_name.xml
@@ -19,8 +19,8 @@
android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMediumInverse"
- android:textColor="@android:color/secondary_text_light"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
/>
diff --git a/core/res/res/layout/keyguard_screen_glogin_unlock.xml b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
index 74ff3b0..6e00d11 100644
--- a/core/res/res/layout/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
@@ -42,7 +42,6 @@
android:gravity="center_vertical"
android:drawableLeft="@drawable/ic_lock_idle_lock"
android:drawablePadding="5dip"
- android:text="@android:string/lockscreen_glogin_too_many_attempts"
/>
<!-- spacer below header -->
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index fcf0b5e..e3ea555 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -18,6 +18,8 @@
android:layout_width="0dip"
android:layout_height="64dip"
android:layout_weight="1"
+ android:layout_marginLeft="-4px"
+ android:layout_marginRight="-4px"
android:orientation="vertical"
android:background="@android:drawable/tab_indicator">
diff --git a/core/res/res/values-en-rUS/donottranslate-names.xml b/core/res/res/values-en-rUS/donottranslate-names.xml
new file mode 100644
index 0000000..42c8ab4
--- /dev/null
+++ b/core/res/res/values-en-rUS/donottranslate-names.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- various string resources for Contacts -->
+ <string-array name="common_nicknames">
+ <item>Albert, Al, Bert, Bertie</item>
+ <item>Alexander, Al, Alex, Lex, Sasha</item>
+ <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item>
+ <item>Alice, Allie, Ally</item>
+ <item>Alison, Allie, Ally</item>
+ <item>Allison, Allie, Ally</item>
+ <item>Amanda, Mandi, Mandy</item>
+ <item>Andrea, Andie</item>
+ <item>Andrew, Andy, Drew</item>
+ <item>Anthony, Tony, Toni, Tone</item>
+ <item>Arthur, Art, Arty</item>
+ <item>Barbara, Babs, Barb, Barbie</item>
+ <item>Benjamin, Ben, Benji, Benny</item>
+ <item>Bernard, Bern, Bernie</item>
+ <item>Bertram, Bert, Bertie</item>
+ <item>Bradly, Brad</item>
+ <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Charles, Chuck, Chaz, Charlie, Buck</item>
+ <item>Christine, Chris, Chrissy, Chrissie</item>
+ <item>Christopher, Chris</item>
+ <item>Cynthia, Cindy, Cynth</item>
+ <item>Daniel, Dan, Danny</item>
+ <item>David, Dave</item>
+ <item>Deborah, Deb, Debbie</item>
+ <item>Dennis, Den, Denny, Dean</item>
+ <item>Dolores, Dolly</item>
+ <item>Donald, Don, Donny</item>
+ <item>Donnatella, Donna</item>
+ <item>Dorothea, Dot, Dotty</item>
+ <item>Dorothy, Dot, Dotty</item>
+ <item>Douglas, Doug</item>
+ <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item>
+ <item>Eleanor, Ella, Ellie, Elle</item>
+ <item>Elisabetta, Betta</item>
+ <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item>
+ <item>Emily, Em, Ems, Emmy</item>
+ <item>Emma, Em, Ems, Emmy</item>
+ <item>Erica, Rikki, Rikkie, Ricky</item>
+ <item>Eugene, Gene</item>
+ <item>Florence, Flo</item>
+ <item>Frances, Fran, Francie</item>
+ <item>Francis, Fran, Frank</item>
+ <item>Frederick, Fred, Freddy</item>
+ <item>Gabriel, Gabe</item>
+ <item>Geoffrey, Jeff</item>
+ <item>Gerald, Gerry</item>
+ <item>Gerard, Gerry</item>
+ <item>Gregory, Greg</item>
+ <item>Harold, Hal, Hank, Harry</item>
+ <item>Henry, Hal, Hank, Harry</item>
+ <item>Herbert, Bert, Bertie</item>
+ <item>Irving, Irv</item>
+ <item>Isabella, Isa, Izzy</item>
+ <item>Jacob, Jake</item>
+ <item>Jacqueline, Jackie</item>
+ <item>James, Jim, Jimmy, Jamie, Jock</item>
+ <item>Janet, Jan</item>
+ <item>Janice, Jan</item>
+ <item>Jason, Jay</item>
+ <item>Jefferson, Jeff</item>
+ <item>Jeffrey, Jeff</item>
+ <item>Jennifer, Jen, Jenny</item>
+ <item>Jerome, Jerry</item>
+ <item>Jessica, Jessie</item>
+ <item>John, Jack, Jacky, Johnny, Jon</item>
+ <item>Jonathan, Jon, John</item>
+ <item>Joseph, Joe, Joey</item>
+ <item>Joshua, Josh</item>
+ <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Kenneth, Ken</item>
+ <item>Kevin, Kev</item>
+ <item>Laura, Lauri, Laurie</item>
+ <item>Lauren, Lauri, Laurie</item>
+ <item>Laurence, Larry, Lauri, Laurie</item>
+ <item>Lawrence, Larry, Lauri, Laurie</item>
+ <item>Leonard, Leo, Len, Lenny</item>
+ <item>Leopold, Leo, Len, Lenny</item>
+ <item>Madeline, Maddie, Maddy</item>
+ <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item>
+ <item>Matthew, Matt, Mattie</item>
+ <item>Maureen, Mo</item>
+ <item>Maurice, Mo</item>
+ <item>Megan, Meg</item>
+ <item>Michael, Mickey, Mick, Mike, Mikey</item>
+ <item>Morris, Mo</item>
+ <item>Nancy, Nan</item>
+ <item>Nathan, Nat, Nate</item>
+ <item>Nathaniel, Nat, Nate</item>
+ <item>Nicholas, Nick</item>
+ <item>Pamela, Pam</item>
+ <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item>
+ <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item>
+ <item>Peter, Pete</item>
+ <item>Raymond, Ray</item>
+ <item>Philip, Phil</item>
+ <item>Rebecca, Becca</item>
+ <item>Richard, Rick, Rich, Dick</item>
+ <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item>
+ <item>Roberta, Bobbie</item>
+ <item>Rodney. Rod</item>
+ <item>Ronald, Ron, Ronnie</item>
+ <item>Rosemary, Rosie, Rose</item>
+ <item>Russell, Russ, Rusty</item>
+ <item>Ryan, Ry</item>
+ <item>Samantha, Sam</item>
+ <item>Samuel, Sam, Sammy</item>
+ <item>Sophia, Sophie</item>
+ <item>Stephanie, Steph, Stephie</item>
+ <item>Stephen, Steve</item>
+ <item>Steven, Steve</item>
+ <item>Stuart, Stu</item>
+ <item>Susan, Sue, Susie, Suzie</item>
+ <item>Suzanne, Sue, Susie, Suzie</item>
+ <item>Teresa, Terrie, Terry</item>
+ <item>Theodora, Teddie, Thea, Theo</item>
+ <item>Theodore, Ted, Teddy, Theo</item>
+ <item>Thomas, Tom, Thom, Tommy</item>
+ <item>Timothy, Tim, Timmy</item>
+ <item>Valerie, Val</item>
+ <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item>
+ <item>Victor, Vic</item>
+ <item>Victoria, Vicky, Vicki, Vickie, Tori</item>
+ <item>Vincent, Vince, Vin, Vinnie</item>
+ <item>Vivian, Vivi</item>
+ <item>Walter, Walt, Wally</item>
+ <item>Wendy, Wen, Wendel</item>
+ <item>William, Bill, Billy, Will, Willy, Liam</item>
+ <item>Yvonna, Vonna</item>
+ <item>Zachary, Zach, Zack, Zac</item>
+ </string-array>
+ <string name="common_name_prefixes">
+ 1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR,
+ GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR,
+ MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST
+ </string>
+ <string name="common_name_suffixes">
+ B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA,
+ MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X
+ </string>
+ <string name="common_last_name_prefixes">
+ D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
+ </string>
+ <string name="common_name_conjunctions">
+ &, AND, OR
+ </string>
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 01253d3..cd3f065 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -361,7 +361,7 @@
<!-- Small inverse ProgressBar style. This is a small circular progress bar. -->
<attr name="progressBarStyleSmallInverse" format="reference" />
<!-- Large inverse ProgressBar style. This is a large circular progress bar. -->
- <attr name="progressBarStyleLargeInverse" format="reference" />
+ <attr name="progressBarStyleLargeInverse" format="reference" />
<!-- Default SeekBar style. -->
<attr name="seekBarStyle" format="reference" />
<!-- Default RatingBar style. -->
@@ -937,18 +937,68 @@
<attr name="windowShowAnimation" format="reference" />
<!-- The animation used when a window is going from VISIBLE to INVISIBLE. -->
<attr name="windowHideAnimation" format="reference" />
+
+ <!-- When opening a new activity, this is the animation that is
+ run on the next activity (which is entering the screen). -->
<attr name="activityOpenEnterAnimation" format="reference" />
+ <!-- When opening a new activity, this is the animation that is
+ run on the previous activity (which is exiting the screen). -->
<attr name="activityOpenExitAnimation" format="reference" />
+ <!-- When closing the current activity, this is the animation that is
+ run on the next activity (which is entering the screen). -->
<attr name="activityCloseEnterAnimation" format="reference" />
+ <!-- When closing the current activity, this is the animation that is
+ run on the current activity (which is exiting the screen). -->
<attr name="activityCloseExitAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the new task (which is entering the screen). -->
<attr name="taskOpenEnterAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the old task (which is exiting the screen). -->
<attr name="taskOpenExitAnimation" format="reference" />
+ <!-- When closing the last activity of a task, this is the animation that is
+ run on the activity of the next task (which is entering the screen). -->
<attr name="taskCloseEnterAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the old task (which is exiting the screen). -->
<attr name="taskCloseExitAnimation" format="reference" />
+ <!-- When bringing an existing task to the foreground, this is the
+ animation that is run on the top activity of the task being brought
+ to the foreground (which is entering the screen). -->
<attr name="taskToFrontEnterAnimation" format="reference" />
+ <!-- When bringing an existing task to the foreground, this is the
+ animation that is run on the current foreground activity
+ (which is exiting the screen). -->
<attr name="taskToFrontExitAnimation" format="reference" />
+ <!-- When sending the current task to the background, this is the
+ animation that is run on the top activity of the task behind
+ it (which is entering the screen). -->
<attr name="taskToBackEnterAnimation" format="reference" />
+ <!-- When sending the current task to the background, this is the
+ animation that is run on the top activity of the current task
+ (which is exiting the screen). -->
<attr name="taskToBackExitAnimation" format="reference" />
+
+ <!-- When opening a new activity that is on top of the wallpaper
+ when the current activity is also on top of the wallpaper,
+ this is the animation that is run on the new activity
+ (which is entering the screen). -->
+ <attr name="wallpaperActivityOpenEnterAnimation" format="reference" />
+ <!-- When opening a new activity that is on top of the wallpaper
+ when the current activity is also on top of the wallpaper,
+ this is the animation that is run on the current activity
+ (which is exiting the screen). -->
+ <attr name="wallpaperActivityOpenExitAnimation" format="reference" />
+ <!-- When closing a foreround activity that is on top of the wallpaper
+ when the previous activity is also on top of the wallpaper,
+ this is the animation that is run on the previous activity
+ (which is entering the screen). -->
+ <attr name="wallpaperActivityCloseEnterAnimation" format="reference" />
+ <!-- When closing a foreround activity that is on top of the wallpaper
+ when the previous activity is also on top of the wallpaper,
+ this is the animation that is run on the current activity
+ (which is exiting the screen). -->
+ <attr name="wallpaperActivityCloseExitAnimation" format="reference" />
</declare-styleable>
<!-- ============================= -->
@@ -2224,6 +2274,10 @@
of the states. If false, the size will vary based on the
current state. -->
<attr name="constantSize" format="boolean" />
+ <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+ an RGB 565 screen.) -->
+ <attr name="dither" format="boolean" />
</declare-styleable>
<declare-styleable name="AnimationDrawable">
@@ -2348,7 +2402,7 @@
<attr name="pivotY" />
<attr name="drawable" />
</declare-styleable>
-
+
<declare-styleable name="InsetDrawable">
<attr name="visible" />
<attr name="drawable" />
@@ -2370,7 +2424,7 @@
<!-- Enables or disables dithering of the bitmap if the bitmap does not have the
same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
an RGB 565 screen.) -->
- <attr name="dither" format="boolean" />
+ <attr name="dither" />
<!-- Defines the gravity for the bitmap. The gravity indicates where to position
the drawable in its container if the bitmap is smaller than the container. -->
<attr name="gravity" />
@@ -2870,24 +2924,24 @@
when the user clicks a suggestion. <i>Optional attribute.</i> -->
<attr name="searchSuggestIntentData" format="string" />
- <!-- If provided, this is the minimum number of characters needed to trigger
+ <!-- @hide If provided, this is the minimum number of characters needed to trigger
search suggestions. The default value is 0. <i>Optional attribute.</i> -->
<attr name="searchSuggestThreshold" format="integer" />
- <!-- If provided and <code>true</code>, this searchable activity will be
+ <!-- @hide If provided and <code>true</code>, this searchable activity will be
included in any global lists of search targets.
- The default value is <code>false</code>. <i>Optional attribute.</i>. -->
+ The default value is <code>false</code>. <i>Optional attribute.</i>.-->
<attr name="includeInGlobalSearch" format="boolean" />
- <!-- If provided and <code>true</code>, this searchable activity will be invoked for all
+ <!-- @hide If provided and <code>true</code>, this searchable activity will be invoked for all
queries in a particular session. If set to <code>false</code> and the activity
returned zero results for a query, it will not be invoked again in that session for
supersets of that zero-results query. For example, if the activity returned zero
results for "bo", it would not be queried again for "bob".
The default value is <code>false</code>. <i>Optional attribute.</i>. -->
<attr name="queryAfterZeroResults" format="boolean" />
-
- <!-- If provided, this string will be used to describe the searchable item in the
+
+ <!-- @hide If provided, this string will be used to describe the searchable item in the
searchable items settings within system search settings. <i>Optional
attribute.</i> -->
<attr name="searchSettingsDescription" format="string" />
@@ -3359,6 +3413,8 @@
<!-- the authority of a content provider. -->
<attr name="contentAuthority" format="string"/>
<attr name="accountType"/>
+ <attr name="userVisible" format="boolean"/>
+ <attr name="supportsUploading" format="boolean"/>
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0fd6861..1057c09 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
-->
<resources>
<drawable name="screen_background_light">#fff9f9f9</drawable>
- <drawable name="screen_background_dark">#ff1a1a1a</drawable>
+ <drawable name="screen_background_dark">#ff202020</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
@@ -28,7 +28,7 @@
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="transparent">#00000000</color>
- <color name="background_dark">#ff1a1a1a</color>
+ <color name="background_dark">#ff202020</color>
<color name="bright_foreground_dark">#ffffffff</color>
<color name="bright_foreground_dark_disabled">#80ffffff</color>
<color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 92c776c..9966930 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -35,10 +35,6 @@
<!-- The duration (in milliseconds) of a long animation. -->
<integer name="config_longAnimTime">300</integer>
- <!-- Flag indicating whether Last Name comes before First Name.
- This becomes true in Japan, for example.-->
- <bool name="config_lastname_comes_before_firstname">false</bool>
-
<!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward -->
<!-- An Array of "[type-name],[associated radio-name],[priority] -->
<string-array translatable="false" name="networkAttributes">
@@ -57,4 +53,10 @@
<item>"wifi,1,1"</item>
<item>"mobile,0,1"</item>
</string-array>
+
+ <!-- The number of degrees to rotate the display when the keyboard is open. -->
+ <integer name="config_lidOpenRotation">90</integer>
+
+ <!-- The number of degrees to rotate the display when the device is in a dock. -->
+ <integer name="config_dockedRotation">90</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6461460a..6a3538d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -28,4 +28,10 @@
<dimen name="toast_y_offset">64dip</dimen>
<!-- Height of the status bar -->
<dimen name="status_bar_height">25dip</dimen>
+ <!-- Size of the fastscroll hint letter -->
+ <dimen name="fastscroll_overlay_size">104dp</dimen>
+ <!-- Width of the fastscroll thumb -->
+ <dimen name="fastscroll_thumb_width">64dp</dimen>
+ <!-- Height of the fastscroll thumb -->
+ <dimen name="fastscroll_thumb_height">52dp</dimen>
</resources>
diff --git a/core/res/res/values/donottranslate-names.xml b/core/res/res/values/donottranslate-names.xml
new file mode 100644
index 0000000..56ae47a
--- /dev/null
+++ b/core/res/res/values/donottranslate-names.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Various locale-specific string resources for Contacts -->
+ <string-array name="common_nicknames"></string-array>
+ <string name="common_name_prefixes"></string>
+ <string name="common_name_suffixes"></string>
+ <string name="common_last_name_prefixes"></string>
+ <string name="common_name_conjunctions"></string>
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d51b439..5f1c3c3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1094,7 +1094,9 @@
<public type="attr" name="tension" id="0x0101026a" />
<public type="attr" name="extraTension" id="0x0101026b" />
<public type="attr" name="anyDensity" id="0x0101026c" />
+ <!-- {@hide} -->
<public type="attr" name="searchSuggestThreshold" id="0x0101026d" />
+ <!-- {@hide} -->
<public type="attr" name="includeInGlobalSearch" id="0x0101026e" />
<public type="attr" name="onClick" id="0x0101026f" />
<public type="attr" name="targetSdkVersion" id="0x01010270" />
@@ -1115,6 +1117,7 @@
<public type="attr" name="backupAgent" id="0x0101027f" />
<public type="attr" name="allowBackup" id="0x01010280" />
<public type="attr" name="glEsVersion" id="0x01010281" />
+ <!-- {@hide} -->
<public type="attr" name="queryAfterZeroResults" id="0x01010282" />
<public type="attr" name="dropDownHeight" id="0x01010283" />
<public type="attr" name="smallScreens" id="0x01010284" />
@@ -1123,6 +1126,7 @@
<public type="attr" name="progressBarStyleInverse" id="0x01010287" />
<public type="attr" name="progressBarStyleSmallInverse" id="0x01010288" />
<public type="attr" name="progressBarStyleLargeInverse" id="0x01010289" />
+ <!-- {@hide} -->
<public type="attr" name="searchSettingsDescription" id="0x0101028a" />
<public type="attr" name="textColorPrimaryInverseDisableOnly" id="0x0101028b" />
<public type="attr" name="autoUrlDetect" id="0x0101028c" />
@@ -1130,17 +1134,17 @@
<public type="style" name="Widget.ProgressBar.Inverse" id="0x0103005b" />
<public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" />
- <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
+ <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
<public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" />
<public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" />
-
+
<public type="anim" name="anticipate_interpolator" id="0x010a0007" />
<public type="anim" name="overshoot_interpolator" id="0x010a0008" />
<public type="anim" name="anticipate_overshoot_interpolator" id="0x010a0009" />
<public type="anim" name="bounce_interpolator" id="0x010a000a" />
<public type="anim" name="linear_interpolator" id="0x010a000b" />
-
+
<!-- ===============================================================
Resources added in Eclair.
=============================================================== -->
@@ -1148,10 +1152,16 @@
<public type="attr" name="accountType" />
<public type="attr" name="contentAuthority" />
+ <public type="attr" name="userVisible" />
<public type="attr" name="windowShowWallpaper" />
+ <public type="attr" name="wallpaperActivityOpenEnterAnimation" />
+ <public type="attr" name="wallpaperActivityOpenExitAnimation" />
+ <public type="attr" name="wallpaperActivityCloseEnterAnimation" />
+ <public type="attr" name="wallpaperActivityCloseExitAnimation" />
<public type="style" name="Theme.Wallpaper" />
<public type="style" name="Theme.Wallpaper.NoTitleBar" />
<public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
+ <public type="attr" name="supportsUploading" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 815b767..7dc4ff9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1294,7 +1294,11 @@
their lock gesture -->
<string name="lockscreen_forgot_pattern_button_text">Forgot pattern?</string>
- <!-- Title of the unlock screen that uses your Google login and password -->
+ <!-- Title of the unlock screen that uses your Google login and password when the user hit
+ the 'forgot pattern' button.-->
+ <string name="lockscreen_glogin_forgot_pattern">Account unlock</string>
+ <!-- Title of the unlock screen that uses your Google login and password when the user attempted
+ too many patterns and we are forcing them to use their account instead. -->
<string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
<!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone -->
<string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account</string>
@@ -1307,6 +1311,9 @@
<!-- Displayed to the user when unlocking the phone with a username and password fails. -->
<string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
+ <!-- Displayed in a progress dialog while a username and password are being checked. -->
+ <string name="lockscreen_glogin_checking_password">Checking...</string>
+
<!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
<string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
@@ -1350,7 +1357,7 @@
<!-- When the battery is low, this is the label of the button to go to the
power usage activity to find out what drained the battery. -->
- <string name="battery_low_why">Why?</string>
+ <string name="battery_low_why">Battery use</string>
<!-- Title of the alert when something went wrong in the factory test. -->
<string name="factorytest_failed">Factory test failed</string>
@@ -1641,7 +1648,7 @@
<string name="copyUrl">Copy URL</string>
<!-- EditText context menu -->
- <string name="inputMethod">Input Method</string>
+ <string name="inputMethod">Input method</string>
<!-- Item on EditText context menu, used to add a word to the
input method dictionary. -->
@@ -1923,157 +1930,6 @@
<!-- This string appears (on two lines) when you type a number into contacts search, to let you create a contact whose phone number is the number you typed. The first line will be in bigger type than the second. -->
<string name="create_contact_using">Create contact\nusing <xliff:g id="number" example="555">%s</xliff:g></string>
- <!-- various string resources for Contacts -->
- <string-array name="common_nicknames">
- <item>Albert, Al, Bert, Bertie</item>
- <item>Alexander, Al, Alex, Lex, Sasha</item>
- <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item>
- <item>Alice, Allie, Ally</item>
- <item>Alison, Allie, Ally</item>
- <item>Allison, Allie, Ally</item>
- <item>Amanda, Mandi, Mandy</item>
- <item>Andrea, Andie</item>
- <item>Andrew, Andy, Drew</item>
- <item>Anthony, Tony, Toni, Tone</item>
- <item>Arthur, Art, Arty</item>
- <item>Barbara, Babs, Barb, Barbie</item>
- <item>Benjamin, Ben, Benji, Benny</item>
- <item>Bernard, Bern, Bernie</item>
- <item>Bertram, Bert, Bertie</item>
- <item>Bradly, Brad</item>
- <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item>
- <item>Charles, Chuck, Chaz, Charlie, Buck</item>
- <item>Christine, Chris, Chrissy, Chrissie</item>
- <item>Christopher, Chris</item>
- <item>Cynthia, Cindy, Cynth</item>
- <item>Daniel, Dan, Danny</item>
- <item>David, Dave</item>
- <item>Deborah, Deb, Debbie</item>
- <item>Dennis, Den, Denny, Dean</item>
- <item>Dolores, Dolly</item>
- <item>Donald, Don, Donny</item>
- <item>Donnatella, Donna</item>
- <item>Dorothea, Dot, Dotty</item>
- <item>Dorothy, Dot, Dotty</item>
- <item>Douglas, Doug</item>
- <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item>
- <item>Eleanor, Ella, Ellie, Elle</item>
- <item>Elisabetta, Betta</item>
- <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item>
- <item>Emily, Em, Ems, Emmy</item>
- <item>Emma, Em, Ems, Emmy</item>
- <item>Erica, Rikki, Rikkie, Ricky</item>
- <item>Eugene, Gene</item>
- <item>Florence, Flo</item>
- <item>Frances, Fran, Francie</item>
- <item>Francis, Fran, Frank</item>
- <item>Frederick, Fred, Freddy</item>
- <item>Gabriel, Gabe</item>
- <item>Geoffrey, Jeff</item>
- <item>Gerald, Gerry</item>
- <item>Gerard, Gerry</item>
- <item>Gregory, Greg</item>
- <item>Harold, Hal, Hank, Harry</item>
- <item>Henry, Hal, Hank, Harry</item>
- <item>Herbert, Bert, Bertie</item>
- <item>Irving, Irv</item>
- <item>Isabella, Isa, Izzy</item>
- <item>Jacob, Jake</item>
- <item>Jacqueline, Jackie</item>
- <item>James, Jim, Jimmy, Jamie, Jock</item>
- <item>Janet, Jan</item>
- <item>Janice, Jan</item>
- <item>Jason, Jay</item>
- <item>Jefferson, Jeff</item>
- <item>Jeffrey, Jeff</item>
- <item>Jennifer, Jen, Jenny</item>
- <item>Jerome, Jerry</item>
- <item>Jessica, Jessie</item>
- <item>John, Jack, Jacky, Johnny, Jon</item>
- <item>Jonathan, Jon, John</item>
- <item>Joseph, Joe, Joey</item>
- <item>Joshua, Josh</item>
- <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
- <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
- <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
- <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
- <item>Kenneth, Ken</item>
- <item>Kevin, Kev</item>
- <item>Laura, Lauri, Laurie</item>
- <item>Lauren, Lauri, Laurie</item>
- <item>Laurence, Larry, Lauri, Laurie</item>
- <item>Lawrence, Larry, Lauri, Laurie</item>
- <item>Leonard, Leo, Len, Lenny</item>
- <item>Leopold, Leo, Len, Lenny</item>
- <item>Madeline, Maddie, Maddy</item>
- <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item>
- <item>Matthew, Matt, Mattie</item>
- <item>Maureen, Mo</item>
- <item>Maurice, Mo</item>
- <item>Megan, Meg</item>
- <item>Michael, Mickey, Mick, Mike, Mikey</item>
- <item>Morris, Mo</item>
- <item>Nancy, Nan</item>
- <item>Nathan, Nat, Nate</item>
- <item>Nathaniel, Nat, Nate</item>
- <item>Nicholas, Nick</item>
- <item>Pamela, Pam</item>
- <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item>
- <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item>
- <item>Peter, Pete</item>
- <item>Raymond, Ray</item>
- <item>Philip, Phil</item>
- <item>Rebecca, Becca</item>
- <item>Richard, Rick, Rich, Dick</item>
- <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item>
- <item>Roberta, Bobbie</item>
- <item>Rodney. Rod</item>
- <item>Ronald, Ron, Ronnie</item>
- <item>Rosemary, Rosie, Rose</item>
- <item>Russell, Russ, Rusty</item>
- <item>Ryan, Ry</item>
- <item>Samantha, Sam</item>
- <item>Samuel, Sam, Sammy</item>
- <item>Sophia, Sophie</item>
- <item>Stephanie, Steph, Stephie</item>
- <item>Stephen, Steve</item>
- <item>Steven, Steve</item>
- <item>Stuart, Stu</item>
- <item>Susan, Sue, Susie, Suzie</item>
- <item>Suzanne, Sue, Susie, Suzie</item>
- <item>Teresa, Terrie, Terry</item>
- <item>Theodora, Teddie, Thea, Theo</item>
- <item>Theodore, Ted, Teddy, Theo</item>
- <item>Thomas, Tom, Thom, Tommy</item>
- <item>Timothy, Tim, Timmy</item>
- <item>Valerie, Val</item>
- <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item>
- <item>Victor, Vic</item>
- <item>Victoria, Vicky, Vicki, Vickie, Tori</item>
- <item>Vincent, Vince, Vin, Vinnie</item>
- <item>Vivian, Vivi</item>
- <item>Walter, Walt, Wally</item>
- <item>Wendy, Wen, Wendel</item>
- <item>William, Bill, Billy, Will, Willy, Liam</item>
- <item>Yvonna, Vonna</item>
- <item>Zachary, Zach, Zack, Zac</item>
- </string-array>
- <string name="common_name_prefixes">
- 1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR,
- GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR,
- MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST
- </string>
- <string name="common_name_suffixes">
- B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA,
- MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X
- </string>
- <string name="common_last_name_prefixes">
- D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
- </string>
- <string name="common_name_conjunctions">
- &, AND, OR
- </string>
-
<!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale,wifi-channel sets. This is used at startup to set system defaults by checking the system property ro.carrier for the carrier-id and searching through this array -->
<!-- An Array of [[Carrier-ID] -->
<!-- [default-locale] -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4aa4210..3950cb1 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -66,6 +66,10 @@
<item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
<item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
<item name="taskToBackExitAnimation">@anim/task_close_exit</item>
+ <item name="wallpaperActivityOpenEnterAnimation">@anim/wallpaper_activity_open_enter</item>
+ <item name="wallpaperActivityOpenExitAnimation">@anim/wallpaper_activity_open_exit</item>
+ <item name="wallpaperActivityCloseEnterAnimation">@anim/wallpaper_activity_close_enter</item>
+ <item name="wallpaperActivityCloseExitAnimation">@anim/wallpaper_activity_close_exit</item>
</style>
<!-- Standard animations for a non-full-screen window or activity. -->
@@ -130,8 +134,7 @@
<item name="windowExitAnimation">@anim/slide_out_down</item>
</style>
- <!-- Window animations that are applied to input method overlay windows.
- {@hide Pending API council approval} -->
+ <!-- Window animations that are applied to input method overlay windows. -->
<style name="Animation.InputMethod">
<item name="windowEnterAnimation">@anim/input_method_enter</item>
<item name="windowExitAnimation">@anim/input_method_exit</item>
@@ -151,8 +154,7 @@
<item name="windowExitAnimation">@anim/search_bar_exit</item>
</style>
- <!-- Window animations that are applied to the zoom buttons overlay window.
- {@hide Pending API council approval} -->
+ <!-- Window animations that are applied to the zoom buttons overlay window. -->
<style name="Animation.ZoomButtons">
<item name="windowEnterAnimation">@anim/fade_in</item>
<item name="windowExitAnimation">@anim/fade_out</item>
@@ -337,7 +339,7 @@
</style>
<style name="Widget.TextView.ListSeparator">
- <item name="android:background">@android:drawable/dark_header</item>
+ <item name="android:background">@android:drawable/dark_header_dither</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">25dip</item>
<item name="android:textStyle">bold</item>
@@ -349,7 +351,7 @@
<style name="Widget.TextView.ListSeparator.White">
<item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:background">@android:drawable/light_header</item>
+ <item name="android:background">@android:drawable/light_header_dither</item>
</style>
<style name="Widget.EditText">
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 20aa6e7..7322e6c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -146,8 +146,6 @@
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
- <library name="com.android.im.plugin"
- file="/system/framework/com.android.im.plugin.jar"/>
<library name="javax.obex"
file="/system/framework/javax.obex.jar"/>
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index 2c42e78..9dea053 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -7,11 +7,12 @@
<ol>
<li><a href="#devices">Available Devices</a>
<ol>
- <li><a href="#g1">T-Mobile G1</a></li>
+ <li><a href="#consumer">Consumer devices</a></li>
<li><a href="#dev-phone-1">Android Dev Phone 1</a></li>
</ol>
</li>
<li><a href="#setting-up">Setting up a Device for Development</a></li>
+ <li><a href="#WinUsbDriver">Installing the WinUsb Driver</a></li>
</ol>
</div>
</div>
@@ -23,20 +24,24 @@
<h2 id="devices">Available Devices</h2>
-<p>While developers can use regular
-consumer devices purchased at retail to test and use their apps, some developers
-may choose not to use a retail device, preferring an unlocked or no-contract
-device. Here are some options for obtaining devices capable of testing your applications.</p>
+<p>Here are some options for obtaining devices capable of testing your applications.</p>
-<h3 id="g1">T-Mobile G1</h3>
+<h3 id="consumer">Consumer devices</h3>
-<p>The T-Mobile G1 device makes an excellent development device. You can write
-applications in the SDK and install them on the G1, then run them as users
-would, using the same hardware, system, and network.</p>
+<p>It's likely that one of your local mobile carriers offers an Android-powered device.
+Any Android-powered device (even one bought from your mobile carrier) is a perfectly good
+device for running and testing your own Android applications.
+You can write applications using the Android SDK and then install them
+directly onto the device for testing.</p>
-<p>For more information about obtaining a G1, visit the <a
-href="http://www.t-mobileg1.com">T-Mobile G1 site</a>. </p>
+<p>Check with the service providers in your area to determine which Android-powered
+devices are available.</p>
+
+<p>Be aware that consumer devices are not designed to allow system image updates by the
+user. If you're interested in manually updating the device with custom system images, then
+you'll need a developer device such as the <a href="#dev-phone-1">Android Dev Phone 1</a>.</p>
+
<h3 id="dev-phone-1">Android Dev Phone 1</h3>
@@ -60,6 +65,7 @@
</ul>
</div>
</div>
+
<p>The Android Dev Phone 1 is a SIM-unlocked and hardware-unlocked device that
is designed for advanced developers. The device ships with a system image that
is fully compatible with Android 1.0, so you can rely on it when developing your
@@ -67,7 +73,7 @@
builds that will work with the unlocked bootloader. Unlike the bootloader on
retail devices, the bootloader on the Android Dev Phone 1 does not enforce
signed system images. The Android Dev Phone 1 should also appeal to developers
-who live outside of T-Mobile geographies. </p>
+who live in geographies where local mobile carriers do not currently offer Android-powered devices. </p>
<p>To purchase an Android Dev Phone 1 device, you must first register as an
Android developer on the Android Market site, if you haven't done so already.
@@ -82,25 +88,30 @@
Hungary. We will continue to expand this program into new geographies over
time. Check this page for updated information.</p>
-<p>Note that Android Dev Phone 1 devices are <em>not</em> intended for
+<p>Android Dev Phone 1 devices are <em>not</em> intended for
non-developer end-users. Because the device can be configured with system
software not provided by or supported by Google or any other company, end-users
operate these devices at their own risk.</p>
+<p>Note that your Android Dev Phone 1 will not receive automated
+over-the-air (OTA) updates for the system image. System updates must be flashed manually.
+See the HTC site for a guide to <a href="http://www.htc.com/www/support/android/adp.html">Flashing
+your Android Dev Phone with a Factory System Image</a>.</p>
+
<p>For full device specs and more information about obtaining an Android Dev
Phone 1 device, see the <a href="http://market.android.com/publish">Android
Market</a> site.</p>
+
<h2 id="setting-up">Setting up a Device for Development</h2>
-<p>With a T-mobile G1 or Android Dev Phone 1, you can develop and debug your Android applications just as you
+<p>With an Android-powered device, you can develop and debug your Android applications just as you
would on the emulator. There are just a few things to do before you can start.</p>
<ol>
<li>Declare your application as "debuggable" in your Android Manifest.
<p>In Eclipse, you can do this from the <b>Application</b> tab when viewing the Manifest
(on the right side, set <b>Debuggable</b> to <em>true</em>). Otherwise, in the <code>AndroidManifest.xml</code>
-
file, add <code>android:debuggable="true"</code> to the <code><application></code> element.</p>
</li>
<li>Turn on "USB Debugging" on your device.
@@ -110,30 +121,8 @@
</li>
<li>Setup your system to detect your device.
<ul>
- <li>If you're developing on 32-bit Windows, you need to install the 32-bit USB driver for adb.
- The USB driver is included in the SDK package. To install it, follow these steps:</p>
- <ol>
- <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears,
- you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this
- time</em> and click <b>Next</b>.</li>
-
- <li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li>
- <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/x86</code> in the SDK package (<code><sdk>\usb_driver\x86</code>).</li>
- <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li>
- </ol>
- </li>
- <li>If you're developing on 64-bit Windows Vista, you need to install the 64-bit USB driver for adb.
- The USB driver is included in the SDK package. To install it, follow these steps:</p>
- <ol>
- <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears,
- you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this
- time</em> and click <b>Next</b>.</li>
-
- <li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li>
- <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/amd64</code> in the SDK package (<code><sdk>\usb_driver\amd64</code>).</li>
- <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li>
- </ol>
- </li>
+ <li>If you're developing on Windows, you need to install a USB driver for adb.
+ Follow the steps below for <a href="#WinUsbDriver">Installing the WinUsb Driver</a>.</li>
<li>If you're developing on Mac OS X, it just works. Skip this step.</li>
<li>If you're developing on Ubuntu Linux, you need to add a rules file:
<ol>
@@ -145,7 +134,7 @@
<code>SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"</code></p>
</li>
<li>Now execute:<br/>
- <code>chmod a+r /etc/udev/rules.d/50-android.rules</code>
+ <code>chmod a+r /etc/udev/rules.d/51-android.rules</code>
</li>
</ol>
@@ -161,3 +150,156 @@
<p>If using the <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> (adb),
you can issue commands with the <code>-d</code> flag to target your connected device.</p>
+
+
+
+
+<h2 id="WinUsbDriver">Installing the WinUsb Driver</h2>
+
+<p>A WinUsb-based driver is needed in order to use your Android-powered device for development on a Windows machine.
+The USB installation package can be found in the <code><em><sdk></em>\usb_driver\</code>
+folder of your SDK package.</p>
+
+<p class="note"><strong>Note:</strong> If you are connecting an Android-powered device to your computer
+for the first time, folllow the procedure to "Perform a fresh installation."
+Android SDKs older than version 1.6 included a non-WinUsb-based driver
+for connecting your device. If you installed the older USB driver and it is working properly,
+you do not need to upgrade to the new driver. However, if you are having problems with the driver or
+would simply like to upgrade to the latest version, follow the procedure to "Upgrade an existing
+driver." </p>
+
+<p>Before you begin installing or upgrading the USB driver, you must
+copy the USB installation package to a secure location on your computer.
+For example, you might want to create a directory at <code>C:\Android\Windows\USB\install\</code> and
+move it there. Once you've moved the installation package, select the appropriate procedure below,
+based on your operating system and whether you're installing for the first time or upgrading.</p>
+
+<ol class="nolist">
+ <li>Windows Vista:
+ <ol class="nolist">
+ <li><a href="#VistaFreshInstall">Perform a fresh installation</a></li>
+ <li><a href="#VistaUprade">Upgrade an existing driver</a></li>
+ </ol>
+ </li>
+ <li>Windows XP:
+ <ol class="nolist">
+ <li><a href="#XPFreshInstall">Perform a fresh installation</a></li>
+ <li><a href="#XPUpgrade">Upgrade an existing driver</a></li>
+ </ol>
+ </li>
+</ol>
+
+
+<p class="caution"><strong>Caution:</strong>
+You may make changes to <code>android_winusb.inf</code> file found inside <code>usb_driver\</code>
+(e.g., to add support for new devices),
+however, this will lead to security warnings when you install or upgrade the
+driver. Making any other changes to the driver files may break the installation process.</p>
+
+<h3 id="VistaFreshInstall">Windows Vista: Perform a fresh installation</h3>
+
+<p>To install the Android USB driver on Windows Vista for the first time:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port. Windows will detect the device
+ and launch the Found New Hardware wizard.</li>
+ <li>Select "Locate and install driver software."</li>
+ <li>Select "Don't search online."</li>
+ <li>Select "I don't have the disk. Show me other options."</li>
+ <li>Select "Browse my computer for driver software."</li>
+ <li>Click "Browse..." and locate the folder where you copied the
+ installation package. As long as you specified the exact location of the
+ installation package, you may leave "Include subfolders" checked or unchecked—it doesn't matter.</li>
+ <li>Click "Next." Vista may prompt you to confirm the privilege elevation required for driver
+ installation. Confirm it.</li>
+ <li>When Vista asks if you'd like to install the Google ADB Interface device, click "Install"
+ to install the driver.</li>
+</ol>
+
+<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p>
+
+
+
+<h3 id="VistaUpgrade">Windows Vista: Upgrade an existing driver</h3>
+
+<p>To upgrade an existing Android USB driver on Windows Vista with the new one:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on "Computer" from your desktop or Windows Explorer,
+ and select "Manage."</li>
+ <li>Select "Device Manager" in the left pane of the Computer Management window.</li>
+ <li>Locate and expand "ADB Interface" in the right pane.</li>
+ <li>Right-click on "HTC Dream Composite ADB Interface", and select "Update Driver Software..."</li>
+ <li>When Vista starts updating the driver, a prompt will ask how you want to search for the driver
+ software. Select "Browse my computer for driver software."</li>
+ <li>Click "Browse..." and locate the folder where you copied the
+ installation package. As long as you specified the exact location of the
+ installation package, you may leave "Include subfolders" checked or unchecked—it doesn't matter.</li>
+ <li>Click "Next." Vista may prompt you to confirm the privilege elevation required for driver
+ installation. Confirm it.</li>
+ <li>When Vista asks if you'd like to install the Google ADB Interface device, click "Install"
+ to install the driver.</li>
+</ol>
+
+<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p>
+
+
+
+<h3 id="XPFreshInstall">Windows XP: Perform a fresh installation</h3>
+
+<p>To install the Android USB driver on Windows XP for the first time:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port. Windows
+ will detect the device and launch the Hardware Update Wizard.</li>
+ <li>Select "Install from a list or specific location" and click
+ "Next."</li>
+ <li>Select "Search for the best driver in these locations"; uncheck "Search
+ removable media"; and check "Include this location in the search."</li>
+ <li>Click "Browse..." and locate the folder where you copied the installation
+ package.</li>
+ <li>Click "Next" to install the driver.</li>
+</ol>
+
+<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p>
+
+
+
+<h3 id="XPUpgrade">Windows XP: Upgrade an existing driver</h3>
+
+<p>To upgrade an existing Android USB driver on Windows XP with the new one:</p>
+
+<ol>
+ <li>Connect your Android-powered device to your computer's USB port.</li>
+ <li>Right-click on "My Computer" from your desktop or Windows Explorer,
+ and select "Manage."</li>
+ <li>Select "Device Manager" in the left pane of the Computer Management window.</li>
+ <li>Locate and expand "Android Phone" in the right pane.</li>
+ <li>Right-click "Android Composite ADB Interface" and select "Update Driver..."
+ This will launch the Hardware Update Wizard.</li>
+ <li>Select "Install from a list or specific location" and click
+ "Next."</li>
+ <li>Select "Search for the best driver in these locations"; uncheck "Search
+ removable media"; and check "Include this location in the search."</li>
+ <li>Click "Browse..." and locate the folder where you copied the installation
+ package.</li>
+ <li>Click "Next" to install the driver.</li>
+</ol>
+
+<p>Return to <a href="#setting-up">Setting up a Device for Development</a>.</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/guide/developing/tools/aidl.jd b/docs/html/guide/developing/tools/aidl.jd
index f370a80..abfa8b1 100644
--- a/docs/html/guide/developing/tools/aidl.jd
+++ b/docs/html/guide/developing/tools/aidl.jd
@@ -194,7 +194,6 @@
<li>Make your class implement the {@link android.os.Parcelable} interface.</li>
<li>Implement the method <code>public void writeToParcel(Parcel out)</code> that takes the
current state of the object and writes it to a parcel.</li>
-<li>Implement the method <code>public void readFromParcel(Parcel in)</code> that reads the
value in a parcel into your object.</li>
<li>Add a static field called <code>CREATOR</code> to your class which is an object implementing
the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.</li>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 2127187..459ad37 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -139,13 +139,16 @@
<li><a href="<?cs var:toroot ?>guide/topics/manifest/intent-filter-element.html"><intent-filter></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/manifest-element.html"><manifest></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/meta-data-element.html"><meta-data></a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/path-permission-element.html"><path-permission></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-element.html"><permission></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-group-element.html"><permission-group></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-tree-element.html"><permission-tree></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/provider-element.html"><provider></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/receiver-element.html"><receiver></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/service-element.html"><service></a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/supports-screens-element.html"><supports-screens></a></li> <!-- ##api level 4## -->
<li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-feature-element.html"><uses-feature></a></li> <!-- ##api level 4## -->
<li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-library-element.html"><uses-library></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-permission-element.html"><uses-permission></a></li>
<li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a></li>
@@ -384,17 +387,30 @@
<li><a href="<?cs var:toroot ?>guide/samples/ApiDemos/index.html">
<span class="en">API Demos</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/Home/index.html">
+ <span class="en">Home</span>
+ </a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/JetBoy/index.html">
+ <span class="en">JetBoy</span>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/samples/LunarLander/index.html">
<span class="en">Lunar Lander</span>
</a></li>
<li><a href="<?cs var:toroot ?>guide/samples/NotePad/index.html">
- <span class="en">NotePad</span>
+ <span class="en">Note Pad</span>
+ </a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/Snake/index.html">
+ <span class="en">Snake</span>
+ </a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/SoftKeyboard/index.html">
+ <span class="en">Soft Keyboard</span>
</a></li>
</ul>
</li>
<?cs /if ?>
</ul>
</li>
+
<li>
<h2><span class="en">Appendix</span>
@@ -407,6 +423,9 @@
<span class="zh-TW">附錄</span>
</h2>
<ul>
+ <li><a href="<?cs var:toroot ?>guide/appendix/api-levels.html">
+ <span class="en">Android API Levels</span>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
<span class="en">Supported Media Formats</span>
</a></li>
diff --git a/docs/html/guide/samples/images/HomeSample.png b/docs/html/guide/samples/images/HomeSample.png
new file mode 100644
index 0000000..990bebb
--- /dev/null
+++ b/docs/html/guide/samples/images/HomeSample.png
Binary files differ
diff --git a/docs/html/guide/samples/images/JetBoy.png b/docs/html/guide/samples/images/JetBoy.png
new file mode 100644
index 0000000..3da0448
--- /dev/null
+++ b/docs/html/guide/samples/images/JetBoy.png
Binary files differ
diff --git a/docs/html/guide/samples/images/Snake.png b/docs/html/guide/samples/images/Snake.png
new file mode 100644
index 0000000..c5211d8
--- /dev/null
+++ b/docs/html/guide/samples/images/Snake.png
Binary files differ
diff --git a/docs/html/guide/samples/images/SoftKeyboard.png b/docs/html/guide/samples/images/SoftKeyboard.png
new file mode 100644
index 0000000..8a4ec63
--- /dev/null
+++ b/docs/html/guide/samples/images/SoftKeyboard.png
Binary files differ
diff --git a/docs/html/guide/samples/images/sample_lunarlander.png b/docs/html/guide/samples/images/sample_lunarlander.png
new file mode 100644
index 0000000..a2ff75a
--- /dev/null
+++ b/docs/html/guide/samples/images/sample_lunarlander.png
Binary files differ
diff --git a/docs/html/guide/samples/images/sample_note.png b/docs/html/guide/samples/images/sample_note.png
new file mode 100644
index 0000000..8fc9dcc
--- /dev/null
+++ b/docs/html/guide/samples/images/sample_note.png
Binary files differ
diff --git a/docs/html/guide/samples/images/sample_notepad.png b/docs/html/guide/samples/images/sample_notepad.png
new file mode 100644
index 0000000..46f2211
--- /dev/null
+++ b/docs/html/guide/samples/images/sample_notepad.png
Binary files differ
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index 365284d..d8bbc41 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -15,11 +15,28 @@
<p>You can easily add these applications as projects in your development environment, so that you
can modify them and watch them execute. </p>
<dl>
+
<dt><a href="ApiDemos/index.html">API Demos</a></dt>
- <dd>A variety of small applications that demonstrate simple views and widgets.</dd>
+ <dd>A variety of small applications that demonstrate an extensive collection of framework topics.</dd>
+
+ <dt><a href="Home/index.html">Home</a></dt>
+ <dd>An application for saving notes. Similar (but not identical) to the
+ <a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
+
+ <dt><a href="JetBoy/index.html">JetBoy</a></dt>
+ <dd>JetBoy is a game that demonstrates the SONiVOX JET interactive music technology, with {@link android.media.JetPlayer}.</dd>
+
<dt><a href="LunarLander/index.html">Lunar Lander</a></dt>
<dd>A classic Lunar Lander game.</dd>
+
<dt><a href="NotePad/index.html">Note Pad</a></dt>
<dd>An application for saving notes. Similar (but not identical) to the
<a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
+
+ <dt><a href="Snake/index.html">Snake</a></dt>
+ <dd>An implementation of the classic game "Snake."</dd>
+
+ <dt><a href="SoftKeyboard/index.html">Soft Keyboard</a></dt>
+ <dd>An example of writing an input method for a software keyboard.</dd>
+
</dl>
diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd
index 1907024..89171c1 100644
--- a/docs/html/guide/topics/manifest/manifest-intro.jd
+++ b/docs/html/guide/topics/manifest/manifest-intro.jd
@@ -78,10 +78,11 @@
<a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission /></a>
<a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree /></a>
<a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group /></a>
-
<a href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><instrumentation /></a>
-
<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk /></a>
+ <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration /></a> <!-- ##api level 3## -->
+ <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature /></a> <!-- ##api level 4## -->
+ <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens /></a> <!-- ##api level 4## -->
<a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a>
@@ -111,11 +112,11 @@
<a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a>
<a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission /></a>
+ <a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission /></a>
<a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data /></a>
<a href="{@docRoot}guide/topics/manifest/provider-element.html"></provider></a>
<a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library /></a>
- <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration /></a> <!-- ##api level 3## -->
<a href="{@docRoot}guide/topics/manifest/application-element.html"></application></a>
@@ -140,19 +141,23 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission /></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code> <!-- ##api level 4## -->
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code> <!-- ##api level 3## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a></code> <!-- ##api level 4## -->
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a></code>
</p>
+
<h2 id="filec">File Conventions</h2>
diff --git a/docs/html/guide/topics/manifest/path-permission-element.jd b/docs/html/guide/topics/manifest/path-permission-element.jd
new file mode 100644
index 0000000..5c271a7
--- /dev/null
+++ b/docs/html/guide/topics/manifest/path-permission-element.jd
@@ -0,0 +1,104 @@
+page.title=<path-permission>
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">
+<path-permission android:<a href="#path">path</a>="<i>string</i>"
+ android:<a href="#pathPrefix">pathPrefix</a>="<i>string</i>"
+ android:<a href="#pathPattern">pathPattern</a>="<i>string</i>"
+ android:<a href="#permission">permission</a>="<i>string</i>"
+ android:<a href="#readPermission">readPermission</a>="<i>string</i>"
+ android:<a href="#writePermission">writePermission</a>="<i>string</i>" />
+</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code></dd>
+
+<!--
+<dt>can contain:</dt>
+</dd>
+-->
+
+<dt>description:</dt>
+<dd>Defines the path and required permissions for a specific subset of data
+within a content provider. This element can be
+specified multiple times to supply multiple paths.
+
+</dd>
+
+<dt>attributes:</dt>
+
+<dd><dl class="attr">
+<dt><a name="path"></a>{@code android:path}</dt>
+<dd>A complete URI path for a subset of content provider data.
+Permission can be granted only to the particular data identified by this path.
+When used to provide search suggestion content, it must be appended
+with "/search_suggest_query".
+</dd>
+
+<dt><a name="pathPrefix"></a>{@code android:pathPrefix}</dt>
+<dd>The initial part of a URI path for a subset of content provider data.
+Permission can be granted to all data subsets with paths that share this initial part.
+</dd>
+
+<dt><a name="pathPattern"></a>{@code android:pathPattern}</dt>
+<dd>A complete URI path for a subset of content provider data,
+but one that can use the following wildcards:
+
+<ul>
+<li>An asterisk ('<code class="Code prettyprint">*</code>'). This matches a sequence of 0 to many occurrences of
+the immediately preceding character.</li>
+
+<li>A period followed by an asterisk ("<code class="Code prettyprint">.*</code>"). This matches any sequence of
+0 or more characters.</li>
+</ul>
+
+<p>
+Because '<code class="Code prettyprint">\</code>' is used as an escape character when the string is read
+from XML (before it is parsed as a pattern), you will need to double-escape.
+For example, a literal '<code class="Code prettyprint">*</code>' would be written as "<code class="Code prettyprint">\\*</code>" and a
+literal '<code class="Code prettyprint">\</code>' would be written as "<code class="Code prettyprint">\\</code>". This is basically
+the same as what you would need to write if constructing the string in Java code.
+</p>
+<p>
+For more information on these types of patterns, see the descriptions of
+<a href="/reference/android/os/PatternMatcher.html#PATTERN_LITERAL">PATTERN_LITERAL</a>,
+<a href="/reference/android/os/PatternMatcher.html#PATTERN_PREFIX">PATTERN_PREFIX</a>, and
+<a href="/reference/android/os/PatternMatcher.html#PATTERN_SIMPLE_GLOB">PATTERN_SIMPLE_GLOB</a> in the
+<a href="/reference/android/os/PatternMatcher.html">PatternMatcher</a> class.
+</p>
+</dd>
+
+<dt><a name="permission"></a>{@code android:permission}</dt>
+<dd>The name of a permission that clients must have in order to read or write the
+content provider's data. This attribute is a convenient way of setting a
+single permission for both reading and writing. However, the
+<code>readPermission</code> and
+<code>writePermission</code> attributes take precedence
+over this one.
+</dd>
+
+<dt><a name="readPermission"></a>{@code android:readPermission}</dt>
+<dd>A permission that clients must have in order to query the content provider.
+</dd>
+
+<dt><a name="writePermission"></a>{@code android:writePermission}</dt>
+<dd>A permission that clients must have in order to make changes to the data controlled by the content provider.
+</dd>
+
+
+
+</dl></dd>
+
+<!-- ##api level indication## -->
+<dt>introduced in:</dt>
+<dd>API Level 4</dd>
+
+<dt>see also:</dt>
+<dd>{@link android.app.SearchManager}</dd>
+<dd>{@link android.Manifest.permission}</dd>
+<dd><a href="/guide/topics/security/security.html">Security and
+Permissions</a></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index 2bb4ff4..3942f95 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -25,7 +25,9 @@
<dt>can contain:</dt>
<dd><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code></dd>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission /></a></code>
+</dd>
<dt>description:</dt>
<dd>Declares a content provider — a subclass of
diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd
new file mode 100644
index 0000000..00797ed
--- /dev/null
+++ b/docs/html/guide/topics/manifest/supports-screens-element.jd
@@ -0,0 +1,123 @@
+page.title=<supports-screens>
+@jd:body
+
+<dl class="xml">
+
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">
+<supports-screens android:<a href="#small">smallScreens</a>=["true" | "false"]
+ android:<a href="#normal">normalScreens</a>=["true" | "false"]
+ android:<a href="#large">largeScreens</a>=["true" | "false"]
+ android:<a href="#any">anyDensity</a>=["true" | "false"] />
+</pre>
+</dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
+
+<dt>description:</dt>
+<dd>Lets you specify the screen dimensions the
+application supports. By default a modern application (using API Level 4 or higher) supports all
+screen sizes and must explicitly disable certain screen sizes here;
+older applications are assumed to support only the "normal"
+screen size. Note that screen size is a separate axis from
+density. Screen size is determined as the available pixels to an application
+after density scaling has been applied.
+
+<p>Based on the target device screen density, the Android
+framework will scale down assets by a factor of 0.75 (low dpi screens)
+or scale them up by a factor of 1.5 (high dpi screens).
+The screen density is expressed as dots-per-inch (dpi).</p>
+
+<p>Currently supported densities:</p>
+<ul>
+ <li>Low density: 120 dpi</li>
+ <li>Medium density: 160 dpi</li>
+ <li>High density: 240 dpi</li>
+</ul>
+
+<p>Table of display types:</p>
+
+<table>
+<tr>
+ <th></th><th>Low Density</th><th>Medium Density</th><th>High Density</th>
+</tr>
+<tr>
+ <th>Small Screen</th>
+ <td>QVGA</td>
+ <td>n/a</td>
+ <td>VGA</td>
+</tr>
+<tr>
+ <th>Normal Screen</th>
+ <td>WQVGA</td>
+ <td>HVGA</td>
+ <td>WVGA, FWVGA</td>
+</tr>
+<tr>
+ <th>Large Screen</th>
+ <td>n/a</td>
+ <td>VGA, WVGA, FWVGA</td>
+ <td>n/a</td>
+</tr>
+</table>
+
+</dd>
+
+
+<dt>attributes:</dt>
+
+<dd>
+<dl class="attr"><dt><a name="small"></a>{@code android:smallScreens}</dt>
+ <dd>Indicates whether the application supports smaller screen form-factors.
+ A small screen is defined as one with a smaller aspect ratio than
+ the "normal" (traditional HVGA) screen. An application that does
+ not support small screens <em>will not be available</em> for
+ small screen devices, because there is little the platform can do
+ to make such an application work on a smaller screen. Applications using
+ API Level 4 or higher default this to "true", others are "false".
+ </dd>
+
+ <dt><a name="normal"></a>{@code android:normalScreens}</dt>
+ <dd>Indicates whether an application supports the "normal" screen
+ form-factors. Traditionally this is an HVGA medium density
+ screen, but WQVGA low density and WVGA high density are also
+ considered to be normal. This attribute is "true" by default,
+ and applications currently should leave it that way.
+ </dd>
+
+ <dt><a name="large"></a>{@code android:largeScreens}</dt>
+ <dd>Indicates whether the application supports larger screen form-factors.
+ A large screen is defined as a screen that is significantly larger
+ than a "normal" phone screen, and thus may require some special care
+ on the application's part to make good use of it. An application that
+ does not support large screens will be placed as a "postage stamp" on
+ such a screen, so that it retains the dimensions it was originally
+ designed for. Applications using API Level 4 or higher default
+ to "true", others are "false".
+ </dd>
+
+ <dt><a name="any"></a>{@code android:anyDensity}</dt>
+ <dd>Indicates whether the application can accommodate any screen
+ density. Older applications (pre API Level 4) are assumed unable to
+ accomodate all densities and this is "false" by default. Applications using
+ API Level 4 or higher are assumed able to and this is "true" by default.
+ You can explicitly supply your abilities here.
+ </dd>
+
+
+</dl></dd>
+
+<!-- ##api level indication## -->
+<dt>introduced in:</dt>
+<dd>API Level 4</dd>
+
+<dt>see also:</dt>
+<dd>
+ <ul>
+ <li>{@link android.util.DisplayMetrics}</li>
+ </ul>
+</dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd
index b26881e..4578c63 100755
--- a/docs/html/guide/topics/manifest/uses-configuration-element.jd
+++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd
@@ -168,9 +168,14 @@
<dd>API Level 3</dd>
<dt>see also:</dt>
-<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html#config">configChanges</a></code>
+<dd>
+ <ul>
+ <li><code><a href="{@docRoot}guide/topics/manifest/activity-element.html#config">configChanges</a></code>
attribute of the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>
-element</dd>
+element</dd></li>
+ <li>{@link android.content.pm.ConfigurationInfo}</li>
+ </ul>
+</dd>
</dl>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
new file mode 100644
index 0000000..2626735
--- /dev/null
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -0,0 +1,52 @@
+page.title=<uses-feature>
+@jd:body
+
+<dl class="xml">
+
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">
+<uses-feature android:<a href="#glEsVersion">glEsVersion</a>=["true" | "false"] />
+</pre>
+</dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
+
+<dt>description:</dt>
+<dd>This element specifies specific features used by the application.
+Android provides some features that may not be equally supported by all
+Android devices. In a manner similar to the <code><a href="uses-sdk-element.html"><uses-sdk></a></code>
+element, this element allows an application to specify which potentially variable
+features it requires. In this way, the application
+will not be installed on devices that do not offer the required feature.</p>
+
+<p>For example, an application might specify that it requires a certain version of Open GL.
+If a device does not support that version of Open GL, then it will not allow installation of the application.</p>
+</dd>
+
+
+<dt>attributes:</dt>
+
+<dd>
+<dl class="attr"><dt><a name="glEsVersion"></a>{@code android:glEsVersion}</dt>
+ <dd>The GLES version needed by the application.
+ The higher 16 bits represent the major number and the lower 16 bits
+ represent the minor number. For example, for GL 1.2 referring to
+ 0x00000102, the actual value should be set as 0x00010002.
+ </dd>
+</dl>
+</dd>
+
+<!-- ##api level indication## -->
+<dt>introduced in:</dt>
+<dd>API Level 4</dd>
+
+<dt>see also:</dt>
+<dd>
+ <ul>
+ <li>{@link android.content.pm.ConfigurationInfo}</li>
+ </ul>
+</dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index b6e7374..adcdc28 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -11,50 +11,68 @@
<dt>description:</dt>
<dd>Lets you express an application's compatibility with one or more versions of the Android platform,
by means of an API Level integer. The API Level expressed by an application will be compared to the
-API Level of a given Android system, which may vary among different Android devices. To declare your
-application's minimum API Level compatibility, use the <a href="#min">minSdkVersion</a> attribute.
+API Level of a given Android system, which may vary among different Android devices.
</p>
<p>
-The default level is 1.
-</p>
-
-<p>
-For more information on the API level, see the
-<a href="{@docRoot}guide/publishing/versioning.html#minsdkversion">Specifying
-Minimum System API Version</a> section of
-<a href="{@docRoot}guide/publishing/versioning.html">Versioning Your
-Applications</a>.
-</p></dd>
-
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt><a name="min"></a>{@code android:minSdkVersion}</dt>
-<dd>An integer designating the minimum level of the Android API that's required
-for the application to run.
-
-<p>
-Despite its name, this attribute specifies the API Level, <em>not</em> the
+Despite its name, this element is used to specify the API Level, <em>not</em> the
version number of the SDK (software development kit). The API Level is always
a single integer; the SDK version may be split into major and minor components
(such as 1.5). You cannot derive the API Level from the SDK version number
(for example, it is not the same as the major version or the sum of the major
-and minor versions). To learn what the API Level is, check the notes that
-came with the SDK you're using.</p>
+and minor versions).</p>
-<p>Prior to installing an application, the Android system checks the value of this
-attribute and allows the installation only if the
-API Level is less than or equal to the API Level used by the system itself.</p>
+<p>For more information, read about
+<a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a> and
+<a href="{@docRoot}guide/publishing/versioning.html">Versioning Your Applications</a>.
+</p></dd>
-<p>If you do not declare this attribute, then a value of "1" is assumed, which
-indicates that your application is compatible with all versions of Android. If your
-application is <em>not</em> universally compatible (for instance if it uses APIs
-introduced in Android 1.5) and you have not declared the proper <code>minSdkVersion</code>,
-then when installed on a system with a lower API Level, the application
-will crash during runtime. For this reason, be certain to declare the appropriate API Level
-in the <code>minSdkVersion</code> attribute.</p>
-</dd>
+
+<dt>attributes:</dt>
+
+<dd>
+<dl class="attr">
+ <dt><a name="min"></a>{@code android:minSdkVersion}</dt>
+ <dd>An integer designating the minimum level of the Android API that's required
+ for the application to run.
+
+ <p>Prior to installing an application, the Android system checks the value of this
+ attribute and allows the installation only if it
+ is less than or equal to the API Level used by the system itself.</p>
+
+ <p>If you do not declare this attribute, then a value of "1" is assumed, which
+ indicates that your application is compatible with all versions of Android. If your
+ application is <em>not</em> universally compatible (for instance if it uses APIs
+ introduced in Android 1.5) and you have not declared the proper <code>minSdkVersion</code>,
+ then when installed on a system with a lower API Level, the application
+ will crash during runtime. For this reason, be certain to declare the appropriate API Level
+ in the <code>minSdkVersion</code> attribute.</p>
+ </dd>
+
+ <dt><a name="max"></a>{@code android:maxSdkVersion}</dt>
+ <dd>An integer designating the maximum level of the Android API that the application is
+ compatible with. 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.</p>
+
+ <p>Prior to installing an application, the Android system checks the value of this
+ attribute and allows the installation only it
+ is greater than or equal to the API Level used by the system itself.</p>
+
+ <p>Introduced in: API Level 4</p>
+ </dd>
+
+ <dt><a name="target"></a>{@code android:targetSdkVersion}</dt>
+ <dd>An integer designating the API Level that the application is targetting.
+
+ <p>With this attribute set, the application says that is is be able to run on
+ older versions (down to {@code minSdkVersion}), but was explicitly tested to work
+ with the version specified here.
+ Specifying this version allows the platform to disable compatibility
+ code that is not required or enable newer features that are not
+ available to older applications.</p>
+
+ <p>Introduced in: API Level 4</p>
+ </dd>
</dl></dd>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 076cd0c..2abb777 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -73,7 +73,7 @@
public Bitmap.Config inPreferredConfig;
/**
- * If dither is true, the decoder will atttempt to dither the decoded
+ * If dither is true, the decoder will attempt to dither the decoded
* image.
*/
public boolean inDither;
@@ -452,6 +452,10 @@
bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
}
+ return finishDecode(bm, outPadding, opts);
+ }
+
+ private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
if (bm == null || opts == null) {
return bm;
}
@@ -487,7 +491,7 @@
return bm;
}
-
+
/**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
@@ -507,7 +511,7 @@
/**
* Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
* return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
+ * this returns, so the descriptor can be used again as-is.
*
* @param fd The file descriptor containing the bitmap data to decode
* @param outPadding If not null, return the padding rect for the bitmap if
@@ -524,13 +528,15 @@
int mappedlength = MemoryFile.getMappedSize(fd);
MemoryFile file = new MemoryFile(fd, mappedlength, "r");
InputStream is = file.getInputStream();
- return decodeStream(is, outPadding, opts);
+ Bitmap bm = decodeStream(is, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
}
} catch (IOException ex) {
// invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
return null;
}
- return nativeDecodeFileDescriptor(fd, outPadding, opts);
+ Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
}
/**
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
index 3deca4a..4f16dc4 100644
--- a/graphics/java/android/graphics/DashPathEffect.java
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -23,13 +23,13 @@
* the even indices specifying the "on" intervals, and the odd indices
* specifying the "off" intervals. phase is an offset into the intervals
* array (mod the sum of all of the intervals). The intervals array
- * controlls the width of the dashes. The paint's strokeWidth controlls the
- * height of the dashes.
+ * controls the length of the dashes. The paint's strokeWidth controls the
+ * thickness of the dashes.
* Note: this patheffect only affects drawing with the paint's style is set
* to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
* style == FILL.
* @param intervals array of ON and OFF distances
- * @param phase offset before the first ON interval is drawn
+ * @param phase offset into the intervals array
*/
public DashPathEffect(float intervals[], float phase) {
if (intervals.length < 2) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index e40e84a..9bcab72 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -172,4 +172,14 @@
private static native int nativeGetStyle(int native_instance);
private static native int nativeCreateFromAsset(AssetManager mgr, String path);
private static native int nativeCreateFromFile(String path);
+
+ /**
+ * Set the global gamma coefficients for black and white text. This call is
+ * usually a no-op in shipping products, and only exists for testing during
+ * development.
+ *
+ * @param blackGamma gamma coefficient for black text
+ * @param whiteGamma gamma coefficient for white text
+ */
+ public static native void setGammaForText(float blackGamma, float whiteGamma);
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index eade73a..1755d4f 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -76,6 +76,7 @@
* @deprecated Use {@link #BitmapDrawable(Resources)} to ensure
* that the drawable has correctly set its target density.
*/
+ @Deprecated
public BitmapDrawable() {
mBitmapState = new BitmapState((Bitmap) null);
}
@@ -97,6 +98,7 @@
* @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
* that the drawable has correctly set its target density.
*/
+ @Deprecated
public BitmapDrawable(Bitmap bitmap) {
this(new BitmapState(bitmap));
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 193f399..21b5e39 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -654,7 +654,7 @@
* Create a drawable from an inputstream
*/
public static Drawable createFromStream(InputStream is, String srcName) {
- return createFromResourceStream(null, null, is, srcName);
+ return createFromResourceStream(null, null, is, srcName, null);
}
/**
@@ -663,6 +663,15 @@
*/
public static Drawable createFromResourceStream(Resources res, TypedValue value,
InputStream is, String srcName) {
+ return createFromResourceStream(res, value, is, srcName, null);
+ }
+
+ /**
+ * Create a drawable from an inputstream, using the given resources and
+ * value to determine density information.
+ */
+ public static Drawable createFromResourceStream(Resources res, TypedValue value,
+ InputStream is, String srcName, BitmapFactory.Options opts) {
if (is == null) {
return null;
@@ -683,7 +692,7 @@
// an application in compatibility mode, without scaling those down
// to the compatibility density only to have them scaled back up when
// drawn to the screen.
- BitmapFactory.Options opts = new BitmapFactory.Options();
+ if (opts == null) opts = new BitmapFactory.Options();
opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index d5c8a08..b175bb6 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -56,6 +56,7 @@
* @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
* to ensure that the drawable has correctly set its target density.
*/
+ @Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
}
@@ -78,6 +79,7 @@
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
* to ensure that the drawable has correctly set its target density.
*/
+ @Deprecated
public NinePatchDrawable(NinePatch patch) {
this(new NinePatchState(patch, null));
}
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index d22a4ba..a8274b1 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -105,6 +105,8 @@
mStateListState.setConstantSize(a.getBoolean(
com.android.internal.R.styleable.StateListDrawable_constantSize, false));
+ setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, false));
+
a.recycle();
int type;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 50d39b7..81848b9 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -47,14 +47,6 @@
mRS.nAllocationUploadToTexture(mID, baseMipLevel);
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nAllocationDestroy(mID);
- }
-
public void data(int[] d) {
mRS.nAllocationData(mID, d);
}
@@ -98,11 +90,6 @@
mID = id;
}
- public void destroy() {
- mRS.nAdapter1DDestroy(mID);
- mID = 0;
- }
-
public void setConstraint(Dimension dim, int value) {
mRS.nAdapter1DSetConstraint(mID, dim.mID, value);
}
@@ -139,11 +126,6 @@
mID = id;
}
- public void destroy() {
- mRS.nAdapter2DDestroy(mID);
- mID = 0;
- }
-
public void setConstraint(Dimension dim, int value) {
mRS.nAdapter2DSetConstraint(mID, dim.mID, value);
}
@@ -251,7 +233,7 @@
Allocation alloc = createTyped(rs, t);
t.destroy();
return alloc;
- }
+ }
*/
}
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index f760035..c25f16a 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -60,10 +60,24 @@
protected void finalize() throws Throwable
{
if (!mDestroyed) {
+ if(mID != 0) {
+ mRS.nObjDestroyOOB(mID);
+ }
+ mID = 0;
+ mDestroyed = true;
Log.v(RenderScript.LOG_TAG,
- "Element finalized without having released the RS reference.");
+ getClass() + " auto finalizing object without having released the RS reference.");
}
super.finalize();
}
+
+ public void destroy() {
+ if(mDestroyed) {
+ throw new IllegalStateException("Object already destroyed.");
+ }
+ mDestroyed = true;
+ mRS.nObjDestroy(mID);
+ }
+
}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 9155da8..aeec739 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -16,9 +16,6 @@
package android.renderscript;
-import android.util.Config;
-import android.util.Log;
-
import java.lang.reflect.Field;
/**
@@ -114,7 +111,8 @@
NX (15),
NY (16),
NZ (17),
- INDEX (18);
+ INDEX (18),
+ POINT_SIZE(19);
int mID;
DataKind(int id) {
@@ -141,11 +139,7 @@
if(mIsPredefined) {
throw new IllegalStateException("Attempting to destroy a predefined Element.");
}
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nElementDestroy(mID);
+ super.destroy();
}
public static Element createFromClass(RenderScript rs, Class c) {
@@ -193,9 +187,7 @@
void addEntry(Entry e) {
if(mEntries.length >= mEntryCount) {
Entry[] en = new Entry[mEntryCount + 8];
- for(int ct=0; ct < mEntries.length; ct++) {
- en[ct] = mEntries[ct];
- }
+ System.arraycopy(mEntries, 0, en, 0, mEntries.length);
mEntries = en;
}
mEntries[mEntryCount] = e;
@@ -228,6 +220,63 @@
return this;
}
+ public Builder addFloat(Element.DataKind dk) {
+ add(DataType.FLOAT, dk, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloat(Element.DataKind dk, String name) {
+ add(DataType.FLOAT, dk, false, 32, name);
+ return this;
+ }
+
+ public Builder addFloatXY() {
+ add(DataType.FLOAT, DataKind.X, false, 32, null);
+ add(DataType.FLOAT, DataKind.Y, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatXYZ() {
+ add(DataType.FLOAT, DataKind.X, false, 32, null);
+ add(DataType.FLOAT, DataKind.Y, false, 32, null);
+ add(DataType.FLOAT, DataKind.Z, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatST() {
+ add(DataType.FLOAT, DataKind.S, false, 32, null);
+ add(DataType.FLOAT, DataKind.T, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatPointSize() {
+ add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatRGB() {
+ add(DataType.FLOAT, DataKind.RED, false, 32, null);
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatRGBA() {
+ add(DataType.FLOAT, DataKind.RED, false, 32, null);
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
+ add(DataType.FLOAT, DataKind.ALPHA, false, 32, null);
+ return this;
+ }
+
+ public Builder addUNorm8RGBA() {
+ add(DataType.UNSIGNED, DataKind.RED, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.GREEN, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.BLUE, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, null);
+ return this;
+ }
+
static synchronized Element internalCreate(RenderScript rs, Builder b) {
rs.nElementBegin();
for (int ct=0; ct < b.mEntryCount; ct++) {
diff --git a/graphics/java/android/renderscript/Light.java b/graphics/java/android/renderscript/Light.java
index 8067f19..115ae03 100644
--- a/graphics/java/android/renderscript/Light.java
+++ b/graphics/java/android/renderscript/Light.java
@@ -29,11 +29,6 @@
mID = id;
}
- public void destroy() {
- mRS.nLightDestroy(mID);
- mID = 0;
- }
-
public void setColor(float r, float g, float b) {
mRS.nLightSetColor(mID, r, g, b);
}
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 09c4d9a..392d93d 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -45,14 +45,6 @@
mID = id;
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nProgramFragmentStoreDestroy(mID);
- }
-
public void bindTexture(Allocation va, int slot)
throws IllegalArgumentException {
if((slot < 0) || (slot >= MAX_SLOT)) {
@@ -76,6 +68,7 @@
RenderScript mRS;
Element mIn;
Element mOut;
+ boolean mPointSpriteEnable;
private class Slot {
Type mType;
@@ -93,6 +86,7 @@
mIn = in;
mOut = out;
mSlots = new Slot[MAX_SLOT];
+ mPointSpriteEnable = false;
for(int ct=0; ct < MAX_SLOT; ct++) {
mSlots[ct] = new Slot();
}
@@ -125,6 +119,9 @@
mSlots[slot].mEnv = env;
}
+ public void setPointSpriteTexCoordinateReplacement(boolean enable) {
+ mPointSpriteEnable = enable;
+ }
static synchronized ProgramFragment internalCreate(RenderScript rs, Builder b) {
int inID = 0;
@@ -135,21 +132,18 @@
if (b.mOut != null) {
outID = b.mOut.mID;
}
- rs.nProgramFragmentBegin(inID, outID);
+ rs.nProgramFragmentBegin(inID, outID, b.mPointSpriteEnable);
for(int ct=0; ct < MAX_SLOT; ct++) {
if(b.mSlots[ct].mTexEnable) {
Slot s = b.mSlots[ct];
+ int typeID = 0;
if(s.mType != null) {
- rs.nProgramFragmentSetType(ct, s.mType.mID);
+ typeID = s.mType.mID;
}
- rs.nProgramFragmentSetTexEnable(ct, true);
- if(s.mEnv != null) {
- rs.nProgramFragmentSetEnvMode(ct, s.mEnv.mID);
- }
+ rs.nProgramFragmentSetSlot(ct, true, s.mEnv.mID, typeID);
}
}
-
int id = rs.nProgramFragmentCreate();
return new ProgramFragment(id, rs);
}
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index f8b59bd..b7d987e 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -80,14 +80,6 @@
mID = id;
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nProgramFragmentStoreDestroy(mID);
- }
-
public static class Builder {
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 74c005f..2a11bfb 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -33,14 +33,6 @@
mID = id;
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nProgramVertexDestroy(mID);
- }
-
public void bindAllocation(MatrixAllocation va) {
mRS.nProgramVertexBindAllocation(mID, va.mAlloc.mID);
}
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index a4be171..a3f1ded 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -71,7 +71,6 @@
public void surfaceCreated(SurfaceHolder holder) {
Log.v(RenderScript.LOG_TAG, "surfaceCreated");
mSurfaceHolder = holder;
- //mGLThread.surfaceCreated();
}
/**
@@ -81,7 +80,6 @@
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return
Log.v(RenderScript.LOG_TAG, "surfaceDestroyed");
- //mGLThread.surfaceDestroyed();
}
/**
@@ -90,8 +88,6 @@
*/
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.v(RenderScript.LOG_TAG, "surfaceChanged");
-
- //mGLThread.onWindowResize(w, h);
}
/**
@@ -102,7 +98,6 @@
*/
public void onPause() {
Log.v(RenderScript.LOG_TAG, "onPause");
- //mGLThread.onPause();
}
/**
@@ -114,7 +109,6 @@
*/
public void onResume() {
Log.v(RenderScript.LOG_TAG, "onResume");
- //mGLThread.onResume();
}
/**
@@ -125,7 +119,6 @@
*/
public void queueEvent(Runnable r) {
Log.v(RenderScript.LOG_TAG, "queueEvent");
- //mGLThread.queueEvent(r);
}
/**
@@ -136,20 +129,16 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- //mGLThread.requestExitAndWait();
}
// ----------------------------------------------------------------------
- public RenderScript createRenderScript() {
- Log.v(RenderScript.LOG_TAG, "createRenderScript 1");
+ public RenderScript createRenderScript(boolean useDepth) {
Surface sur = null;
while ((sur == null) || (mSurfaceHolder == null)) {
sur = getHolder().getSurface();
}
- Log.v(RenderScript.LOG_TAG, "createRenderScript 2");
- RenderScript rs = new RenderScript(sur);
- Log.v(RenderScript.LOG_TAG, "createRenderScript 3 rs");
+ RenderScript rs = new RenderScript(sur, useDepth);
return rs;
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index b98a48ab..8489003 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -60,7 +60,7 @@
native int nDeviceCreate();
native void nDeviceDestroy(int dev);
- native int nContextCreate(int dev, Surface sur, int ver);
+ native int nContextCreate(int dev, Surface sur, int ver, boolean useDepth);
native void nContextDestroy(int con);
//void rsContextBindSampler (uint32_t slot, RsSampler sampler);
@@ -74,6 +74,8 @@
native void nContextAddDefineF(String name, float value);
native void nAssignName(int obj, byte[] name);
+ native void nObjDestroy(int id);
+ native void nObjDestroyOOB(int id);
native int nFileOpen(byte[] name);
native void nElementBegin();
@@ -81,12 +83,10 @@
native void nElementAdd(int kind, int type, int norm, int bits, String s);
native int nElementCreate();
native int nElementGetPredefined(int predef);
- native void nElementDestroy(int obj);
native void nTypeBegin(int elementID);
native void nTypeAdd(int dim, int val);
native int nTypeCreate();
- native void nTypeDestroy(int id);
native void nTypeFinalDestroy(Type t);
native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
@@ -97,7 +97,6 @@
native int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
native void nAllocationUploadToTexture(int alloc, int baseMioLevel);
- native void nAllocationDestroy(int alloc);
native void nAllocationData(int id, int[] d);
native void nAllocationData(int id, float[] d);
native void nAllocationSubData1D(int id, int off, int count, int[] d);
@@ -108,7 +107,6 @@
native void nAllocationRead(int id, float[] d);
native void nAllocationDataFromObject(int id, Type t, Object o);
- native void nTriangleMeshDestroy(int id);
native void nTriangleMeshBegin(int vertex, int index);
native void nTriangleMeshAddVertex_XY (float x, float y);
native void nTriangleMeshAddVertex_XYZ (float x, float y, float z);
@@ -118,7 +116,6 @@
native void nTriangleMeshAddTriangle(int i1, int i2, int i3);
native int nTriangleMeshCreate();
- native void nAdapter1DDestroy(int id);
native void nAdapter1DBindAllocation(int ad, int alloc);
native void nAdapter1DSetConstraint(int ad, int dim, int value);
native void nAdapter1DData(int ad, int[] d);
@@ -127,7 +124,6 @@
native void nAdapter1DSubData(int ad, int off, int count, float[] d);
native int nAdapter1DCreate();
- native void nAdapter2DDestroy(int id);
native void nAdapter2DBindAllocation(int ad, int alloc);
native void nAdapter2DSetConstraint(int ad, int dim, int value);
native void nAdapter2DData(int ad, int[] d);
@@ -136,13 +132,12 @@
native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, float[] d);
native int nAdapter2DCreate();
- native void nScriptDestroy(int script);
native void nScriptBindAllocation(int script, int alloc, int slot);
native void nScriptSetClearColor(int script, float r, float g, float b, float a);
native void nScriptSetClearDepth(int script, float depth);
native void nScriptSetClearStencil(int script, int stencil);
native void nScriptSetTimeZone(int script, byte[] timeZone);
- native void nScriptSetType(int type, String name, int slot);
+ native void nScriptSetType(int type, boolean writable, String name, int slot);
native void nScriptSetRoot(boolean isRoot);
native void nScriptCBegin();
@@ -151,7 +146,6 @@
native void nScriptCAddDefineI32(String name, int value);
native void nScriptCAddDefineF(String name, float value);
- native void nSamplerDestroy(int sampler);
native void nSamplerBegin();
native void nSamplerSet(int param, int value);
native int nSamplerCreate();
@@ -163,18 +157,13 @@
native void nProgramFragmentStoreBlendFunc(int src, int dst);
native void nProgramFragmentStoreDither(boolean enable);
native int nProgramFragmentStoreCreate();
- native void nProgramFragmentStoreDestroy(int pgm);
- native void nProgramFragmentBegin(int in, int out);
+ native void nProgramFragmentBegin(int in, int out, boolean pointSpriteEnable);
native void nProgramFragmentBindTexture(int vpf, int slot, int a);
native void nProgramFragmentBindSampler(int vpf, int slot, int s);
- native void nProgramFragmentSetType(int slot, int vt);
- native void nProgramFragmentSetEnvMode(int slot, int env);
- native void nProgramFragmentSetTexEnable(int slot, boolean enable);
+ native void nProgramFragmentSetSlot(int slot, boolean enable, int env, int vt);
native int nProgramFragmentCreate();
- native void nProgramFragmentDestroy(int pgm);
- native void nProgramVertexDestroy(int pv);
native void nProgramVertexBindAllocation(int pv, int mID);
native void nProgramVertexBegin(int inID, int outID);
native void nProgramVertexSetTextureMatrixEnable(boolean enable);
@@ -185,16 +174,13 @@
native void nLightSetIsMono(boolean isMono);
native void nLightSetIsLocal(boolean isLocal);
native int nLightCreate();
- native void nLightDestroy(int l);
native void nLightSetColor(int l, float r, float g, float b);
native void nLightSetPosition(int l, float x, float y, float z);
- native void nSimpleMeshDestroy(int id);
native int nSimpleMeshCreate(int batchID, int idxID, int[] vtxID, int prim);
native void nSimpleMeshBindVertex(int id, int alloc, int slot);
native void nSimpleMeshBindIndex(int id, int alloc);
- native void nAnimationDestroy(int id);
native void nAnimationBegin(int attribCount, int keyframeCount);
native void nAnimationAdd(float time, float[] attribs);
native int nAnimationCreate();
@@ -208,10 +194,10 @@
///////////////////////////////////////////////////////////////////////////////////
//
- public RenderScript(Surface sur) {
+ public RenderScript(Surface sur, boolean useDepth) {
mSurface = sur;
mDev = nDeviceCreate();
- mContext = nContextCreate(mDev, mSurface, 0);
+ mContext = nContextCreate(mDev, mSurface, 0, useDepth);
// TODO: This should be protected by a lock
if(!mElementsInitialized) {
@@ -220,6 +206,13 @@
}
}
+ public void destroy() {
+ nContextDestroy(mContext);
+ mContext = 0;
+
+ nDeviceDestroy(mDev);
+ mDev = 0;
+ }
//////////////////////////////////////////////////////////////////////////////////
// Triangle Mesh
@@ -229,11 +222,6 @@
super(RenderScript.this);
mID = id;
}
-
- public void destroy() {
- nTriangleMeshDestroy(mID);
- mID = 0;
- }
}
public void triangleMeshBegin(Element vertex, Element index) {
@@ -278,11 +266,6 @@
super(RenderScript.this);
mID = id;
}
-
- public void destroy() {
- //nLightDestroy(mID);
- mID = 0;
- }
}
public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
@@ -305,7 +288,11 @@
// Root state
public void contextBindRootScript(Script s) {
- nContextBindRootScript(s.mID);
+ int id = 0;
+ if(s != null) {
+ id = s.mID;
+ }
+ nContextBindRootScript(id);
}
//public void contextBindSampler(Sampler s, int slot) {
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
index dfeac81..5e0b110 100644
--- a/graphics/java/android/renderscript/Sampler.java
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -51,11 +51,6 @@
mID = id;
}
- public void destroy() {
- mRS.nSamplerDestroy(mID);
- mID = 0;
- }
-
public static class Builder {
RenderScript mRS;
Value mMin;
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 47479d8..a402471 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -24,20 +24,13 @@
boolean mIsRoot;
Type[] mTypes;
+ boolean[] mWritable;
Script(int id, RenderScript rs) {
super(rs);
mID = id;
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nScriptDestroy(mID);
- }
-
public void bindAllocation(Allocation va, int slot) {
mRS.nScriptBindAllocation(mID, va.mID, slot);
}
@@ -67,11 +60,13 @@
boolean mIsRoot = false;
Type[] mTypes;
String[] mNames;
+ boolean[] mWritable;
Builder(RenderScript rs) {
mRS = rs;
mTypes = new Type[MAX_SLOT];
mNames = new String[MAX_SLOT];
+ mWritable = new boolean[MAX_SLOT];
}
public void setType(Type t, int slot) {
@@ -84,11 +79,15 @@
mNames[slot] = name;
}
+ public void setType(boolean writable, int slot) {
+ mWritable[slot] = writable;
+ }
+
void transferCreate() {
mRS.nScriptSetRoot(mIsRoot);
for(int ct=0; ct < mTypes.length; ct++) {
if(mTypes[ct] != null) {
- mRS.nScriptSetType(mTypes[ct].mID, mNames[ct], ct);
+ mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
}
}
}
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index 484849b..d80551e 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -34,14 +34,6 @@
mID = id;
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nSimpleMeshDestroy(mID);
- }
-
public void bindVertexAllocation(Allocation a, int slot) {
mRS.nSimpleMeshBindVertex(mID, a.mID, slot);
}
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index afb0e60..b6b7adf 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -18,10 +18,6 @@
import java.lang.reflect.Field;
-import android.renderscript.Element;
-import android.util.Config;
-import android.util.Log;
-
/**
* @hide
*
@@ -48,14 +44,6 @@
super.finalize();
}
- public void destroy() {
- if(mDestroyed) {
- throw new IllegalStateException("Object already destroyed.");
- }
- mDestroyed = true;
- mRS.nTypeDestroy(mID);
- }
-
public static Type createFromClass(RenderScript rs, Class c, int size) {
Element e = Element.createFromClass(rs, c);
Builder b = new Builder(rs, e);
@@ -121,9 +109,7 @@
public void add(Dimension d, int value) {
if(mEntries.length >= mEntryCount) {
Entry[] en = new Entry[mEntryCount + 8];
- for(int ct=0; ct < mEntries.length; ct++) {
- en[ct] = mEntries[ct];
- }
+ System.arraycopy(mEntries, 0, en, 0, mEntries.length);
mEntries = en;
}
mEntries[mEntryCount] = new Entry();
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 5780e02..2393f74 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -74,10 +74,27 @@
jint len = _env->GetArrayLength(str);
jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
- rsAssignName((void *)obj, (const char *)cptr, len);
+ rsAssignName(con, (void *)obj, (const char *)cptr, len);
_env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
}
+static void
+nObjDestroy(JNIEnv *_env, jobject _this, jint obj)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nObjDestroy, con(%p) obj(%p)", con, (void *)obj);
+ rsObjDestroy(con, (void *)obj);
+}
+
+static void
+nObjDestroyOOB(JNIEnv *_env, jobject _this, jint obj)
+{
+ // This function only differs from nObjDestroy in that it calls the
+ // special Out Of Band version of ObjDestroy which is thread safe.
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nObjDestroyOOB, con(%p) obj(%p)", con, (void *)obj);
+ rsObjDestroyOOB(con, (void *)obj);
+}
static jint
nFileOpen(JNIEnv *_env, jobject _this, jbyteArray str)
@@ -87,7 +104,7 @@
jint len = _env->GetArrayLength(str);
jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
- jint ret = (jint)rsFileOpen((const char *)cptr, len);
+ jint ret = (jint)rsFileOpen(con, (const char *)cptr, len);
_env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
return ret;
}
@@ -109,7 +126,7 @@
}
static jint
-nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver)
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver, jboolean useDepth)
{
LOG_API("nContextCreate");
@@ -125,7 +142,7 @@
if (window == NULL)
goto not_valid_surface;
- return (jint)rsContextCreate((RsDevice)dev, window, ver);
+ return (jint)rsContextCreate((RsDevice)dev, window, ver, useDepth);
}
static void
@@ -141,7 +158,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nElementBegin, con(%p)", con);
- rsElementBegin();
+ rsElementBegin(con);
}
static void
@@ -149,7 +166,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nElementAddPredefined, con(%p), predef(%i)", con, predef);
- rsElementAddPredefined((RsElementPredefined)predef);
+ rsElementAddPredefined(con, (RsElementPredefined)predef);
}
static void
@@ -161,7 +178,7 @@
n = _env->GetStringUTFChars(name, NULL);
}
LOG_API("nElementAdd, con(%p), kind(%i), type(%i), norm(%i), bits(%i)", con, kind, type, norm, bits);
- rsElementAdd((RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits, n);
+ rsElementAdd(con, (RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits, n);
if (n) {
_env->ReleaseStringUTFChars(name, n);
}
@@ -172,7 +189,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nElementCreate, con(%p)", con);
- return (jint)rsElementCreate();
+ return (jint)rsElementCreate(con);
}
static jint
@@ -180,15 +197,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nElementGetPredefined, con(%p) predef(%i)", con, predef);
- return (jint)rsElementGetPredefined((RsElementPredefined)predef);
-}
-
-static void
-nElementDestroy(JNIEnv *_env, jobject _this, jint e)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nElementDestroy, con(%p) e(%p)", con, (RsElement)e);
- rsElementDestroy((RsElement)e);
+ return (jint)rsElementGetPredefined(con, (RsElementPredefined)predef);
}
// -----------------------------------
@@ -198,7 +207,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTypeBegin, con(%p) e(%p)", con, (RsElement)eID);
- rsTypeBegin((RsElement)eID);
+ rsTypeBegin(con, (RsElement)eID);
}
static void
@@ -206,7 +215,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTypeAdd, con(%p) dim(%i), val(%i)", con, dim, val);
- rsTypeAdd((RsDimension)dim, val);
+ rsTypeAdd(con, (RsDimension)dim, val);
}
static jint
@@ -214,15 +223,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTypeCreate, con(%p)", con);
- return (jint)rsTypeCreate();
-}
-
-static void
-nTypeDestroy(JNIEnv *_env, jobject _this, jint eID)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nTypeDestroy, con(%p), t(%p)", con, (RsType)eID);
- rsTypeDestroy((RsType)eID);
+ return (jint)rsTypeCreate(con);
}
static void * SF_LoadInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
@@ -317,7 +318,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAllocationCreateTyped, con(%p), e(%p)", con, (RsElement)e);
- return (jint) rsAllocationCreateTyped((RsElement)e);
+ return (jint) rsAllocationCreateTyped(con, (RsElement)e);
}
static jint
@@ -325,7 +326,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAllocationCreatePredefSized, con(%p), predef(%i), count(%i)", con, predef, count);
- return (jint) rsAllocationCreatePredefSized((RsElementPredefined)predef, count);
+ return (jint) rsAllocationCreatePredefSized(con, (RsElementPredefined)predef, count);
}
static jint
@@ -333,7 +334,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAllocationCreateSized, con(%p), e(%p), count(%i)", con, (RsElement)e, count);
- return (jint) rsAllocationCreateSized((RsElement)e, count);
+ return (jint) rsAllocationCreateSized(con, (RsElement)e, count);
}
static void
@@ -341,7 +342,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAllocationUploadToTexture, con(%p), a(%p), mip(%i)", con, (RsAllocation)a, mip);
- rsAllocationUploadToTexture((RsAllocation)a, mip);
+ rsAllocationUploadToTexture(con, (RsAllocation)a, mip);
}
static RsElementPredefined SkBitmapToPredefined(SkBitmap::Config cfg)
@@ -380,7 +381,7 @@
const int w = bitmap.width();
const int h = bitmap.height();
const void* ptr = bitmap.getPixels();
- jint id = (jint)rsAllocationCreateFromBitmap(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ jint id = (jint)rsAllocationCreateFromBitmap(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
bitmap.unlockPixels();
return id;
}
@@ -403,7 +404,7 @@
const int w = bitmap.width();
const int h = bitmap.height();
const void* ptr = bitmap.getPixels();
- jint id = (jint)rsAllocationCreateFromBitmapBoxed(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ jint id = (jint)rsAllocationCreateFromBitmapBoxed(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
bitmap.unlockPixels();
return id;
}
@@ -412,21 +413,13 @@
static void
-nAllocationDestroy(JNIEnv *_env, jobject _this, jint a)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nAllocationDestroy, con(%p), a(%p)", con, (RsAllocation)a);
- rsAllocationDestroy((RsAllocation)a);
-}
-
-static void
nAllocationData_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAllocationData((RsAllocation)alloc, ptr);
+ rsAllocationData(con, (RsAllocation)alloc, ptr);
_env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
}
@@ -437,7 +430,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAllocationData((RsAllocation)alloc, ptr);
+ rsAllocationData(con, (RsAllocation)alloc, ptr);
_env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
}
@@ -448,7 +441,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocation1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAllocation1DSubData((RsAllocation)alloc, offset, count, ptr);
+ rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr);
_env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
}
@@ -459,7 +452,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocation1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAllocation1DSubData((RsAllocation)alloc, offset, count, ptr);
+ rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr);
_env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
}
@@ -470,7 +463,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAllocation2DSubData((RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ rsAllocation2DSubData(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr);
_env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
}
@@ -481,7 +474,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAllocation2DSubData((RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ rsAllocation2DSubData(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr);
_env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
}
@@ -492,7 +485,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAllocationRead((RsAllocation)alloc, ptr);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr);
_env->ReleaseIntArrayElements(data, ptr, JNI_COMMIT);
}
@@ -503,7 +496,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationRead_f, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAllocationRead((RsAllocation)alloc, ptr);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr);
_env->ReleaseFloatArrayElements(data, ptr, JNI_COMMIT);
}
@@ -523,7 +516,7 @@
const TypeFieldCache *tfc = &tc->fields[ct];
buf = tfc->ptr(_env, _o, tfc->field, buf);
}
- rsAllocationData((RsAllocation)alloc, bufAlloc);
+ rsAllocationData(con, (RsAllocation)alloc, bufAlloc);
const uint32_t * tmp = (const uint32_t *)bufAlloc;
free(bufAlloc);
}
@@ -531,19 +524,11 @@
// -----------------------------------
static void
-nTriangleMeshDestroy(JNIEnv *_env, jobject _this, jint tm)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nTriangleMeshDestroy, con(%p), tm(%p)", con, (RsAllocation)tm);
- rsTriangleMeshDestroy((RsTriangleMesh)tm);
-}
-
-static void
nTriangleMeshBegin(JNIEnv *_env, jobject _this, jint v, jint i)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshBegin, con(%p), vertex(%p), index(%p)", con, (RsElement)v, (RsElement)i);
- rsTriangleMeshBegin((RsElement)v, (RsElement)i);
+ rsTriangleMeshBegin(con, (RsElement)v, (RsElement)i);
}
static void
@@ -552,7 +537,7 @@
float v[] = {x, y};
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddVertex_XY, con(%p), x(%f), y(%f)", con, x, y);
- rsTriangleMeshAddVertex(v);
+ rsTriangleMeshAddVertex(con, v);
}
static void
@@ -561,7 +546,7 @@
float v[] = {x, y, z};
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddVertex_XYZ, con(%p), x(%f), y(%f), z(%f)", con, x, y, z);
- rsTriangleMeshAddVertex(v);
+ rsTriangleMeshAddVertex(con, v);
}
static void
@@ -570,7 +555,7 @@
float v[] = {s, t, x, y};
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddVertex_XY_ST, con(%p), x(%f), y(%f), s(%f), t(%f)", con, x, y, s, t);
- rsTriangleMeshAddVertex(v);
+ rsTriangleMeshAddVertex(con, v);
}
static void
@@ -579,7 +564,7 @@
float v[] = {s, t, x, y, z};
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddVertex_XYZ_ST, con(%p), x(%f), y(%f), z(%f), s(%f), t(%f)", con, x, y, z, s, t);
- rsTriangleMeshAddVertex(v);
+ rsTriangleMeshAddVertex(con, v);
}
static void
@@ -588,7 +573,7 @@
float v[] = {nx, ny, nz, s, t, x, y, z};
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddVertex_XYZ_ST, con(%p), x(%f), y(%f), z(%f), s(%f), t(%f)", con, x, y, z, s, t);
- rsTriangleMeshAddVertex(v);
+ rsTriangleMeshAddVertex(con, v);
}
static void
@@ -596,7 +581,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshAddTriangle, con(%p), i1(%i), i2(%i), i3(%i)", con, i1, i2, i3);
- rsTriangleMeshAddTriangle(i1, i2, i3);
+ rsTriangleMeshAddTriangle(con, i1, i2, i3);
}
static jint
@@ -604,25 +589,17 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nTriangleMeshCreate, con(%p)", con);
- return (jint) rsTriangleMeshCreate();
+ return (jint) rsTriangleMeshCreate(con);
}
// -----------------------------------
static void
-nAdapter1DDestroy(JNIEnv *_env, jobject _this, jint adapter)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nAdapter1DDestroy, con(%p), adapter(%p)", con, (RsAdapter1D)adapter);
- rsAdapter1DDestroy((RsAdapter1D)adapter);
-}
-
-static void
nAdapter1DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter1DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter1D)adapter, (RsAllocation)alloc);
- rsAdapter1DBindAllocation((RsAdapter1D)adapter, (RsAllocation)alloc);
+ rsAdapter1DBindAllocation(con, (RsAdapter1D)adapter, (RsAllocation)alloc);
}
static void
@@ -630,7 +607,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter1DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter1D)adapter, dim, value);
- rsAdapter1DSetConstraint((RsAdapter1D)adapter, (RsDimension)dim, value);
+ rsAdapter1DSetConstraint(con, (RsAdapter1D)adapter, (RsDimension)dim, value);
}
static void
@@ -640,7 +617,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter1DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAdapter1DData((RsAdapter1D)adapter, ptr);
+ rsAdapter1DData(con, (RsAdapter1D)adapter, ptr);
_env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -651,7 +628,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAdapter1DSubData((RsAdapter1D)adapter, offset, count, ptr);
+ rsAdapter1DSubData(con, (RsAdapter1D)adapter, offset, count, ptr);
_env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -662,7 +639,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter1DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAdapter1DData((RsAdapter1D)adapter, ptr);
+ rsAdapter1DData(con, (RsAdapter1D)adapter, ptr);
_env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -673,7 +650,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAdapter1DSubData((RsAdapter1D)adapter, offset, count, ptr);
+ rsAdapter1DSubData(con, (RsAdapter1D)adapter, offset, count, ptr);
_env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -682,25 +659,17 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter1DCreate, con(%p)", con);
- return (jint)rsAdapter1DCreate();
+ return (jint)rsAdapter1DCreate(con);
}
// -----------------------------------
static void
-nAdapter2DDestroy(JNIEnv *_env, jobject _this, jint adapter)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nAdapter2DDestroy, con(%p), adapter(%p)", con, (RsAdapter2D)adapter);
- rsAdapter2DDestroy((RsAdapter2D)adapter);
-}
-
-static void
nAdapter2DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter2DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter2D)adapter, (RsAllocation)alloc);
- rsAdapter2DBindAllocation((RsAdapter2D)adapter, (RsAllocation)alloc);
+ rsAdapter2DBindAllocation(con, (RsAdapter2D)adapter, (RsAllocation)alloc);
}
static void
@@ -708,7 +677,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter2DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter2D)adapter, dim, value);
- rsAdapter2DSetConstraint((RsAdapter2D)adapter, (RsDimension)dim, value);
+ rsAdapter2DSetConstraint(con, (RsAdapter2D)adapter, (RsDimension)dim, value);
}
static void
@@ -718,7 +687,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter2DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAdapter2DData((RsAdapter2D)adapter, ptr);
+ rsAdapter2DData(con, (RsAdapter2D)adapter, ptr);
_env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -729,7 +698,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAdapter2DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAdapter2DData((RsAdapter2D)adapter, ptr);
+ rsAdapter2DData(con, (RsAdapter2D)adapter, ptr);
_env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -741,7 +710,7 @@
LOG_API("nAdapter2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)",
con, (RsAdapter2D)adapter, xoff, yoff, w, h, len);
jint *ptr = _env->GetIntArrayElements(data, NULL);
- rsAdapter2DSubData((RsAdapter2D)adapter, xoff, yoff, w, h, ptr);
+ rsAdapter2DSubData(con, (RsAdapter2D)adapter, xoff, yoff, w, h, ptr);
_env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -753,7 +722,7 @@
LOG_API("nAdapter2DSubData_f, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)",
con, (RsAdapter2D)adapter, xoff, yoff, w, h, len);
jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
- rsAdapter2DSubData((RsAdapter1D)adapter, xoff, yoff, w, h, ptr);
+ rsAdapter2DSubData(con, (RsAdapter1D)adapter, xoff, yoff, w, h, ptr);
_env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
}
@@ -762,25 +731,17 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAdapter2DCreate, con(%p)", con);
- return (jint)rsAdapter2DCreate();
+ return (jint)rsAdapter2DCreate(con);
}
// -----------------------------------
static void
-nScriptDestroy(JNIEnv *_env, jobject _this, jint script)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptDestroy, con(%p), script(%p)", con, (RsScript)script);
- rsScriptDestroy((RsScript)script);
-}
-
-static void
nScriptBindAllocation(JNIEnv *_env, jobject _this, jint script, jint alloc, jint slot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", con, (RsScript)script, (RsAllocation)alloc, slot);
- rsScriptBindAllocation((RsScript)script, (RsAllocation)alloc, slot);
+ rsScriptBindAllocation(con, (RsScript)script, (RsAllocation)alloc, slot);
}
static void
@@ -788,7 +749,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptSetClearColor, con(%p), s(%p), r(%f), g(%f), b(%f), a(%f)", con, script, r, g, b, a);
- rsScriptSetClearColor((RsScript)script, r, g, b, a);
+ rsScriptSetClearColor(con, (RsScript)script, r, g, b, a);
}
static void
@@ -796,7 +757,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptCSetClearDepth, con(%p), s(%p), depth(%f)", con, script, d);
- rsScriptSetClearDepth((RsScript)script, d);
+ rsScriptSetClearDepth(con, (RsScript)script, d);
}
static void
@@ -804,7 +765,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptCSetClearStencil, con(%p), s(%p), stencil(%i)", con, script, stencil);
- rsScriptSetClearStencil((RsScript)script, stencil);
+ rsScriptSetClearStencil(con, (RsScript)script, stencil);
}
static void
@@ -817,7 +778,7 @@
jbyte* timeZone_ptr;
timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
- rsScriptSetTimeZone((RsScript)script, (const char *)timeZone_ptr, length);
+ rsScriptSetTimeZone(con, (RsScript)script, (const char *)timeZone_ptr, length);
if (timeZone_ptr) {
_env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
@@ -825,15 +786,15 @@
}
static void
-nScriptSetType(JNIEnv *_env, jobject _this, jint type, jstring _str, jint slot)
+nScriptSetType(JNIEnv *_env, jobject _this, jint type, jboolean writable, jstring _str, jint slot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nScriptCAddType, con(%p), type(%p), slot(%i)", con, (RsType)type, slot);
+ LOG_API("nScriptCAddType, con(%p), type(%p), writable(%i), slot(%i)", con, (RsType)type, writable, slot);
const char* n = NULL;
if (_str) {
n = _env->GetStringUTFChars(_str, NULL);
}
- rsScriptSetType((RsType)type, slot, n);
+ rsScriptSetType(con, (RsType)type, slot, writable, n);
if (n) {
_env->ReleaseStringUTFChars(_str, n);
}
@@ -844,7 +805,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot);
- rsScriptSetRoot(isRoot);
+ rsScriptSetRoot(con, isRoot);
}
// -----------------------------------
@@ -854,7 +815,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptCBegin, con(%p)", con);
- rsScriptCBegin();
+ rsScriptCBegin(con);
}
static void
@@ -892,7 +853,7 @@
_env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
script_ptr = script_base + offset;
- rsScriptCSetText((const char *)script_ptr, length);
+ rsScriptCSetText(con, (const char *)script_ptr, length);
exit:
if (script_base) {
@@ -906,7 +867,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nScriptCCreate, con(%p)", con);
- return (jint)rsScriptCCreate();
+ return (jint)rsScriptCCreate(con);
}
static void
@@ -915,7 +876,7 @@
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
const char* n = _env->GetStringUTFChars(name, NULL);
LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
- rsScriptCSetDefineI32(n, value);
+ rsScriptCSetDefineI32(con, n, value);
_env->ReleaseStringUTFChars(name, n);
}
@@ -925,7 +886,7 @@
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
const char* n = _env->GetStringUTFChars(name, NULL);
LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
- rsScriptCSetDefineF(n, value);
+ rsScriptCSetDefineF(con, n, value);
_env->ReleaseStringUTFChars(name, n);
}
@@ -936,7 +897,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
- rsProgramFragmentStoreBegin((RsElement)in, (RsElement)out);
+ rsProgramFragmentStoreBegin(con, (RsElement)in, (RsElement)out);
}
static void
@@ -944,7 +905,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreDepthFunc, con(%p), func(%i)", con, func);
- rsProgramFragmentStoreDepthFunc((RsDepthFunc)func);
+ rsProgramFragmentStoreDepthFunc(con, (RsDepthFunc)func);
}
static void
@@ -952,7 +913,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreDepthMask, con(%p), enable(%i)", con, enable);
- rsProgramFragmentStoreDepthMask(enable);
+ rsProgramFragmentStoreDepthMask(con, enable);
}
static void
@@ -960,7 +921,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a);
- rsProgramFragmentStoreColorMask(r, g, b, a);
+ rsProgramFragmentStoreColorMask(con, r, g, b, a);
}
static void
@@ -968,7 +929,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst);
- rsProgramFragmentStoreBlendFunc((RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
+ rsProgramFragmentStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
}
static void
@@ -976,7 +937,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreDither, con(%p), enable(%i)", con, enable);
- rsProgramFragmentStoreDither(enable);
+ rsProgramFragmentStoreDither(con, enable);
}
static jint
@@ -985,25 +946,17 @@
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentStoreCreate, con(%p)", con);
- return (jint)rsProgramFragmentStoreCreate();
-}
-
-static void
-nProgramFragmentStoreDestroy(JNIEnv *_env, jobject _this, jint pgm)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentStoreDestroy, con(%p), pgm(%i)", con, pgm);
- rsProgramFragmentStoreDestroy((RsProgramFragmentStore)pgm);
+ return (jint)rsProgramFragmentStoreCreate(con);
}
// ---------------------------------------------------------------------------
static void
-nProgramFragmentBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+nProgramFragmentBegin(JNIEnv *_env, jobject _this, jint in, jint out, jboolean pointSpriteEnable)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
- rsProgramFragmentBegin((RsElement)in, (RsElement)out);
+ LOG_API("nProgramFragmentBegin, con(%p), in(%p), out(%p) PointSprite(%i)", con, (RsElement)in, (RsElement)out, pointSpriteEnable);
+ rsProgramFragmentBegin(con, (RsElement)in, (RsElement)out, pointSpriteEnable);
}
static void
@@ -1011,7 +964,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentBindTexture, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
- rsProgramFragmentBindTexture((RsProgramFragment)vpf, slot, (RsAllocation)a);
+ rsProgramFragmentBindTexture(con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
}
static void
@@ -1019,31 +972,15 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentBindSampler, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsSampler)a);
- rsProgramFragmentBindSampler((RsProgramFragment)vpf, slot, (RsSampler)a);
+ rsProgramFragmentBindSampler(con, (RsProgramFragment)vpf, slot, (RsSampler)a);
}
static void
-nProgramFragmentSetType(JNIEnv *_env, jobject _this, jint slot, jint vt)
+nProgramFragmentSetSlot(JNIEnv *_env, jobject _this, jint slot, jboolean enable, jint env, jint vt)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentSetType, con(%p), slot(%i), vt(%p)", con, slot, (RsType)vt);
- rsProgramFragmentSetType(slot, (RsType)vt);
-}
-
-static void
-nProgramFragmentSetEnvMode(JNIEnv *_env, jobject _this, jint slot, jint env)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentSetEnvMode, con(%p), slot(%i), vt(%i)", con, slot, env);
- rsProgramFragmentSetEnvMode(slot, (RsTexEnvMode)env);
-}
-
-static void
-nProgramFragmentSetTexEnable(JNIEnv *_env, jobject _this, jint slot, jboolean enable)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentSetTexEnable, con(%p), slot(%i), enable(%i)", con, slot, enable);
- rsProgramFragmentSetTexEnable(slot, enable);
+ LOG_API("nProgramFragmentSetType, con(%p), slot(%i), enable(%i), env(%i), vt(%p)", con, slot, enable, env, (RsType)vt);
+ rsProgramFragmentSetSlot(con, slot, enable, (RsTexEnvMode)env, (RsType)vt);
}
static jint
@@ -1051,15 +988,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramFragmentCreate, con(%p)", con);
- return (jint)rsProgramFragmentCreate();
-}
-
-static void
-nProgramFragmentDestroy(JNIEnv *_env, jobject _this, jint pgm)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentDestroy, con(%p), pgm(%i)", con, pgm);
- rsProgramFragmentDestroy((RsProgramFragment)pgm);
+ return (jint)rsProgramFragmentCreate(con);
}
// ---------------------------------------------------------------------------
@@ -1069,7 +998,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramVertexBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
- rsProgramVertexBegin((RsElement)in, (RsElement)out);
+ rsProgramVertexBegin(con, (RsElement)in, (RsElement)out);
}
static void
@@ -1077,7 +1006,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramVertexBindAllocation, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramVertex)vpv, slot, (RsAllocation)a);
- rsProgramVertexBindAllocation((RsProgramFragment)vpv, (RsAllocation)a);
+ rsProgramVertexBindAllocation(con, (RsProgramFragment)vpv, (RsAllocation)a);
}
static void
@@ -1085,7 +1014,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramVertexSetTextureMatrixEnable, con(%p), enable(%i)", con, enable);
- rsProgramVertexSetTextureMatrixEnable(enable);
+ rsProgramVertexSetTextureMatrixEnable(con, enable);
}
static void
@@ -1093,7 +1022,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramVertexAddLight, con(%p), light(%p)", con, (RsLight)light);
- rsProgramVertexAddLight((RsLight)light);
+ rsProgramVertexAddLight(con, (RsLight)light);
}
static jint
@@ -1101,18 +1030,9 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nProgramVertexCreate, con(%p)", con);
- return (jint)rsProgramVertexCreate();
+ return (jint)rsProgramVertexCreate(con);
}
-static void
-nProgramVertexDestroy(JNIEnv *_env, jobject _this, jint pgm)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramFragmentDestroy, con(%p), pgm(%i)", con, pgm);
- rsProgramFragmentDestroy((RsProgramFragment)pgm);
-}
-
-
// ---------------------------------------------------------------------------
@@ -1122,7 +1042,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nContextBindRootScript, con(%p), script(%p)", con, (RsScript)script);
- rsContextBindRootScript((RsScript)script);
+ rsContextBindRootScript(con, (RsScript)script);
}
static void
@@ -1130,7 +1050,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nContextBindProgramFragmentStore, con(%p), pfs(%p)", con, (RsProgramFragmentStore)pfs);
- rsContextBindProgramFragmentStore((RsProgramFragmentStore)pfs);
+ rsContextBindProgramFragmentStore(con, (RsProgramFragmentStore)pfs);
}
static void
@@ -1138,7 +1058,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nContextBindProgramFragment, con(%p), pf(%p)", con, (RsProgramFragment)pf);
- rsContextBindProgramFragment((RsProgramFragment)pf);
+ rsContextBindProgramFragment(con, (RsProgramFragment)pf);
}
static void
@@ -1146,7 +1066,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nContextBindProgramVertex, con(%p), pf(%p)", con, (RsProgramVertex)pf);
- rsContextBindProgramVertex((RsProgramVertex)pf);
+ rsContextBindProgramVertex(con, (RsProgramVertex)pf);
}
static void
@@ -1155,7 +1075,7 @@
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
const char* n = _env->GetStringUTFChars(name, NULL);
LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
- rsContextSetDefineI32(n, value);
+ rsContextSetDefineI32(con, n, value);
_env->ReleaseStringUTFChars(name, n);
}
@@ -1165,7 +1085,7 @@
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
const char* n = _env->GetStringUTFChars(name, NULL);
LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
- rsContextSetDefineF(n, value);
+ rsContextSetDefineF(con, n, value);
_env->ReleaseStringUTFChars(name, n);
}
@@ -1173,19 +1093,11 @@
// ---------------------------------------------------------------------------
static void
-nSamplerDestroy(JNIEnv *_env, jobject _this, jint s)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nSamplerDestroy, con(%p), sampler(%p)", con, (RsSampler)s);
- rsSamplerDestroy((RsSampler)s);
-}
-
-static void
nSamplerBegin(JNIEnv *_env, jobject _this)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nSamplerBegin, con(%p)", con);
- rsSamplerBegin();
+ rsSamplerBegin(con);
}
static void
@@ -1193,7 +1105,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nSamplerSet, con(%p), param(%i), value(%i)", con, p, v);
- rsSamplerSet((RsSamplerParam)p, (RsSamplerValue)v);
+ rsSamplerSet(con, (RsSamplerParam)p, (RsSamplerValue)v);
}
static jint
@@ -1201,7 +1113,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nSamplerCreate, con(%p)", con);
- return (jint)rsSamplerCreate();
+ return (jint)rsSamplerCreate(con);
}
// ---------------------------------------------------------------------------
@@ -1211,7 +1123,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightBegin, con(%p)", con);
- rsLightBegin();
+ rsLightBegin(con);
}
static void
@@ -1219,7 +1131,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightSetIsMono, con(%p), isMono(%i)", con, isMono);
- rsLightSetMonochromatic(isMono);
+ rsLightSetMonochromatic(con, isMono);
}
static void
@@ -1227,7 +1139,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightSetIsLocal, con(%p), isLocal(%i)", con, isLocal);
- rsLightSetLocal(isLocal);
+ rsLightSetLocal(con, isLocal);
}
static jint
@@ -1235,15 +1147,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightCreate, con(%p)", con);
- return (jint)rsLightCreate();
-}
-
-static void
-nLightDestroy(JNIEnv *_env, jobject _this, jint light)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nLightDestroy, con(%p), light(%p)", con, (RsLight)light);
- rsLightDestroy((RsLight)light);
+ return (jint)rsLightCreate(con);
}
static void
@@ -1251,7 +1155,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightSetColor, con(%p), light(%p), r(%f), g(%f), b(%f)", con, (RsLight)light, r, g, b);
- rsLightSetColor((RsLight)light, r, g, b);
+ rsLightSetColor(con, (RsLight)light, r, g, b);
}
static void
@@ -1259,19 +1163,11 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nLightSetPosition, con(%p), light(%p), x(%f), y(%f), z(%f)", con, (RsLight)light, x, y, z);
- rsLightSetPosition((RsLight)light, x, y, z);
+ rsLightSetPosition(con, (RsLight)light, x, y, z);
}
// ---------------------------------------------------------------------------
-static void
-nSimpleMeshDestroy(JNIEnv *_env, jobject _this, jint s)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nSimpleMeshDestroy, con(%p), SimpleMesh(%p)", con, (RsSimpleMesh)s);
- rsSimpleMeshDestroy((RsSimpleMesh)s);
-}
-
static jint
nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID)
{
@@ -1280,7 +1176,7 @@
LOG_API("nSimpleMeshCreate, con(%p), batchID(%i), indexID(%i), vtxIDs.len(%i), primID(%i)",
con, batchID, indexID, len, primID);
jint *ptr = _env->GetIntArrayElements(vtxIDs, NULL);
- int id = (int)rsSimpleMeshCreate((void *)batchID, (void *)indexID, (void **)ptr, len, primID);
+ int id = (int)rsSimpleMeshCreate(con, (void *)batchID, (void *)indexID, (void **)ptr, len, primID);
_env->ReleaseIntArrayElements(vtxIDs, ptr, 0/*JNI_ABORT*/);
return id;
}
@@ -1290,7 +1186,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nSimpleMeshBindVertex, con(%p), SimpleMesh(%p), Alloc(%p), slot(%i)", con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
- rsSimpleMeshBindVertex((RsSimpleMesh)s, (RsAllocation)alloc, slot);
+ rsSimpleMeshBindVertex(con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
}
static void
@@ -1298,7 +1194,7 @@
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc);
- rsSimpleMeshBindIndex((RsSimpleMesh)s, (RsAllocation)alloc);
+ rsSimpleMeshBindIndex(con, (RsSimpleMesh)s, (RsAllocation)alloc);
}
// ---------------------------------------------------------------------------
@@ -1310,9 +1206,11 @@
{"_nInit", "()V", (void*)_nInit },
{"nDeviceCreate", "()I", (void*)nDeviceCreate },
{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
-{"nContextCreate", "(ILandroid/view/Surface;I)I", (void*)nContextCreate },
+{"nContextCreate", "(ILandroid/view/Surface;IZ)I", (void*)nContextCreate },
{"nContextDestroy", "(I)V", (void*)nContextDestroy },
{"nAssignName", "(I[B)V", (void*)nAssignName },
+{"nObjDestroy", "(I)V", (void*)nObjDestroy },
+{"nObjDestroyOOB", "(I)V", (void*)nObjDestroyOOB },
{"nFileOpen", "([B)I", (void*)nFileOpen },
@@ -1321,12 +1219,10 @@
{"nElementAdd", "(IIIILjava/lang/String;)V", (void*)nElementAdd },
{"nElementCreate", "()I", (void*)nElementCreate },
{"nElementGetPredefined", "(I)I", (void*)nElementGetPredefined },
-{"nElementDestroy", "(I)V", (void*)nElementDestroy },
{"nTypeBegin", "(I)V", (void*)nTypeBegin },
{"nTypeAdd", "(II)V", (void*)nTypeAdd },
{"nTypeCreate", "()I", (void*)nTypeCreate },
-{"nTypeDestroy", "(I)V", (void*)nTypeDestroy },
{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy },
{"nTypeSetupFields", "(Landroid/renderscript/Type;[I[I[Ljava/lang/reflect/Field;)V", (void*)nTypeSetupFields },
@@ -1336,7 +1232,6 @@
{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed },
{"nAllocationUploadToTexture", "(II)V", (void*)nAllocationUploadToTexture },
-{"nAllocationDestroy", "(I)V", (void*)nAllocationDestroy },
{"nAllocationData", "(I[I)V", (void*)nAllocationData_i },
{"nAllocationData", "(I[F)V", (void*)nAllocationData_f },
{"nAllocationSubData1D", "(III[I)V", (void*)nAllocationSubData1D_i },
@@ -1347,7 +1242,6 @@
{"nAllocationRead", "(I[F)V", (void*)nAllocationRead_f },
{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
-{"nTriangleMeshDestroy", "(I)V", (void*)nTriangleMeshDestroy },
{"nTriangleMeshBegin", "(II)V", (void*)nTriangleMeshBegin },
{"nTriangleMeshAddVertex_XY", "(FF)V", (void*)nTriangleMeshAddVertex_XY },
{"nTriangleMeshAddVertex_XYZ", "(FFF)V", (void*)nTriangleMeshAddVertex_XYZ },
@@ -1357,7 +1251,6 @@
{"nTriangleMeshAddTriangle", "(III)V", (void*)nTriangleMeshAddTriangle },
{"nTriangleMeshCreate", "()I", (void*)nTriangleMeshCreate },
-{"nAdapter1DDestroy", "(I)V", (void*)nAdapter1DDestroy },
{"nAdapter1DBindAllocation", "(II)V", (void*)nAdapter1DBindAllocation },
{"nAdapter1DSetConstraint", "(III)V", (void*)nAdapter1DSetConstraint },
{"nAdapter1DData", "(I[I)V", (void*)nAdapter1DData_i },
@@ -1366,7 +1259,6 @@
{"nAdapter1DSubData", "(III[F)V", (void*)nAdapter1DSubData_f },
{"nAdapter1DCreate", "()I", (void*)nAdapter1DCreate },
-{"nAdapter2DDestroy", "(I)V", (void*)nAdapter2DDestroy },
{"nAdapter2DBindAllocation", "(II)V", (void*)nAdapter2DBindAllocation },
{"nAdapter2DSetConstraint", "(III)V", (void*)nAdapter2DSetConstraint },
{"nAdapter2DData", "(I[I)V", (void*)nAdapter2DData_i },
@@ -1375,13 +1267,12 @@
{"nAdapter2DSubData", "(IIIII[F)V", (void*)nAdapter2DSubData_f },
{"nAdapter2DCreate", "()I", (void*)nAdapter2DCreate },
-{"nScriptDestroy", "(I)V", (void*)nScriptDestroy },
{"nScriptBindAllocation", "(III)V", (void*)nScriptBindAllocation },
{"nScriptSetClearColor", "(IFFFF)V", (void*)nScriptSetClearColor },
{"nScriptSetClearDepth", "(IF)V", (void*)nScriptSetClearDepth },
{"nScriptSetClearStencil", "(II)V", (void*)nScriptSetClearStencil },
{"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone },
-{"nScriptSetType", "(ILjava/lang/String;I)V", (void*)nScriptSetType },
+{"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType },
{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot },
{"nScriptCBegin", "()V", (void*)nScriptCBegin },
@@ -1397,18 +1288,13 @@
{"nProgramFragmentStoreBlendFunc", "(II)V", (void*)nProgramFragmentStoreBlendFunc },
{"nProgramFragmentStoreDither", "(Z)V", (void*)nProgramFragmentStoreDither },
{"nProgramFragmentStoreCreate", "()I", (void*)nProgramFragmentStoreCreate },
-{"nProgramFragmentStoreDestroy", "(I)V", (void*)nProgramFragmentStoreDestroy },
-{"nProgramFragmentBegin", "(II)V", (void*)nProgramFragmentBegin },
+{"nProgramFragmentBegin", "(IIZ)V", (void*)nProgramFragmentBegin },
{"nProgramFragmentBindTexture", "(III)V", (void*)nProgramFragmentBindTexture },
{"nProgramFragmentBindSampler", "(III)V", (void*)nProgramFragmentBindSampler },
-{"nProgramFragmentSetType", "(II)V", (void*)nProgramFragmentSetType },
-{"nProgramFragmentSetEnvMode", "(II)V", (void*)nProgramFragmentSetEnvMode },
-{"nProgramFragmentSetTexEnable", "(IZ)V", (void*)nProgramFragmentSetTexEnable },
+{"nProgramFragmentSetSlot", "(IZII)V", (void*)nProgramFragmentSetSlot },
{"nProgramFragmentCreate", "()I", (void*)nProgramFragmentCreate },
-{"nProgramFragmentDestroy", "(I)V", (void*)nProgramFragmentDestroy },
-{"nProgramVertexDestroy", "(I)V", (void*)nProgramVertexDestroy },
{"nProgramVertexBindAllocation", "(II)V", (void*)nProgramVertexBindAllocation },
{"nProgramVertexBegin", "(II)V", (void*)nProgramVertexBegin },
{"nProgramVertexSetTextureMatrixEnable", "(Z)V", (void*)nProgramVertexSetTextureMatrixEnable },
@@ -1419,7 +1305,6 @@
{"nLightSetIsMono", "(Z)V", (void*)nLightSetIsMono },
{"nLightSetIsLocal", "(Z)V", (void*)nLightSetIsLocal },
{"nLightCreate", "()I", (void*)nLightCreate },
-{"nLightDestroy", "(I)V", (void*)nLightDestroy },
{"nLightSetColor", "(IFFF)V", (void*)nLightSetColor },
{"nLightSetPosition", "(IFFF)V", (void*)nLightSetPosition },
@@ -1428,12 +1313,10 @@
{"nContextBindProgramFragment", "(I)V", (void*)nContextBindProgramFragment },
{"nContextBindProgramVertex", "(I)V", (void*)nContextBindProgramVertex },
-{"nSamplerDestroy", "(I)V", (void*)nSamplerDestroy },
{"nSamplerBegin", "()V", (void*)nSamplerBegin },
{"nSamplerSet", "(II)V", (void*)nSamplerSet },
{"nSamplerCreate", "()I", (void*)nSamplerCreate },
-{"nSimpleMeshDestroy", "(I)V", (void*)nSimpleMeshDestroy },
{"nSimpleMeshCreate", "(II[II)I", (void*)nSimpleMeshCreate },
{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex },
{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex },
diff --git a/im/java/android/im/BrandingResourceIDs.java b/im/java/android/im/BrandingResourceIDs.java
deleted file mode 100644
index 9960722..0000000
--- a/im/java/android/im/BrandingResourceIDs.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 android.im;
-
-/**
- * @hide
- * Defines the IDs of branding resources.
- */
-public interface BrandingResourceIDs {
- /**
- * The logo icon of the provider which is displayed in the landing page.
- */
- public static final int DRAWABLE_LOGO = 100;
- /**
- * The icon of online presence status.
- */
- public static final int DRAWABLE_PRESENCE_ONLINE = 102;
- /**
- * The icon of busy presence status.
- */
- public static final int DRAWABLE_PRESENCE_BUSY = 103;
- /**
- * The icon of away presence status.
- */
- public static final int DRAWABLE_PRESENCE_AWAY = 104;
- /**
- * The icon of invisible presence status.
- */
- public static final int DRAWABLE_PRESENCE_INVISIBLE = 105;
- /**
- * The icon of offline presence status.
- */
- public static final int DRAWABLE_PRESENCE_OFFLINE = 106;
- /**
- * The label of the menu to go to the contact list screen.
- */
- public static final int STRING_MENU_CONTACT_LIST = 107;
-
-}
diff --git a/im/java/android/im/IImPlugin.aidl b/im/java/android/im/IImPlugin.aidl
deleted file mode 100644
index 229cd0e..0000000
--- a/im/java/android/im/IImPlugin.aidl
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 android.im;
-
-/**
- * @hide
- */
-interface IImPlugin {
- /**
- * Notify the plugin the front door activity is created. This gives the plugin a chance to
- * start its own servics, etc.
- */
- void onStart();
-
- /**
- * Notify the plugin the front door activity is stopping.
- */
- void onStop();
-
- /**
- * Sign in to the service for the account passed in.
- *
- * @param account the account id for the accont to be signed into.
- */
- void signIn(long account);
-
- /**
- * Sign out of the service for the account passed in.
- *
- * @param account the account id for the accont to be signed out of.
- */
- void signOut(long account);
-
- /**
- * Returns the package name used to load the resources for the given provider name.
- *
- * @return The package name to load the resourcs for the given provider.
- */
- String getResourcePackageNameForProvider(String providerName);
-
- /**
- * Returns a map of branding resources for the given provider. The keys are defined
- * in {@link android.im.BrandingResourceIDs}. The values are the resource identifiers generated
- * by the aapt tool.
- *
- * @return The map of branding resources for the given provider.
- */
- Map getResourceMapForProvider(String providerName);
-
- /*
- * Returns a list of supported IM providers.
- *
- * @return a List of supported providers.
- */
- List getSupportedProviders();
-}
diff --git a/im/java/android/im/ImPluginConsts.java b/im/java/android/im/ImPluginConsts.java
deleted file mode 100644
index 416493ff..0000000
--- a/im/java/android/im/ImPluginConsts.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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 android.im;
-
-/**
- * @hide
- */
-public class ImPluginConsts {
- /**
- * The intent action name for the plugin service.
- */
- public static final String PLUGIN_ACTION_NAME = "android.im.plugin";
-}
\ No newline at end of file
diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
index 83c7283..435540e 100644
--- a/include/binder/MemoryHeapBase.h
+++ b/include/binder/MemoryHeapBase.h
@@ -42,7 +42,7 @@
* maps the memory referenced by fd. but DOESN'T take ownership
* of the filedescriptor (it makes a copy with dup()
*/
- MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
/*
* maps memory from the given device
@@ -82,7 +82,7 @@
int flags = 0, const char* device = NULL);
private:
- status_t mapfd(int fd, size_t size);
+ status_t mapfd(int fd, size_t size, uint32_t offset = 0);
int mFD;
size_t mSize;
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 58c2d9a..ba6c711 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -74,6 +74,7 @@
status_t writeInt64(int64_t val);
status_t writeFloat(float val);
status_t writeDouble(double val);
+ status_t writeIntPtr(intptr_t val);
status_t writeCString(const char* str);
status_t writeString8(const String8& str);
status_t writeString16(const String16& str);
@@ -109,6 +110,8 @@
status_t readFloat(float *pArg) const;
double readDouble() const;
status_t readDouble(double *pArg) const;
+ intptr_t readIntPtr() const;
+ status_t readIntPtr(intptr_t *pArg) const;
const char* readCString() const;
String8 readString8() const;
@@ -163,6 +166,14 @@
void initState();
void scanForFds() const;
+ template<class T>
+ status_t readAligned(T *pArg) const;
+
+ template<class T> T readAligned() const;
+
+ template<class T>
+ status_t writeAligned(T val);
+
status_t mError;
uint8_t* mData;
size_t mDataSize;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 7e5ff61..58a74c7 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -56,6 +56,14 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) = 0;
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) = 0;
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) = 0;
+
virtual status_t use_buffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) = 0;
@@ -82,6 +90,11 @@
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp) = 0;
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) = 0;
+
virtual sp<IOMXRenderer> createRenderer(
const sp<ISurface> &surface,
const char *componentName,
@@ -114,10 +127,11 @@
QUIT_OBSERVER,
} type;
+ IOMX::node_id node;
+
union {
// if type == EVENT
struct {
- IOMX::node_id node;
OMX_EVENTTYPE event;
OMX_U32 data1;
OMX_U32 data2;
@@ -126,13 +140,11 @@
// if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER
// || type == INITIAL_FILL_BUFFER
struct {
- IOMX::node_id node;
IOMX::buffer_id buffer;
} buffer_data;
// if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE
struct {
- IOMX::node_id node;
IOMX::buffer_id buffer;
OMX_U32 range_offset;
OMX_U32 range_length;
@@ -143,7 +155,6 @@
// if type == SEND_COMMAND
struct {
- IOMX::node_id node;
OMX_COMMANDTYPE cmd;
OMX_S32 param;
} send_command_data;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 3db8a0f..9ea2775 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -52,6 +52,7 @@
METADATA_KEY_VIDEO_FORMAT = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_VIDEO_WIDTH = 20,
+ METADATA_KEY_WRITER = 21,
// Add more here...
};
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 0f2e528..960eda3 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -31,10 +31,10 @@
class AudioPlayer : public TimeSource {
public:
AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
- ~AudioPlayer();
+ virtual ~AudioPlayer();
// Caller retains ownership of "source".
- void setSource(MediaSource *source);
+ void setSource(const sp<MediaSource> &source);
// Return time in us.
virtual int64_t getRealTimeUs();
@@ -56,7 +56,7 @@
status_t seekTo(int64_t time_us);
private:
- MediaSource *mSource;
+ sp<MediaSource> mSource;
AudioTrack *mAudioTrack;
MediaBuffer *mInputBuffer;
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
index e275cb4..e35e19e 100644
--- a/include/media/stagefright/CachingDataSource.h
+++ b/include/media/stagefright/CachingDataSource.h
@@ -26,14 +26,16 @@
class CachingDataSource : public DataSource {
public:
- // Assumes ownership of "source".
- CachingDataSource(DataSource *source, size_t pageSize, int numPages);
- virtual ~CachingDataSource();
+ CachingDataSource(
+ const sp<DataSource> &source, size_t pageSize, int numPages);
status_t InitCheck() const;
virtual ssize_t read_at(off_t offset, void *data, size_t size);
+protected:
+ virtual ~CachingDataSource();
+
private:
struct Page {
Page *mPrev, *mNext;
@@ -42,7 +44,7 @@
void *mData;
};
- DataSource *mSource;
+ sp<DataSource> mSource;
void *mData;
size_t mPageSize;
Page *mFirst, *mLast;
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 31eea27..f46f0af 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -22,19 +22,22 @@
#include <utils/Errors.h>
#include <utils/List.h>
+#include <utils/RefBase.h>
#include <utils/threads.h>
namespace android {
class String8;
-class DataSource {
+class DataSource : public RefBase {
public:
DataSource() {}
- virtual ~DataSource() {}
virtual ssize_t read_at(off_t offset, void *data, size_t size) = 0;
+ // Convenience methods:
+ bool getUInt16(off_t offset, uint16_t *x);
+
// May return ERROR_UNSUPPORTED.
virtual status_t getSize(off_t *size);
@@ -43,11 +46,14 @@
bool sniff(String8 *mimeType, float *confidence);
typedef bool (*SnifferFunc)(
- DataSource *source, String8 *mimeType, float *confidence);
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
static void RegisterSniffer(SnifferFunc func);
static void RegisterDefaultSniffers();
+protected:
+ virtual ~DataSource() {}
+
private:
static Mutex gSnifferMutex;
static List<SnifferFunc> gSniffers;
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
index 09cfb70..4e1f3c3 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/include/media/stagefright/MP3Extractor.h
@@ -28,16 +28,17 @@
class MP3Extractor : public MediaExtractor {
public:
// Extractor assumes ownership of "source".
- MP3Extractor(DataSource *source);
+ MP3Extractor(const sp<DataSource> &source);
- ~MP3Extractor();
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index);
- status_t countTracks(int *num_tracks);
- status_t getTrack(int index, MediaSource **source);
- sp<MetaData> getTrackMetaData(int index);
+protected:
+ virtual ~MP3Extractor();
private:
- DataSource *mDataSource;
+ sp<DataSource> mDataSource;
off_t mFirstFramePos;
sp<MetaData> mMeta;
uint32_t mFixedHeader;
@@ -46,7 +47,8 @@
MP3Extractor &operator=(const MP3Extractor &);
};
-bool SniffMP3(DataSource *source, String8 *mimeType, float *confidence);
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
} // namespace android
diff --git a/include/media/stagefright/MPEG4Extractor.h b/include/media/stagefright/MPEG4Extractor.h
index 51a7e82..932e30f 100644
--- a/include/media/stagefright/MPEG4Extractor.h
+++ b/include/media/stagefright/MPEG4Extractor.h
@@ -29,22 +29,24 @@
class MPEG4Extractor : public MediaExtractor {
public:
// Extractor assumes ownership of "source".
- MPEG4Extractor(DataSource *source);
- ~MPEG4Extractor();
+ MPEG4Extractor(const sp<DataSource> &source);
- status_t countTracks(int *num_tracks);
- status_t getTrack(int index, MediaSource **source);
- sp<MetaData> getTrackMetaData(int index);
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index);
+
+protected:
+ virtual ~MPEG4Extractor();
private:
struct Track {
Track *next;
sp<MetaData> meta;
uint32_t timescale;
- SampleTable *sampleTable;
+ sp<SampleTable> sampleTable;
};
- DataSource *mDataSource;
+ sp<DataSource> mDataSource;
bool mHaveMetadata;
Track *mFirstTrack, *mLastTrack;
@@ -58,7 +60,8 @@
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
-bool SniffMPEG4(DataSource *source, String8 *mimeType, float *confidence);
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
} // namespace android
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 40d6127..5147de9 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -30,13 +30,12 @@
class MediaSource;
class MetaData;
-class MPEG4Writer {
+class MPEG4Writer : public RefBase {
public:
MPEG4Writer(const char *filename);
- ~MPEG4Writer();
// Caller retains ownership of both meta and source.
- void addSource(const sp<MetaData> &meta, MediaSource *source);
+ void addSource(const sp<MetaData> &meta, const sp<MediaSource> &source);
void start();
void stop();
@@ -50,6 +49,9 @@
void write(const void *data, size_t size);
void endBox();
+protected:
+ virtual ~MPEG4Writer();
+
private:
class Track;
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c72ed66..339e6fb 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -75,6 +75,8 @@
// MetaData.
MediaBuffer *clone();
+ int refcount() const;
+
protected:
virtual ~MediaBuffer();
@@ -102,8 +104,6 @@
void setNextBuffer(MediaBuffer *buffer);
MediaBuffer *nextBuffer();
- int refcount() const;
-
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
};
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index e95a9c2..0488292 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -18,6 +18,7 @@
#define MEDIA_BUFFER_GROUP_H_
+#include <media/stagefright/MediaBuffer.h>
#include <utils/Errors.h>
#include <utils/threads.h>
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
new file mode 100644
index 0000000..c8a8f00e7
--- /dev/null
+++ b/include/media/stagefright/MediaDebug.h
@@ -0,0 +1,20 @@
+#ifndef MEDIA_DEBUG_H_
+
+#define MEDIA_DEBUG_H_
+
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x) #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y) \
+ LOG_ALWAYS_FATAL_IF( \
+ (x) != (y), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x) \
+ LOG_ALWAYS_FATAL_IF( \
+ !(x), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+#endif // MEDIA_DEBUG_H_
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 38f8e5b..67e45bd 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -26,18 +26,18 @@
class MediaSource;
class MetaData;
-class MediaExtractor {
+class MediaExtractor : public RefBase {
public:
- static MediaExtractor *Create(DataSource *source, const char *mime = NULL);
+ static sp<MediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
- virtual ~MediaExtractor() {}
-
- virtual status_t countTracks(int *num_tracks) = 0;
- virtual status_t getTrack(int index, MediaSource **source) = 0;
- virtual sp<MetaData> getTrackMetaData(int index) = 0;
+ virtual size_t countTracks() = 0;
+ virtual sp<MediaSource> getTrack(size_t index) = 0;
+ virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
protected:
MediaExtractor() {}
+ virtual ~MediaExtractor() {}
private:
MediaExtractor(const MediaExtractor &);
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
index e96e5e8..53a2088 100644
--- a/include/media/stagefright/MediaPlayerImpl.h
+++ b/include/media/stagefright/MediaPlayerImpl.h
@@ -35,7 +35,6 @@
class MediaSource;
class MemoryHeapPmem;
class MetaData;
-class OMXDecoder;
class Surface;
class TimeSource;
@@ -71,16 +70,16 @@
OMXClient mClient;
- MediaExtractor *mExtractor;
+ sp<MediaExtractor> mExtractor;
TimeSource *mTimeSource;
- MediaSource *mAudioSource;
- OMXDecoder *mAudioDecoder;
+ sp<MediaSource> mAudioSource;
+ sp<MediaSource> mAudioDecoder;
AudioPlayer *mAudioPlayer;
- MediaSource *mVideoSource;
- MediaSource *mVideoDecoder;
+ sp<MediaSource> mVideoSource;
+ sp<MediaSource> mVideoDecoder;
int32_t mVideoWidth, mVideoHeight;
int64_t mVideoPosition;
@@ -103,16 +102,13 @@
bool mSeeking;
int64_t mSeekTimeUs;
- size_t mFrameSize;
- bool mUseSoftwareColorConversion;
-
void init();
static void *VideoWrapper(void *me);
void videoEntry();
- void setAudioSource(MediaSource *source);
- void setVideoSource(MediaSource *source);
+ void setAudioSource(const sp<MediaSource> &source);
+ void setVideoSource(const sp<MediaSource> &source);
MediaSource *makeShoutcastSource(const char *path);
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index eb07f68..d1fa114 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -27,9 +27,8 @@
class MediaBuffer;
class MetaData;
-struct MediaSource {
+struct MediaSource : public RefBase {
MediaSource();
- virtual ~MediaSource();
// To be called before any other methods on this object, except
// getFormat().
@@ -81,6 +80,9 @@
int64_t mLatenessUs;
};
+protected:
+ virtual ~MediaSource();
+
private:
MediaSource(const MediaSource &);
MediaSource &operator=(const MediaSource &);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 2d5b8d8..be60565 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -28,23 +28,24 @@
namespace android {
enum {
- kKeyMIMEType = 'mime',
- kKeyWidth = 'widt',
- kKeyHeight = 'heig',
- kKeyChannelCount = '#chn',
- kKeySampleRate = 'srte',
- kKeyBitRate = 'brte',
- kKeyESDS = 'esds',
- kKeyAVCC = 'avcc',
- kKeyTimeUnits = '#tim',
- kKeyTimeScale = 'scal',
- kKeyNeedsNALFraming = 'NALf',
- kKeyIsSyncFrame = 'sync',
- kKeyDuration = 'dura',
- kKeyColorFormat = 'colf',
- kKeyPlatformPrivate = 'priv',
- kKeyDecoderComponent = 'decC',
- kKeyBufferID = 'bfID',
+ kKeyMIMEType = 'mime',
+ kKeyWidth = 'widt',
+ kKeyHeight = 'heig',
+ kKeyChannelCount = '#chn',
+ kKeySampleRate = 'srte',
+ kKeyBitRate = 'brte',
+ kKeyESDS = 'esds',
+ kKeyAVCC = 'avcc',
+ kKeyTimeUnits = '#tim',
+ kKeyTimeScale = 'scal',
+ kKeyWantsNALFragments = 'NALf',
+ kKeyIsSyncFrame = 'sync',
+ kKeyDuration = 'dura',
+ kKeyColorFormat = 'colf',
+ kKeyPlatformPrivate = 'priv',
+ kKeyDecoderComponent = 'decC',
+ kKeyBufferID = 'bfID',
+ kKeyCompressedSize = 'cmpS',
};
enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
new file mode 100644
index 0000000..ff94e10
--- /dev/null
+++ b/include/media/stagefright/OMXCodec.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OMX_CODEC_H_
+
+#define OMX_CODEC_H_
+
+#include <media/IOMX.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MemoryDealer;
+struct OMXCodecObserver;
+
+struct OMXCodec : public MediaSource,
+ public MediaBufferObserver {
+ static sp<OMXCodec> Create(
+ const sp<IOMX> &omx,
+ const sp<MetaData> &meta, bool createEncoder,
+ const sp<MediaSource> &source);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+ void on_message(const omx_message &msg);
+
+ // from MediaBufferObserver
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+protected:
+ virtual ~OMXCodec();
+
+private:
+ enum State {
+ DEAD,
+ LOADED,
+ LOADED_TO_IDLE,
+ IDLE_TO_EXECUTING,
+ EXECUTING,
+ EXECUTING_TO_IDLE,
+ IDLE_TO_LOADED,
+ RECONFIGURING,
+ ERROR
+ };
+
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+
+ enum PortStatus {
+ ENABLED,
+ DISABLING,
+ DISABLED,
+ ENABLING,
+ SHUTTING_DOWN,
+ };
+
+ enum Quirks {
+ kNeedsFlushBeforeDisable = 1,
+ kWantsNALFragments = 2,
+ kRequiresLoadedToIdleAfterAllocation = 4,
+ kRequiresAllocateBufferOnInputPorts = 8,
+ kRequiresFlushCompleteEmulation = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ };
+
+ struct BufferInfo {
+ IOMX::buffer_id mBuffer;
+ bool mOwnedByComponent;
+ sp<IMemory> mMem;
+ MediaBuffer *mMediaBuffer;
+ };
+
+ struct CodecSpecificData {
+ size_t mSize;
+ uint8_t mData[1];
+ };
+
+ sp<IOMX> mOMX;
+ IOMX::node_id mNode;
+ sp<OMXCodecObserver> mObserver;
+ uint32_t mQuirks;
+ bool mIsEncoder;
+ char *mMIME;
+ char *mComponentName;
+ sp<MetaData> mOutputFormat;
+ sp<MediaSource> mSource;
+ Vector<CodecSpecificData *> mCodecSpecificData;
+ size_t mCodecSpecificDataIndex;
+
+ sp<MemoryDealer> mDealer[2];
+
+ State mState;
+ Vector<BufferInfo> mPortBuffers[2];
+ PortStatus mPortStatus[2];
+ bool mSignalledEOS;
+ bool mNoMoreOutputData;
+ int64_t mSeekTimeUs;
+
+ Mutex mLock;
+ Condition mAsyncCompletion;
+
+ // A list of indices into mPortStatus[kPortIndexOutput] filled with data.
+ List<size_t> mFilledBuffers;
+ Condition mBufferFilled;
+
+ OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ bool isEncoder, const char *mime, const char *componentName,
+ const sp<MediaSource> &source);
+
+ void addCodecSpecificData(const void *data, size_t size);
+ void clearCodecSpecificData();
+
+ void setAMRFormat();
+ void setAACFormat();
+
+ status_t setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat);
+
+ void setVideoInputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height);
+
+ void setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height);
+
+ void setImageOutputFormat(
+ OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height);
+
+ void setJPEGInputFormat(
+ OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize);
+
+ status_t allocateBuffers();
+ status_t allocateBuffersOnPort(OMX_U32 portIndex);
+
+ status_t freeBuffersOnPort(
+ OMX_U32 portIndex, bool onlyThoseWeOwn = false);
+
+ void drainInputBuffer(IOMX::buffer_id buffer);
+ void fillOutputBuffer(IOMX::buffer_id buffer);
+ void drainInputBuffer(BufferInfo *info);
+ void fillOutputBuffer(BufferInfo *info);
+
+ void drainInputBuffers();
+ void fillOutputBuffers();
+
+ // Returns true iff a flush was initiated and a completion event is
+ // upcoming, false otherwise (A flush was not necessary as we own all
+ // the buffers on that port).
+ // This method will ONLY ever return false for a component with quirk
+ // "kRequiresFlushCompleteEmulation".
+ bool flushPortAsync(OMX_U32 portIndex);
+
+ void disablePortAsync(OMX_U32 portIndex);
+ void enablePortAsync(OMX_U32 portIndex);
+
+ static size_t countBuffersWeOwn(const Vector<BufferInfo> &buffers);
+ static bool isIntermediateState(State state);
+
+ void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
+ void onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data);
+ void onStateChange(OMX_STATETYPE newState);
+ void onPortSettingsChanged(OMX_U32 portIndex);
+
+ void setState(State newState);
+
+ status_t init();
+ void initOutputFormat(const sp<MetaData> &inputFormat);
+
+ void dumpPortStatus(OMX_U32 portIndex);
+
+ OMXCodec(const OMXCodec &);
+ OMXCodec &operator=(const OMXCodec &);
+};
+
+} // namespace android
+
+#endif // OMX_CODEC_H_
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index c6b7cb3..99d803a 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -36,14 +36,10 @@
public OMXObserver,
public MediaBufferObserver {
public:
- static OMXDecoder *Create(
+ static sp<OMXDecoder> Create(
OMXClient *client, const sp<MetaData> &data,
- bool createEncoder = false);
-
- virtual ~OMXDecoder();
-
- // Caller retains ownership of "source".
- void setSource(MediaSource *source);
+ bool createEncoder,
+ const sp<MediaSource> &source);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -61,6 +57,9 @@
// from MediaBufferObserver
virtual void signalBufferReturned(MediaBuffer *buffer);
+protected:
+ virtual ~OMXDecoder();
+
private:
enum {
kPortIndexInput = 0,
@@ -77,7 +76,7 @@
};
enum Quirks {
- kWantsRawNALFrames = 1,
+ kWantsNALFragments = 1,
kDoesntReturnBuffersOnDisable = 2,
kDoesntFlushOnExecutingToIdle = 4,
kDoesntProperlyFlushAllPortsAtOnce = 8,
@@ -97,7 +96,7 @@
bool mIsEncoder;
uint32_t mQuirks;
- MediaSource *mSource;
+ sp<MediaSource> mSource;
sp<MetaData> mOutputFormat;
Mutex mLock;
@@ -135,7 +134,8 @@
OMXDecoder(OMXClient *client, IOMX::node_id node,
const char *mime, const char *codec,
bool is_encoder,
- uint32_t quirks);
+ uint32_t quirks,
+ const sp<MediaSource> &source);
void setPortStatus(OMX_U32 port_index, PortStatus status);
PortStatus getPortStatus(OMX_U32 port_index) const;
diff --git a/include/media/stagefright/SampleTable.h b/include/media/stagefright/SampleTable.h
index 712da10..808d142 100644
--- a/include/media/stagefright/SampleTable.h
+++ b/include/media/stagefright/SampleTable.h
@@ -22,17 +22,16 @@
#include <stdint.h>
#include <media/stagefright/MediaErrors.h>
+#include <utils/RefBase.h>
#include <utils/threads.h>
namespace android {
class DataSource;
-class SampleTable {
+class SampleTable : public RefBase {
public:
- // Caller retains ownership of "source".
- SampleTable(DataSource *source);
- ~SampleTable();
+ SampleTable(const sp<DataSource> &source);
// type can be 'stco' or 'co64'.
status_t setChunkOffsetParams(
@@ -76,8 +75,11 @@
status_t findClosestSyncSample(
uint32_t start_sample_index, uint32_t *sample_index);
+protected:
+ ~SampleTable();
+
private:
- DataSource *mDataSource;
+ sp<DataSource> mDataSource;
Mutex mLock;
off_t mChunkOffsetOffset;
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
index f7fa81b..ef42648 100644
--- a/include/media/stagefright/TIHardwareRenderer.h
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -46,6 +46,7 @@
size_t mFrameSize;
sp<Overlay> mOverlay;
Vector<void *> mOverlayAddresses;
+ bool mIsFirstFrame;
size_t mIndex;
TIHardwareRenderer(const TIHardwareRenderer &);
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 523aed0..67c2dd8 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -287,6 +287,7 @@
vec4_t normalizedObjPosition;
vec4_t spotDir;
vec4_t normalizedSpotDir;
+ vec4_t objViewer;
GLfixed spotExp;
GLfixed spotCutoff;
GLfixed spotCutoffCosine;
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 932a70a..5d231e6d 100644
--- a/include/ui/ISurfaceFlingerClient.h
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -52,6 +52,9 @@
struct surface_data_t {
int32_t token;
int32_t identity;
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
};
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 4ff0e4a..30ab82f 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -146,16 +146,16 @@
static bool isValid(const sp<Surface>& surface) {
return (surface != 0) && surface->isValid();
}
- bool isValid() {
- return mToken>=0 && mClient!=0;
- }
+
static bool isSameSurface(
const sp<Surface>& lhs, const sp<Surface>& rhs);
- SurfaceID ID() const { return mToken; }
- uint32_t getFlags() const { return mFlags; }
+
+ bool isValid();
+ SurfaceID ID() const { return mToken; }
+ uint32_t getFlags() const { return mFlags; }
uint32_t getIdentity() const { return mIdentity; }
-
+ // the lock/unlock APIs must be used from the same thread
status_t lock(SurfaceInfo* info, bool blocking = true);
status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
status_t unlockAndPost();
@@ -175,14 +175,18 @@
friend class SurfaceComposerClient;
friend class SurfaceControl;
+
// camera and camcorder need access to the ISurface binder interface for preview
friend class Camera;
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
- friend class Test;
friend class IOMX;
- const sp<ISurface>& getISurface() const { return mSurface; }
+ // this is just to be able to write some unit tests
+ friend class Test;
+
+ sp<SurfaceComposerClient> getClient() const;
+ sp<ISurface> getISurface() const;
status_t getBufferLocked(int index, int usage);
@@ -210,24 +214,38 @@
status_t queueBuffer(const sp<SurfaceBuffer>& buffer);
- alloc_device_t* mAllocDevice;
+ void setUsage(uint32_t reqUsage);
+
+ // constants
sp<SurfaceComposerClient> mClient;
sp<ISurface> mSurface;
- sp<SurfaceBuffer> mBuffers[2];
- sp<SurfaceBuffer> mLockedBuffer;
SurfaceID mToken;
uint32_t mIdentity;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mUsage;
PixelFormat mFormat;
uint32_t mFlags;
- mutable Region mDirtyRegion;
- mutable Region mOldDirtyRegion;
- mutable uint8_t mBackbufferIndex;
- mutable Mutex mSurfaceLock;
- Rect mSwapRectangle;
BufferMapper& mBufferMapper;
+
+ // protected by mSurfaceLock
+ Rect mSwapRectangle;
+ uint32_t mUsage;
+ bool mUsageChanged;
+
+ // protected by mSurfaceLock. These are also used from lock/unlock
+ // but in that case, they must be called form the same thread.
+ sp<SurfaceBuffer> mBuffers[2];
+ mutable Region mDirtyRegion;
+ mutable uint8_t mBackbufferIndex;
+
+ // must be used from the lock/unlock thread
+ sp<SurfaceBuffer> mLockedBuffer;
+ mutable Region mOldDirtyRegion;
+
+ // query() must be called from dequeueBuffer() thread
+ uint32_t mWidth;
+ uint32_t mHeight;
+
+ // Inherently thread-safe
+ mutable Mutex mSurfaceLock;
};
}; // namespace android
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 363142c..3740db5 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -54,8 +54,8 @@
void* reserved[4];
/* reference-counting interface */
- void (*incRef)(android_native_base_t* base);
- void (*decRef)(android_native_base_t* base);
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
} android_native_base_t;
// ---------------------------------------------------------------------------
@@ -108,7 +108,7 @@
*
* Returns 0 on success or -errno on error.
*/
- int (*setSwapInterval)(android_native_window_t* window,
+ int (*setSwapInterval)(struct android_native_window_t* window,
int interval);
/*
@@ -118,7 +118,7 @@
*
* Returns 0 on success or -errno on error.
*/
- int (*dequeueBuffer)(android_native_window_t* window,
+ int (*dequeueBuffer)(struct android_native_window_t* window,
struct android_native_buffer_t** buffer);
/*
@@ -128,7 +128,7 @@
*
* Returns 0 on success or -errno on error.
*/
- int (*lockBuffer)(android_native_window_t* window,
+ int (*lockBuffer)(struct android_native_window_t* window,
struct android_native_buffer_t* buffer);
/*
* hook called by EGL when modifications to the render buffer are done.
@@ -138,7 +138,7 @@
*
* Returns 0 on success or -errno on error.
*/
- int (*queueBuffer)(android_native_window_t* window,
+ int (*queueBuffer)(struct android_native_window_t* window,
struct android_native_buffer_t* buffer);
/*
@@ -146,7 +146,7 @@
*
* Returns 0 on success or -errno on error.
*/
- int (*query)(android_native_window_t* window,
+ int (*query)(struct android_native_window_t* window,
int what, int* value);
/*
@@ -162,7 +162,7 @@
*
*/
- int (*perform)(android_native_window_t* window,
+ int (*perform)(struct android_native_window_t* window,
int operation, ... );
void* reserved_proc[3];
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
index 21d04bd..d9ed32d 100644
--- a/include/utils/Debug.h
+++ b/include/utils/Debug.h
@@ -29,6 +29,8 @@
#define COMPILE_TIME_ASSERT(_exp) \
template class CompileTimeAssert< (_exp) >;
#endif
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
+ CompileTimeAssert<( _exp )>();
// ---------------------------------------------------------------------------
diff --git a/keystore/MODULE_LICENSE_APACHE2 b/keystore/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/keystore/MODULE_LICENSE_APACHE2
diff --git a/keystore/NOTICE b/keystore/NOTICE
new file mode 100644
index 0000000..64aaa8d
--- /dev/null
+++ b/keystore/NOTICE
@@ -0,0 +1,190 @@
+
+ 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index ac38f51..5df078f 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -78,13 +78,13 @@
}
}
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(0), mNeedUnmap(false)
{
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- mapfd(dup(fd), size);
+ mapfd(dup(fd), size, offset);
}
status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
@@ -100,7 +100,7 @@
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
{
if (size == 0) {
// try to figure out the size automatically
@@ -121,7 +121,7 @@
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
void* base = (uint8_t*)mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
LOGE("mmap(fd=%d, size=%u) failed (%s)",
fd, uint32_t(size), strerror(errno));
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 785a3c5..e397bce 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -562,54 +562,27 @@
status_t Parcel::writeInt32(int32_t val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int32_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeInt64(int64_t val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int64_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeFloat(float val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<float*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+ return writeAligned(val);
}
status_t Parcel::writeDouble(double val)
{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<double*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
+ return writeAligned(val);
+}
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
+status_t Parcel::writeIntPtr(intptr_t val)
+{
+ return writeAligned(val);
}
status_t Parcel::writeCString(const char* str)
@@ -768,103 +741,98 @@
return NULL;
}
-status_t Parcel::readInt32(int32_t *pArg) const
-{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+template<class T>
+status_t Parcel::readAligned(T *pArg) const {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(T)) <= mDataSize) {
const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- *pArg = *reinterpret_cast<const int32_t*>(data);
+ mDataPos += sizeof(T);
+ *pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
}
}
+template<class T>
+T Parcel::readAligned() const {
+ T result;
+ if (readAligned(&result) != NO_ERROR) {
+ result = 0;
+ }
+
+ return result;
+}
+
+template<class T>
+status_t Parcel::writeAligned(T val) {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<T*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::readInt32(int32_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
int32_t Parcel::readInt32() const
{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int32_t*>(data);
- }
- return 0;
+ return readAligned<int32_t>();
}
status_t Parcel::readInt64(int64_t *pArg) const
{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- *pArg = *reinterpret_cast<const int64_t*>(data);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
int64_t Parcel::readInt64() const
{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int64_t*>(data);
- }
- return 0;
+ return readAligned<int64_t>();
}
status_t Parcel::readFloat(float *pArg) const
{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const float*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
float Parcel::readFloat() const
{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const float*>(data);
- }
- return 0;
+ return readAligned<float>();
}
status_t Parcel::readDouble(double *pArg) const
{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const double*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
+ return readAligned(pArg);
}
double Parcel::readDouble() const
{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const double*>(data);
- }
- return 0;
+ return readAligned<double>();
+}
+
+status_t Parcel::readIntPtr(intptr_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+intptr_t Parcel::readIntPtr() const
+{
+ return readAligned<intptr_t>();
}
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index d7d572e..1e24cd2 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -49,8 +49,9 @@
RsDevice rsDeviceCreate();
void rsDeviceDestroy(RsDevice);
-RsContext rsContextCreate(RsDevice, void *, uint32_t version);
+RsContext rsContextCreate(RsDevice, void *, uint32_t version, bool useDepth);
void rsContextDestroy(RsContext);
+void rsObjDestroyOOB(RsContext, void *);
#define RS_MAX_TEXTURE 2
@@ -79,7 +80,8 @@
RS_KIND_NX,
RS_KIND_NY,
RS_KIND_NZ,
- RS_KIND_INDEX
+ RS_KIND_INDEX,
+ RS_KIND_POINT_SIZE
};
enum RsElementPredefined {
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg b/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
new file mode 100644
index 0000000..565a63b
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index b18c124..f348a62 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -13,30 +13,15 @@
// limitations under the License.
#pragma version(1)
-#pragma stateVertex(PVBackground)
+#pragma stateVertex(PVSky)
#pragma stateFragment(PFBackground)
#pragma stateFragmentStore(PFSBackground)
#define RSID_STATE 0
-#define RSID_FRAME_COUNT 0
-#define RSID_WIDTH 1
-#define RSID_HEIGHT 2
-#define RSID_MESH_WIDTH 3
-#define RSID_MESH_HEIGHT 4
-#define RSID_RIPPLE_MAP_SIZE 5
-#define RSID_RIPPLE_INDEX 6
-#define RSID_DROP_X 7
-#define RSID_DROP_Y 8
-#define RSID_RUNNING 9
-#define RSID_LEAVES_COUNT 10
-
#define RSID_RIPPLE_MAP 1
#define RSID_REFRACTION_MAP 2
#define RSID_LEAVES 3
-
-#define RSID_GL_STATE 4
-#define RSID_GL_WIDTH 0
-#define RSID_GL_HEIGHT 1
+#define RSID_DROP 4
#define LEAF_STRUCT_FIELDS_COUNT 11
#define LEAF_STRUCT_X 0
@@ -66,34 +51,35 @@
return x + 1 + (y + 1) * (width + 2);
}
-void drop(int x, int y, int r) {
- int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
- int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
+void dropWithStrength(int x, int y, int r, int s) {
+ int width = State_meshWidth;
+ int height = State_meshHeight;
if (x < r) x = r;
if (y < r) y = r;
if (x >= width - r) x = width - r - 1;
- if (y >= height - r) x = height - r - 1;
-
+ if (y >= height - r) y = height - r - 1;
+
x = width - x;
- int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
- int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+ int rippleMapSize = State_rippleMapSize;
+ int index = State_rippleIndex;
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
int sqr = r * r;
+ float invs = 1.0f / s;
int h = 0;
- for ( ; h < r; h++) {
+ for ( ; h < r; h += 1) {
int sqv = h * h;
int yn = origin + (y - h) * (width + 2);
int yp = origin + (y + h) * (width + 2);
int w = 0;
- for ( ; w < r; w++) {
+ for ( ; w < r; w += 1) {
int squ = w * w;
if (squ + sqv < sqr) {
- int v = -sqrtf((sqr - (squ + sqv)) << 16);
+ int v = -sqrtf((sqr - (squ + sqv)) << 16) * invs;
current[yn + x + w] = v;
current[yp + x + w] = v;
current[yn + x - w] = v;
@@ -103,17 +89,21 @@
}
}
+void drop(int x, int y, int r) {
+ dropWithStrength(x, y, r, 1);
+}
+
void updateRipples() {
- int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
- int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
- int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
- int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+ int rippleMapSize = State_rippleMapSize;
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ int index = State_rippleIndex;
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
- storeI32(RSID_STATE, RSID_RIPPLE_INDEX, 1 - index);
+ storeI32(RSID_STATE, OFFSETOF_WorldState_rippleIndex, 1 - index);
int a = 1;
int b = width + 2;
@@ -121,21 +111,20 @@
while (h) {
int w = width;
while (w) {
- int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - next[0];
+ int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - *next;
droplet -= (droplet >> DAMP);
- next[0] = droplet;
- current++;
- next++;
- w--;
+ *next = droplet;
+ current += 1;
+ next += 1;
+ w -= 1;
}
current += 2;
next += 2;
- h--;
+ h -= 1;
}
}
-int refraction(int d, int wave) {
- int* map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+int refraction(int d, int wave, int *map) {
int i = d;
if (i < 0) i = -i;
if (i > 512) i = 512;
@@ -149,71 +138,83 @@
}
void generateRipples() {
- int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
- int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
- int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
- int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+ int rippleMapSize = loadI32(RSID_STATE, OFFSETOF_WorldState_rippleMapSize);
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ int index = State_rippleIndex;
int origin = offset(0, 0, width);
int b = width + 2;
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
- float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+ int *map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+ float fw = (float) width;
+ float fh = (float) height;
+ float fy = (1.0f / 512.0f) * (1.0f / RIPPLE_HEIGHT);
int h = height - 1;
while (h >= 0) {
int w = width - 1;
- int wave = current[0];
+ int wave = *current;
int offset = h * width;
while (w >= 0) {
int nextWave = current[1];
int dx = nextWave - wave;
int dy = current[b] - wave;
- int offsetx = refraction(dx, wave) >> 16;
+ int offsetx = refraction(dx, wave, map) >> 16;
int u = (width - w) + offsetx;
u &= ~(u >> 31);
if (u >= width) u = width - 1;
- int offsety = refraction(dy, wave) >> 16;
+ int offsety = refraction(dy, wave, map) >> 16;
int v = (height - h) + offsety;
v &= ~(v >> 31);
if (v >= height) v = height - 1;
- vertices[(offset + w) * 8 + 3] = u / (float) width;
- vertices[(offset + w) * 8 + 4] = v / (float) height;
+ int index = (offset + w) << 3;
+ vertices[index + 3] = u / fw;
+ vertices[index + 4] = v / fh;
// Update Z coordinate of the vertex
- vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
+ vertices[index + 7] = dy * fy;
- w--;
- current++;
+ w -= 1;
+ current += 1;
wave = nextWave;
}
- h--;
+ h -= 1;
current += 2;
}
// Compute the normals for lighting
int y = 0;
- for ( ; y < height; y++) {
+ int w8 = width << 3;
+ for ( ; y < height; y += 1) {
int x = 0;
int yOffset = y * width;
- for ( ; x < width; x++) {
+ for ( ; x < width; x += 1) {
+ int o = (yOffset + x) << 3;
+ int o1 = o + 8;
+ int ow = o + w8;
+ int ow1 = ow + 8;
+
// V1
- float v1x = vertices[(yOffset + x) * 8 + 5];
- float v1y = vertices[(yOffset + x) * 8 + 6];
- float v1z = vertices[(yOffset + x) * 8 + 7];
+ float v1x = vertices[o + 5];
+ float v1y = vertices[o + 6];
+ float v1z = vertices[o + 7];
// V2
- float v2x = vertices[(yOffset + x + 1) * 8 + 5];
- float v2y = vertices[(yOffset + x + 1) * 8 + 6];
- float v2z = vertices[(yOffset + x + 1) * 8 + 7];
+ float v2x = vertices[o1 + 5];
+ float v2y = vertices[o1 + 6];
+ float v2z = vertices[o1 + 7];
// V3
- float v3x = vertices[(yOffset + width + x) * 8 + 5];
- float v3y = vertices[(yOffset + width + x) * 8 + 6];
- float v3z = vertices[(yOffset + width + x) * 8 + 7];
+ float v3x = vertices[ow + 5];
+ float v3y = vertices[ow + 6];
+ float v3z = vertices[ow + 7];
// N1
float n1x = v2x - v1x;
@@ -231,15 +232,15 @@
float n3z = n1x * n2y - n1y * n2x;
// Normalize
- float len = magf3(n3x, n3y, n3z);
- n3x /= len;
- n3y /= len;
- n3z /= len;
+ float len = 1.0f / magf3(n3x, n3y, n3z);
+ n3x *= len;
+ n3y *= len;
+ n3z *= len;
// V2
- v2x = vertices[(yOffset + width + x + 1) * 8 + 5];
- v2y = vertices[(yOffset + width + x + 1) * 8 + 6];
- v2z = vertices[(yOffset + width + x + 1) * 8 + 7];
+ v2x = vertices[ow1 + 5];
+ v2y = vertices[ow1 + 6];
+ v2z = vertices[ow1 + 7];
// N1
n1x = v2x - v1x;
@@ -251,49 +252,23 @@
n2y = v3y - v1y;
n2z = v3z - v1z;
- // Avegare of previous normal and N1 x N2
- n3x = n3x / 2.0f + (n1y * n2z - n1z * n2y) / 2.0f;
- n3y = n3y / 2.0f + (n1z * n2x - n1x * n2z) / 2.0f;
- n3z = n3z / 2.0f + (n1x * n2y - n1y * n2x) / 2.0f;
+ // Average of previous normal and N1 x N2
+ n3x = n3x * 0.5f + (n1y * n2z - n1z * n2y) * 0.5f;
+ n3y = n3y * 0.5f + (n1z * n2x - n1x * n2z) * 0.5f;
+ n3z = n3z * 0.5f + (n1x * n2y - n1y * n2x) * 0.5f;
// Normalize
- len = magf3(n3x, n3y, n3z);
- n3x /= len;
- n3y /= len;
- n3z /= len;
+ len = 1.0f / magf3(n3x, n3y, n3z);
+ n3x *= len;
+ n3y *= len;
+ n3z *= len;
- vertices[(yOffset + x) * 8 + 0] = n3x;
- vertices[(yOffset + x) * 8 + 1] = n3y;
- vertices[(yOffset + x) * 8 + 2] = -n3z;
+ vertices[o + 0] = n3x;
+ vertices[o + 1] = n3y;
+ vertices[o + 2] = -n3z;
// reset Z
- //vertices[(yOffset + x) * 8 + 7] = 0.0f;
- }
- }
-}
-
-void drawNormals() {
- int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
- int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
-
- float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
-
- bindProgramVertex(NAMED_PVLines);
- color(1.0f, 0.0f, 0.0f, 1.0f);
-
- int y = 0;
- for ( ; y < height; y++) {
- int yOffset = y * width;
- int x = 0;
- for ( ; x < width; x++) {
- int offset = (yOffset + x) * 8;
- float vx = vertices[offset + 5];
- float vy = vertices[offset + 6];
- float vz = vertices[offset + 7];
- float nx = vertices[offset + 0];
- float ny = vertices[offset + 1];
- float nz = vertices[offset + 2];
- drawLine(vx, vy, vz, vx + nx / 10.0f, vy + ny / 10.0f, vz + nz / 10.0f);
+ //vertices[(yOffset + x) << 3 + 7] = 0.0f;
}
}
}
@@ -301,10 +276,10 @@
float averageZ(float x1, float x2, float y1, float y2, float* vertices,
int meshWidth, int meshHeight, float glWidth, float glHeight) {
- x1 = ((x1 + glWidth / 2.0f) / glWidth) * meshWidth;
- x2 = ((x2 + glWidth / 2.0f) / glWidth) * meshWidth;
- y1 = ((y1 + glHeight / 2.0f) / glHeight) * meshHeight;
- y2 = ((y2 + glHeight / 2.0f) / glHeight) * meshHeight;
+ x1 = ((x1 + glWidth * 0.5f) / glWidth) * meshWidth;
+ x2 = ((x2 + glWidth * 0.5f) / glWidth) * meshWidth;
+ y1 = ((y1 + glHeight * 0.5f) / glHeight) * meshHeight;
+ y2 = ((y2 + glHeight * 0.5f) / glHeight) * meshHeight;
int quadX1 = clamp(x1, 0, meshWidth);
int quadX2 = clamp(x2, 0, meshWidth);
@@ -315,19 +290,19 @@
int vertexCount = 0;
int y = quadY1;
- for ( ; y < quadY2; y++) {
+ for ( ; y < quadY2; y += 1) {
int x = quadX1;
int yOffset = y * meshWidth;
- for ( ; x < quadX2; x++) {
- z += vertices[(yOffset + x) * 8 + 7];
- vertexCount++;
+ for ( ; x < quadX2; x += 1) {
+ z += vertices[(yOffset + x) << 3 + 7];
+ vertexCount += 1;
}
}
- return 75.0f * z / vertexCount;
+ return 55.0f * z / vertexCount;
}
-void drawLeaf(int index, int frameCount, float* vertices, int meshWidth, int meshHeight,
+void drawLeaf(int index, float* vertices, int meshWidth, int meshHeight,
float glWidth, float glHeight) {
float *leafStruct = loadArrayF(RSID_LEAVES, index);
@@ -356,10 +331,10 @@
if (a > 0.0f) {
tz = -a;
} else {
- z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
- z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
- z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
- z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
}
x1 -= x;
@@ -383,12 +358,16 @@
if (a <= 0.0f) {
float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
if (rippled < 0.0f) {
- drop(((x + glWidth / 2.0f) / glWidth) * meshWidth,
- meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+ drop(((x + glWidth * 0.5f) / glWidth) * meshWidth,
+ meshHeight - ((y + glHeight * 0.5f) / glHeight) * meshHeight,
DROP_RADIUS);
spin /= 4.0f;
leafStruct[LEAF_STRUCT_SPIN] = spin;
leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
+ } else {
+// dropWithStrength(((x + glWidth / 2.0f) / glWidth) * meshWidth,
+// meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+// 2, 5);
}
leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
@@ -411,71 +390,129 @@
leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
leafStruct[LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
leafStruct[LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
- leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 100.0f;
- leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 100.0f;
+ leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 60.0f;
+ leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 60.0f;
}
}
-void drawLeaves(int frameCount) {
- bindProgramFragment(NAMED_PFLeaf);
+void drawLeaves() {
+ bindProgramFragment(NAMED_PFBackground);
bindProgramFragmentStore(NAMED_PFSLeaf);
- bindTexture(NAMED_PFLeaf, 0, NAMED_TLeaves);
+ bindProgramVertex(NAMED_PVSky);
+ bindTexture(NAMED_PFBackground, 0, NAMED_TLeaves);
- int leavesCount = loadI32(RSID_STATE, RSID_LEAVES_COUNT);
+ int leavesCount = State_leavesCount;
int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
- int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
- int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
- float glWidth = loadF(RSID_GL_STATE, RSID_GL_WIDTH);
- float glHeight = loadF(RSID_GL_STATE, RSID_GL_HEIGHT);
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ float glWidth = State_glWidth;
+ float glHeight = State_glHeight;
- float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
int i = 0;
for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
- drawLeaf(i, frameCount, vertices, width, height, glWidth, glHeight);
+ drawLeaf(i, vertices, width, height, glWidth, glHeight);
}
-}
-
-int main(int index) {
- int frameCount = loadI32(RSID_STATE, RSID_FRAME_COUNT);
-
- int dropX = loadI32(RSID_STATE, RSID_DROP_X);
- if (dropX != -1) {
- int dropY = loadI32(RSID_STATE, RSID_DROP_Y);
- drop(dropX, dropY, DROP_RADIUS);
- storeI32(RSID_STATE, RSID_DROP_X, -1);
- storeI32(RSID_STATE, RSID_DROP_Y, -1);
- }
-
- int isRunning = loadI32(RSID_STATE, RSID_RUNNING);
- if (isRunning) {
- updateRipples();
- generateRipples();
- updateTriangleMesh(NAMED_mesh);
- }
-
+
float matrix[16];
matrixLoadIdentity(matrix);
vpLoadModelMatrix(matrix);
+}
+void drawRiverbed() {
bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
- drawTriangleMesh(NAMED_mesh);
+ drawTriangleMesh(NAMED_WaterMesh);
+}
+
+void drawSky() {
+ color(1.0f, 1.0f, 1.0f, 0.8f);
+
+ bindProgramFragment(NAMED_PFSky);
+ bindProgramFragmentStore(NAMED_PFSLeaf);
+ bindTexture(NAMED_PFSky, 0, NAMED_TSky);
+
+ float x = State_skyOffsetX + State_skySpeedX;
+ float y = State_skyOffsetY + State_skySpeedY;
+
+ if (x > 1.0f) x = 0.0f;
+ if (x < -1.0f) x = 0.0f;
+ if (y > 1.0f) y = 0.0f;
+
+ storeF(RSID_STATE, OFFSETOF_WorldState_skyOffsetX, x);
+ storeF(RSID_STATE, OFFSETOF_WorldState_skyOffsetY, y);
+
+ float matrix[16];
+ matrixLoadTranslate(matrix, x, y, 0.0f);
+ vpLoadTextureMatrix(matrix);
+
+ drawTriangleMesh(NAMED_WaterMesh);
+
+ matrixLoadIdentity(matrix);
+ vpLoadTextureMatrix(matrix);
+}
+
+void drawLighting() {
ambient(0.0f, 0.0f, 0.0f, 1.0f);
diffuse(0.0f, 0.0f, 0.0f, 1.0f);
specular(0.44f, 0.44f, 0.44f, 1.0f);
shininess(40.0f);
+
+ bindProgramFragmentStore(NAMED_PFSBackground);
bindProgramFragment(NAMED_PFLighting);
- drawTriangleMesh(NAMED_mesh);
+ bindProgramVertex(NAMED_PVLight);
- drawLeaves(frameCount);
+ drawTriangleMesh(NAMED_WaterMesh);
+}
- if (!isRunning) {
- drawNormals();
+void drawNormals() {
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+ bindProgramVertex(NAMED_PVSky);
+ bindProgramFragment(NAMED_PFLighting);
+
+ color(1.0f, 0.0f, 0.0f, 1.0f);
+
+ float scale = 1.0f / 10.0f;
+ int y = 0;
+ for ( ; y < height; y += 1) {
+ int yOffset = y * width;
+ int x = 0;
+ for ( ; x < width; x += 1) {
+ int offset = (yOffset + x) << 3;
+ float vx = vertices[offset + 5];
+ float vy = vertices[offset + 6];
+ float vz = vertices[offset + 7];
+ float nx = vertices[offset + 0];
+ float ny = vertices[offset + 1];
+ float nz = vertices[offset + 2];
+ drawLine(vx, vy, vz, vx + nx * scale, vy + ny * scale, vz + nz * scale);
+ }
+ }
+}
+
+int main(int index) {
+ int dropX = Drop_dropX;
+ if (dropX != -1) {
+ int dropY = Drop_dropY;
+ drop(dropX, dropY, DROP_RADIUS);
+ storeI32(RSID_DROP, OFFSETOF_DropState_dropX, -1);
+ storeI32(RSID_DROP, OFFSETOF_DropState_dropY, -1);
}
- frameCount++;
- storeI32(RSID_STATE, RSID_FRAME_COUNT, frameCount);
+ updateRipples();
+ generateRipples();
+ updateTriangleMesh(NAMED_WaterMesh);
+
+ drawRiverbed();
+ drawSky();
+ drawLighting();
+ drawLeaves();
+ //drawNormals();
return 1;
}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
index 63e6ed9..8a33d66 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -26,8 +26,9 @@
import android.renderscript.Sampler;
import android.renderscript.Element;
import android.renderscript.Light;
+import android.renderscript.Type;
import static android.renderscript.Sampler.Value.LINEAR;
-import static android.renderscript.Sampler.Value.CLAMP;
+import static android.renderscript.Sampler.Value.WRAP;
import static android.renderscript.ProgramStore.DepthFunc.*;
import static android.renderscript.ProgramStore.BlendDstFunc;
import static android.renderscript.ProgramStore.BlendSrcFunc;
@@ -43,22 +44,12 @@
private static final int MESH_RESOLUTION = 48;
private static final int RSID_STATE = 0;
- private static final int RSID_STATE_FRAMECOUNT = 0;
- private static final int RSID_STATE_WIDTH = 1;
- private static final int RSID_STATE_HEIGHT = 2;
- private static final int RSID_STATE_MESH_WIDTH = 3;
- private static final int RSID_STATE_MESH_HEIGHT = 4;
- private static final int RSID_STATE_RIPPLE_MAP_SIZE = 5;
- private static final int RSID_STATE_RIPPLE_INDEX = 6;
- private static final int RSID_STATE_DROP_X = 7;
- private static final int RSID_STATE_DROP_Y = 8;
- private static final int RSID_STATE_RUNNING = 9;
- private static final int RSID_STATE_LEAVES_COUNT = 10;
-
- private static final int TEXTURES_COUNT = 2;
+
+ private static final int TEXTURES_COUNT = 3;
private static final int LEAVES_TEXTURES_COUNT = 4;
private static final int RSID_TEXTURE_RIVERBED = 0;
private static final int RSID_TEXTURE_LEAVES = 1;
+ private static final int RSID_TEXTURE_SKY = 2;
private static final int RSID_RIPPLE_MAP = 1;
@@ -79,12 +70,8 @@
private static final int LEAF_STRUCT_DELTAX = 9;
private static final int LEAF_STRUCT_DELTAY = 10;
- private static final int RSID_GL_STATE = 4;
- private static final int RSID_STATE_GL_WIDTH = 0;
- private static final int RSID_STATE_GL_HEIGHT = 1;
-
- private boolean mIsRunning = true;
-
+ private static final int RSID_DROP = 4;
+
private Resources mResources;
private RenderScript mRS;
@@ -93,30 +80,36 @@
private final int mWidth;
private final int mHeight;
- private ScriptC mScript;
- private Sampler mSampler;
+ @SuppressWarnings({"FieldCanBeLocal"})
private ProgramFragment mPfBackground;
+ @SuppressWarnings({"FieldCanBeLocal"})
private ProgramFragment mPfLighting;
- private ProgramFragment mPfLeaf;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramFragment mPfSky;
+ @SuppressWarnings({"FieldCanBeLocal"})
private ProgramStore mPfsBackground;
+ @SuppressWarnings({"FieldCanBeLocal"})
private ProgramStore mPfsLeaf;
- private ProgramVertex mPvBackground;
- private ProgramVertex mPvLines;
- private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
- private Light mLight;
-
- private Allocation[] mTextures;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramVertex mPvLight;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramVertex mPvSky;
private Allocation mState;
- private RenderScript.TriangleMesh mMesh;
+ private Allocation mDropState;
+ private DropState mDrop;
+ private Type mStateType;
+ private Type mDropType;
private int mMeshWidth;
+
private int mMeshHeight;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private RenderScript.TriangleMesh mMesh;
private Allocation mRippleMap;
private Allocation mRefractionMap;
- private Allocation mLeaves;
- private Allocation mGlState;
+ private Allocation mLeaves;
private float mGlHeight;
public FallRS(int width, int height) {
@@ -132,38 +125,6 @@
initRS();
}
- public void destroy() {
- mScript.destroy();
- mSampler.destroy();
- mPfBackground.destroy();
- mPfsBackground.destroy();
- mPvBackground.destroy();
- mPvOrthoAlloc.mAlloc.destroy();
- for (Allocation a : mTextures) {
- a.destroy();
- }
- mState.destroy();
- mMesh.destroy();
- mLight.destroy();
- mRippleMap.destroy();
- mRefractionMap.destroy();
- mPvLines.destroy();
- mPfLighting.destroy();
- mLeaves.destroy();
- mPfsLeaf.destroy();
- mPfLeaf.destroy();
- mGlState.destroy();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } finally {
- super.finalize();
- }
- }
-
private void initRS() {
createProgramVertex();
createProgramFragmentStore();
@@ -173,19 +134,22 @@
loadTextures();
ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setType(mStateType, "State", RSID_STATE);
+ sb.setType(mDropType, "Drop", RSID_DROP);
sb.setScript(mResources, R.raw.fall);
sb.setRoot(true);
- mScript = sb.create();
- mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- mScript.setTimeZone(TimeZone.getDefault().getID());
- mScript.bindAllocation(mState, RSID_STATE);
- mScript.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
- mScript.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
- mScript.bindAllocation(mLeaves, RSID_LEAVES);
- mScript.bindAllocation(mGlState, RSID_GL_STATE);
+ ScriptC script = sb.create();
+ script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ script.setTimeZone(TimeZone.getDefault().getID());
- mRS.contextBindRootScript(mScript);
+ script.bindAllocation(mState, RSID_STATE);
+ script.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
+ script.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
+ script.bindAllocation(mLeaves, RSID_LEAVES);
+ script.bindAllocation(mDropState, RSID_DROP);
+
+ mRS.contextBindRootScript(script);
}
private void createMesh() {
@@ -216,27 +180,42 @@
hResolution += 2;
for (int y = 0; y <= hResolution; y++) {
+ final boolean shift = (y & 0x1) == 0;
final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
final float t = 1.0f - y / (float) hResolution;
for (int x = 0; x <= wResolution; x++) {
- rs.triangleMeshAddVertex_XYZ_ST_NORM(
- -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
- x / (float) wResolution, t,
- 0.0f, 0.0f, -1.0f);
+ if (shift) {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(
+ -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
+ x / (float) wResolution, t,
+ 0.0f, 0.0f, -1.0f);
+ } else {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(
+ -1.0f + x * quadWidth - quadWidth * 0.5f, yOffset, 0.0f,
+ x / (float) wResolution, t,
+ 0.0f, 0.0f, -1.0f);
+ }
}
}
for (int y = 0; y < hResolution; y++) {
+ final boolean shift = (y & 0x1) == 0;
+ final int yOffset = y * (wResolution + 1);
for (int x = 0; x < wResolution; x++) {
- final int index = y * (wResolution + 1) + x;
+ final int index = yOffset + x;
final int iWR1 = index + wResolution + 1;
- rs.triangleMeshAddTriangle(index, index + 1, iWR1);
- rs.triangleMeshAddTriangle(index + 1, iWR1, iWR1 + 1);
+ if (shift) {
+ rs.triangleMeshAddTriangle(index, index + 1, iWR1);
+ rs.triangleMeshAddTriangle(index + 1, iWR1 + 1, iWR1);
+ } else {
+ rs.triangleMeshAddTriangle(index, iWR1 + 1, iWR1);
+ rs.triangleMeshAddTriangle(index, index + 1, iWR1 + 1);
+ }
}
}
mMesh = rs.triangleMeshCreate();
- mMesh.setName("mesh");
+ mMesh.setName("WaterMesh");
mMeshWidth = wResolution + 1;
mMeshHeight = hResolution + 1;
@@ -246,7 +225,6 @@
final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
createState(rippleMapSize);
- createGlState();
createRippleMap(rippleMapSize);
createRefractionMap();
createLeaves();
@@ -275,31 +253,56 @@
private void createRippleMap(int rippleMapSize) {
final int[] rippleMap = new int[rippleMapSize * 2];
mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+ mRippleMap.data(rippleMap);
}
- private void createGlState() {
- final float[] meshState = new float[2];
- mGlState = Allocation.createSized(mRS, USER_FLOAT, meshState.length);
- meshState[RSID_STATE_GL_WIDTH] = 2.0f;
- meshState[RSID_STATE_GL_HEIGHT] = mGlHeight;
- mGlState.data(meshState);
+ static class WorldState {
+ public int frameCount;
+ public int width;
+ public int height;
+ public int meshWidth;
+ public int meshHeight;
+ public int rippleMapSize;
+ public int rippleIndex;
+ public int leavesCount;
+ public float glWidth;
+ public float glHeight;
+ public float skyOffsetX;
+ public float skyOffsetY;
+ public float skySpeedX;
+ public float skySpeedY;
+ }
+
+ static class DropState {
+ public int dropX;
+ public int dropY;
}
private void createState(int rippleMapSize) {
- final int[] data = new int[11];
- mState = Allocation.createSized(mRS, USER_I32, data.length);
- data[RSID_STATE_FRAMECOUNT] = 0;
- data[RSID_STATE_WIDTH] = mWidth;
- data[RSID_STATE_HEIGHT] = mHeight;
- data[RSID_STATE_MESH_WIDTH] = mMeshWidth;
- data[RSID_STATE_MESH_HEIGHT] = mMeshHeight;
- data[RSID_STATE_RIPPLE_MAP_SIZE] = rippleMapSize;
- data[RSID_STATE_RIPPLE_INDEX] = 0;
- data[RSID_STATE_DROP_X] = -1;
- data[RSID_STATE_DROP_Y] = -1;
- data[RSID_STATE_RUNNING] = 1;
- data[RSID_STATE_LEAVES_COUNT] = LEAVES_COUNT;
- mState.data(data);
+ WorldState worldState = new WorldState();
+ worldState.width = mWidth;
+ worldState.height = mHeight;
+ worldState.meshWidth = mMeshWidth;
+ worldState.meshHeight = mMeshHeight;
+ worldState.rippleMapSize = rippleMapSize;
+ worldState.rippleIndex = 0;
+ worldState.leavesCount = LEAVES_COUNT;
+ worldState.glWidth = 2.0f;
+ worldState.glHeight = mGlHeight;
+ worldState.skySpeedX = random(-0.001f, 0.001f);
+ worldState.skySpeedY = random(0.00008f, 0.0002f);
+
+ mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
+ mState = Allocation.createTyped(mRS, mStateType);
+ mState.data(worldState);
+
+ mDrop = new DropState();
+ mDrop.dropX = -1;
+ mDrop.dropY = -1;
+
+ mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
+ mDropState = Allocation.createTyped(mRS, mDropType);
+ mDropState.data(mDrop);
}
private void createLeaf(float[] leaves, int index) {
@@ -314,16 +317,15 @@
leaves[index + LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
leaves[index + LEAF_STRUCT_ALTITUDE] = -1.0f;
leaves[index + LEAF_STRUCT_RIPPLED] = 1.0f;
- leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 100.0f;
- leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 100.0f;
+ leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 60.0f;
+ leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 60.0f;
}
private void loadTextures() {
- mTextures = new Allocation[TEXTURES_COUNT];
-
- final Allocation[] textures = mTextures;
+ final Allocation[] textures = new Allocation[TEXTURES_COUNT];
textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
+ textures[RSID_TEXTURE_SKY] = loadTextureARGB(R.drawable.sky, "TSky");
final int count = textures.length;
for (int i = 0; i < count; i++) {
@@ -350,36 +352,36 @@
Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
sampleBuilder.setMin(LINEAR);
sampleBuilder.setMag(LINEAR);
- sampleBuilder.setWrapS(CLAMP);
- sampleBuilder.setWrapT(CLAMP);
- mSampler = sampleBuilder.create();
+ sampleBuilder.setWrapS(WRAP);
+ sampleBuilder.setWrapT(WRAP);
+ Sampler sampler = sampleBuilder.create();
ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
builder.setTexEnable(true, 0);
builder.setTexEnvMode(REPLACE, 0);
mPfBackground = builder.create();
mPfBackground.setName("PFBackground");
- mPfBackground.bindSampler(mSampler, 0);
+ mPfBackground.bindSampler(sampler, 0);
builder = new ProgramFragment.Builder(mRS, null, null);
builder.setTexEnable(false, 0);
mPfLighting = builder.create();
mPfLighting.setName("PFLighting");
- mPfLighting.bindSampler(mSampler, 0);
+ mPfLighting.bindSampler(sampler, 0);
builder = new ProgramFragment.Builder(mRS, null, null);
builder.setTexEnable(true, 0);
- builder.setTexEnvMode(REPLACE, 0);
- mPfLeaf = builder.create();
- mPfLeaf.setName("PFLeaf");
- mPfLeaf.bindSampler(mSampler, 0);
+ builder.setTexEnvMode(MODULATE, 0);
+ mPfSky = builder.create();
+ mPfSky.setName("PFSky");
+ mPfSky.bindSampler(sampler, 0);
}
private void createProgramFragmentStore() {
ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
builder.setDepthFunc(ALWAYS);
builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
- builder.setDitherEnable(true);
+ builder.setDitherEnable(false);
builder.setDepthMask(true);
mPfsBackground = builder.create();
mPfsBackground.setName("PFSBackground");
@@ -387,40 +389,35 @@
builder = new ProgramStore.Builder(mRS, null, null);
builder.setDepthFunc(ALWAYS);
builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
- builder.setDitherEnable(true);
+ builder.setDitherEnable(false);
builder.setDepthMask(true);
mPfsLeaf = builder.create();
mPfsLeaf.setName("PFSLeaf");
}
private void createProgramVertex() {
- mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
- mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
+ ProgramVertex.MatrixAllocation pvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ pvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
- mLight = new Light.Builder(mRS).create();
- mLight.setPosition(0.0f, 2.0f, -8.0f);
+ Light light = new Light.Builder(mRS).create();
+ light.setPosition(0.0f, 2.0f, -8.0f);
ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
- builder.setTextureMatrixEnable(true);
- builder.addLight(mLight);
- mPvBackground = builder.create();
- mPvBackground.bindAllocation(mPvOrthoAlloc);
- mPvBackground.setName("PVBackground");
+ builder.addLight(light);
+ mPvLight = builder.create();
+ mPvLight.bindAllocation(pvOrthoAlloc);
+ mPvLight.setName("PVLight");
builder = new ProgramVertex.Builder(mRS, null, null);
- mPvLines = builder.create();
- mPvLines.bindAllocation(mPvOrthoAlloc);
- mPvLines.setName("PVLines");
+ builder.setTextureMatrixEnable(true);
+ mPvSky = builder.create();
+ mPvSky.bindAllocation(pvOrthoAlloc);
+ mPvSky.setName("PVSky");
}
void addDrop(float x, float y) {
- mState.subData1D(RSID_STATE_DROP_X, 2, new int[] {
- (int) ((x / mWidth) * mMeshWidth), (int) ((y / mHeight) * mMeshHeight)
- });
- }
-
- void togglePause() {
- mIsRunning = !mIsRunning;
- mState.subData1D(RSID_STATE_RUNNING, 1, new int[] { mIsRunning ? 1 : 0 });
+ mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
+ mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
+ mDropState.data(mDrop);
}
}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
index d7573be..7468d2b 100644
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
@@ -36,26 +36,12 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
- RenderScript RS = createRenderScript();
+ RenderScript RS = createRenderScript(false);
mRender = new FallRS(w, h);
mRender.init(RS, getResources());
}
@Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- if (mRender != null) mRender.destroy();
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
- keyCode == KeyEvent.KEYCODE_MENU) {
- mRender.togglePause();
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java
index 73b7414..1c5b2bc 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmView.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmView.java
@@ -52,7 +52,7 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
- mRS = createRenderScript();
+ mRS = createRenderScript(true);
mRender = new FilmRS();
mRender.init(mRS, getResources(), w, h);
}
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index 6e6afcd..8c1cad4 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -1,86 +1,51 @@
// Fountain test script
-
#pragma version(1)
#pragma stateVertex(default)
-#pragma stateFragment(PgmFragParts)
-#pragma stateFragmentStore(PFSBlend)
-
+#pragma stateFragment(default)
+#pragma stateFragmentStore(default)
int main(int launchID) {
int ct;
- int count = loadI32(0, OFFSETOF_SomeData_count);
- int touch = loadI32(0, OFFSETOF_SomeData_touch);
- int rate = 4;
- int maxLife = (count / rate) - 1;
+ int count = Control_count - 1;
+ int rate = Control_rate;
+ float *dataF = loadArrayF(1, 0);
+ float height = getHeight();
- if (touch) {
- int x = loadI32(0, OFFSETOF_SomeData_x);
- int y = loadI32(0, OFFSETOF_SomeData_y);
- int newPart = loadI32(2, 0);
- for (ct=0; ct<rate; ct++) {
- int idx = newPart * 5 + 1;
- storeF(2, idx, randf(1.f) - 0.5f);
- storeF(2, idx + 1, randf(1.f) - 0.5f);
- storeI32(2, idx + 2, maxLife);
- storeF(2, idx + 3, x);
- storeF(2, idx + 4, y);
+ if (rate) {
+ int *dataI = loadArrayI32(1, 0);
+ float rMax = ((float)rate) * 0.005f;
+ int x = Control_x;
+ int y = Control_y;
+ int newPart = loadI32(1, count * 5);
+ int c = colorFloatRGBAtoUNorm8(Control_r, Control_g, Control_b, 0.99f);
+
+ while (rate--) {
+ int idx = newPart * 5;
+ vec2Rand(dataF + idx, rMax);
+ dataF[idx + 2] = x;
+ dataF[idx + 3] = y;
+ dataI[idx + 4] = c;
newPart++;
if (newPart >= count) {
newPart = 0;
}
}
- storeI32(2, 0, newPart);
+ storeI32(1, count * 5, newPart);
}
- int drawCount = 0;
- float height = getHeight();
for (ct=0; ct < count; ct++) {
- int srcIdx = ct * 5 + 1;
-
- int life = loadI32(2, srcIdx + 2);
-
- if (life) {
- float posx = loadF(2, srcIdx + 3);
- float posy = loadF(2, srcIdx + 4);
- float dx = loadF(2, srcIdx);
- float dy = loadF(2, srcIdx + 1);
- if (posy < height) {
- int dstIdx = drawCount * 9;
- int c = 0xcfcfcfcf;
-
- storeI32(1, dstIdx, c);
- storeF(1, dstIdx + 1, posx);
- storeF(1, dstIdx + 2, posy);
-
- storeI32(1, dstIdx + 3, c);
- storeF(1, dstIdx + 4, posx + 1.f);
- storeF(1, dstIdx + 5, posy + dy);
-
- storeI32(1, dstIdx + 6, c);
- storeF(1, dstIdx + 7, posx - 1.f);
- storeF(1, dstIdx + 8, posy + dy);
- drawCount ++;
- } else {
- if (dy > 0) {
- dy *= -0.5f;
- }
- }
-
- posx = posx + dx;
- posy = posy + dy;
- dy = dy + 0.05f;
- life --;
-
- //storeI32(2, srcIdx, dx);
- storeF(2, srcIdx + 1, dy);
- storeI32(2, srcIdx + 2, life);
- storeF(2, srcIdx + 3, posx);
- storeF(2, srcIdx + 4, posy);
+ float dy = dataF[1] + 0.15f;
+ float posy = dataF[3] + dy;
+ if ((posy > height) && (dy > 0)) {
+ dy *= -0.3f;
}
+ dataF[1] = dy;
+ dataF[2] += dataF[0];
+ dataF[3] = posy;
+ dataF += 5;
}
- //drawTriangleArray(NAMED_PartBuffer, drawCount);
uploadToBufferObject(NAMED_PartBuffer);
- drawSimpleMeshRange(NAMED_PartMesh, 0, drawCount * 3);
+ drawSimpleMeshRange(NAMED_PartMesh, 0, count);
return 1;
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index da4eeb4..6d400c5 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -16,26 +16,22 @@
package com.android.fountain;
-import java.io.Writer;
-
-import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.renderscript.*;
import android.util.Log;
public class FountainRS {
- public static final int PART_COUNT = 4000;
+ public static final int PART_COUNT = 20000;
static class SomeData {
public int x;
public int y;
- public int touch;
public int rate;
public int count;
+ public float r;
+ public float g;
+ public float b;
}
public FountainRS() {
@@ -47,8 +43,18 @@
initRS();
}
- public void newTouchPosition(int x, int y) {
- mSD.touch = 1;
+ public void newTouchPosition(int x, int y, int rate) {
+ if (mSD.rate == 0) {
+ mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f;
+ mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f;
+ mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f;
+ if ((mSD.r + mSD.g + mSD.b) < 0.9f) {
+ mSD.r = 0.8f;
+ mSD.g = 0.5f;
+ mSD.b = 1.f;
+ }
+ }
+ mSD.rate = rate;
mSD.x = x;
mSD.y = y;
mIntAlloc.data(mSD);
@@ -61,71 +67,47 @@
private RenderScript mRS;
private Allocation mIntAlloc;
- private Allocation mPartAlloc;
- private Allocation mVertAlloc;
- private Script mScript;
- private ProgramStore mPFS;
- private ProgramFragment mPF;
private SimpleMesh mSM;
-
- private Bitmap mBackground;
-
- SomeData mSD = new SomeData();
+ private SomeData mSD;
private Type mSDType;
private void initRS() {
mSD = new SomeData();
mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData");
mIntAlloc = Allocation.createTyped(mRS, mSDType);
- mVertAlloc = Allocation.createSized(mRS, Element.USER_I32, PART_COUNT * 5 + 1);
-
- ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null);
- bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE);
- bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
- bs.setDepthMask(false);
- bs.setDitherEnable(false);
- mPFS = bs.create();
- mPFS.setName("PFSBlend");
-
- ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null);
- mPF = bf.create();
- mPF.setName("PgmFragParts");
-
mSD.count = PART_COUNT;
mIntAlloc.data(mSD);
Element.Builder eb = new Element.Builder(mRS);
- eb.add(Element.DataType.UNSIGNED, Element.DataKind.RED, true, 8);
- eb.add(Element.DataType.UNSIGNED, Element.DataKind.GREEN, true, 8);
- eb.add(Element.DataType.UNSIGNED, Element.DataKind.BLUE, true, 8);
- eb.add(Element.DataType.UNSIGNED, Element.DataKind.ALPHA, true, 8);
- eb.add(Element.DataType.FLOAT, Element.DataKind.X, false, 32);
- eb.add(Element.DataType.FLOAT, Element.DataKind.Y, false, 32);
+ eb.addFloat(Element.DataKind.USER); //dx
+ eb.addFloat(Element.DataKind.USER); //dy
+ eb.addFloatXY();
+ eb.addUNorm8RGBA();
Element primElement = eb.create();
+
SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
- int vtxSlot = smb.addVertexType(primElement, PART_COUNT * 3);
- smb.setPrimitive(Primitive.TRIANGLE);
+ int vtxSlot = smb.addVertexType(primElement, PART_COUNT);
+ smb.setPrimitive(Primitive.POINT);
mSM = smb.create();
mSM.setName("PartMesh");
- mPartAlloc = mSM.createVertexAllocation(vtxSlot);
- mPartAlloc.setName("PartBuffer");
- mSM.bindVertexAllocation(mPartAlloc, 0);
+ Allocation partAlloc = mSM.createVertexAllocation(vtxSlot);
+ partAlloc.setName("PartBuffer");
+ mSM.bindVertexAllocation(partAlloc, 0);
// All setup of named objects should be done by this point
// because we are about to compile the script.
ScriptC.Builder sb = new ScriptC.Builder(mRS);
sb.setScript(mRes, R.raw.fountain);
sb.setRoot(true);
- sb.setType(mSDType, 0);
- mScript = sb.create();
- mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ sb.setType(mSDType, "Control", 0);
+ Script script = sb.create();
+ script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- mScript.bindAllocation(mIntAlloc, 0);
- mScript.bindAllocation(mPartAlloc, 1);
- mScript.bindAllocation(mVertAlloc, 2);
- mRS.contextBindRootScript(mScript);
+ script.bindAllocation(mIntAlloc, 0);
+ script.bindAllocation(partAlloc, 1);
+ mRS.contextBindRootScript(script);
}
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
index be8b24e..7826161 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -52,7 +52,7 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
- mRS = createRenderScript();
+ mRS = createRenderScript(false);
mRender = new FountainRS();
mRender.init(mRS, getResources(), w, h);
}
@@ -61,13 +61,18 @@
@Override
public boolean onTouchEvent(MotionEvent ev)
{
- boolean ret = true;
int act = ev.getAction();
if (act == ev.ACTION_UP) {
- ret = false;
+ mRender.newTouchPosition(0, 0, 0);
+ return false;
}
- mRender.newTouchPosition((int)ev.getX(), (int)ev.getY());
- return ret;
+ float rate = (ev.getPressure() * 50.f);
+ rate *= rate;
+ if(rate > 2000.f) {
+ rate = 2000.f;
+ }
+ mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate);
+ return true;
}
}
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
index 3e1c54d..7524a0e 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -54,7 +54,7 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
- mRS = createRenderScript();
+ mRS = createRenderScript(false);
mRender = new RolloRS();
mRender.init(mRS, getResources(), w, h);
}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 105142b..e275f27 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -32,6 +32,10 @@
param size_t len
}
+ObjDestroy {
+ param void *obj
+ }
+
ElementBegin {
}
@@ -56,10 +60,6 @@
ret RsElement
}
-ElementDestroy {
- param RsElement ve
- }
-
TypeBegin {
param RsElement type
}
@@ -73,10 +73,6 @@
ret RsType
}
-TypeDestroy {
- param RsType p
- }
-
AllocationCreateTyped {
param RsType type
ret RsAllocation
@@ -130,10 +126,6 @@
param RsAllocation alloc
}
-AllocationDestroy {
- param RsAllocation alloc
- }
-
AllocationData {
param RsAllocation va
@@ -170,10 +162,6 @@
param RsAllocation alloc
}
-Adapter1DDestroy {
- param RsAdapter1D adapter
- }
-
Adapter1DSetConstraint {
param RsAdapter1D adapter
param RsDimension dim
@@ -201,10 +189,6 @@
param RsAllocation alloc
}
-Adapter2DDestroy {
- param RsAdapter2D adapter
- }
-
Adapter2DSetConstraint {
param RsAdapter2D adapter
param RsDimension dim
@@ -237,9 +221,6 @@
ret RsSampler
}
-SamplerDestroy {
- param RsSampler s
- }
TriangleMeshBegin {
param RsElement vertex
@@ -260,9 +241,6 @@
ret RsTriangleMesh
}
-TriangleMeshDestroy {
- param RsTriangleMesh mesh
- }
TriangleMeshRender {
param RsTriangleMesh vtm
@@ -274,9 +252,6 @@
param uint32_t count
}
-ScriptDestroy {
- param RsScript script
- }
ScriptBindAllocation {
param RsScript vtm
@@ -315,6 +290,7 @@
ScriptSetType {
param RsType type
param uint32_t slot
+ param bool isWritable
param const char * name
}
@@ -380,14 +356,12 @@
ret RsProgramFragmentStore
}
-ProgramFragmentStoreDestroy {
- param RsProgramFragmentStore pfs
- }
ProgramFragmentBegin {
param RsElement in
param RsElement out
+ param bool pointSpriteEnable
}
ProgramFragmentBindTexture {
@@ -402,29 +376,17 @@
param RsSampler s
}
-ProgramFragmentSetType {
- param uint32_t slot
- param RsType t
- }
-
-ProgramFragmentSetEnvMode {
- param uint32_t slot
- param RsTexEnvMode env
- }
-
-ProgramFragmentSetTexEnable {
+ProgramFragmentSetSlot {
param uint32_t slot
param bool enable
+ param RsTexEnvMode env
+ param RsType t
}
ProgramFragmentCreate {
ret RsProgramFragment
}
-ProgramFragmentDestroy {
- param RsProgramFragment pf
- }
-
ProgramVertexBegin {
param RsElement in
@@ -463,9 +425,6 @@
ret RsLight light
}
-LightDestroy {
- param RsLight light
- }
LightSetPosition {
param RsLight light
@@ -497,9 +456,6 @@
param uint32_t primType
}
-SimpleMeshDestroy {
- param RsSimpleMesh mesh
- }
SimpleMeshBindIndex {
param RsSimpleMesh mesh
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
index 25f3340..3242e11 100644
--- a/libs/rs/rsAdapter.cpp
+++ b/libs/rs/rsAdapter.cpp
@@ -76,12 +76,6 @@
return a;
}
-void rsi_Adapter1DDestroy(Context *rsc, RsAdapter1D va)
-{
- Adapter1D * a = static_cast<Adapter1D *>(va);
- a->decRef();
-}
-
void rsi_Adapter1DBindAllocation(Context *rsc, RsAdapter1D va, RsAllocation valloc)
{
Adapter1D * a = static_cast<Adapter1D *>(va);
@@ -195,12 +189,6 @@
return a;
}
-void rsi_Adapter2DDestroy(Context *rsc, RsAdapter2D va)
-{
- Adapter2D * a = static_cast<Adapter2D *>(va);
- a->decRef();
-}
-
void rsi_Adapter2DBindAllocation(Context *rsc, RsAdapter2D va, RsAllocation valloc)
{
Adapter2D * a = static_cast<Adapter2D *>(va);
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index ad9c739..3cb76bc 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -201,10 +201,6 @@
alloc->uploadToBufferObject();
}
-void rsi_AllocationDestroy(Context *rsc, RsAllocation)
-{
-}
-
static void mip565(const Adapter2D &out, const Adapter2D &in)
{
uint32_t w = out.getDimX();
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index b88710c..4a043f3 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -24,7 +24,7 @@
Component::Component()
{
mType = FLOAT;
- mKind = NONE;
+ mKind = USER;
mIsNormalized = false;
mBits = 0;
}
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
index 6342f1b..5856524 100644
--- a/libs/rs/rsComponent.h
+++ b/libs/rs/rsComponent.h
@@ -34,13 +34,13 @@
};
enum DataKind {
- NONE,
+ USER,
RED, GREEN, BLUE, ALPHA, LUMINANCE, INTENSITY,
X, Y, Z, W,
S, T, Q, R,
NX, NY, NZ,
INDEX,
- USER
+ POINT_SIZE
};
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 2860452..52c2b78 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -18,6 +18,7 @@
#include "rsContext.h"
#include "rsThreadIO.h"
#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -25,46 +26,67 @@
using namespace android;
using namespace android::renderscript;
-Context * Context::gCon = NULL;
pthread_key_t Context::gThreadTLSKey = 0;
void Context::initEGL()
{
- mNumConfigs = -1;
+ mEGL.mNumConfigs = -1;
+ EGLint configAttribs[128];
+ EGLint *configAttribsPtr = configAttribs;
- EGLint s_configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-#if 1
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
-#else
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
-#endif
- EGL_DEPTH_SIZE, 16,
- EGL_NONE
- };
+ memset(configAttribs, 0, sizeof(configAttribs));
- mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion);
- eglChooseConfig(mDisplay, s_configAttribs, &mConfig, 1, &mNumConfigs);
+ configAttribsPtr[0] = EGL_SURFACE_TYPE;
+ configAttribsPtr[1] = EGL_WINDOW_BIT;
+ configAttribsPtr += 2;
- if (mWndSurface) {
- mSurface = eglCreateWindowSurface(mDisplay, mConfig, mWndSurface,
- NULL);
- } else {
- mSurface = eglCreateWindowSurface(mDisplay, mConfig,
- android_createDisplaySurface(),
- NULL);
- }
+ if (mUseDepth) {
+ configAttribsPtr[0] = EGL_DEPTH_SIZE;
+ configAttribsPtr[1] = 16;
+ configAttribsPtr += 2;
+ }
+ configAttribsPtr[0] = EGL_NONE;
+ rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
- mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL);
- eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
- eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mWidth);
- eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mHeight);
+ mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig);
+ if (err) {
+ LOGE("couldn't find an EGLConfig matching the screen format\n");
+ }
+ //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs);
+
+ if (mWndSurface) {
+ mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL);
+ } else {
+ mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig,
+ android_createDisplaySurface(),
+ NULL);
+ }
+
+ mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL);
+ eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+ eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
+ eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
+
+
+ mGL.mVersion = glGetString(GL_VERSION);
+ mGL.mVendor = glGetString(GL_VENDOR);
+ mGL.mRenderer = glGetString(GL_RENDERER);
+ mGL.mExtensions = glGetString(GL_EXTENSIONS);
+
+ //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
+ //LOGV("GL Version %s", mGL.mVersion);
+ //LOGV("GL Vendor %s", mGL.mVendor);
+ //LOGV("GL Renderer %s", mGL.mRenderer);
+ //LOGV("GL Extensions %s", mGL.mExtensions);
+
+ if ((strlen((const char *)mGL.mVersion) < 12) || memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) {
+ LOGE("Error, OpenGL ES Lite not supported");
+ } else {
+ sscanf((const char *)mGL.mVersion + 13, "%i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion);
+ }
}
bool Context::runScript(Script *s, uint32_t launchID)
@@ -85,55 +107,87 @@
bool Context::runRootScript()
{
#if RS_LOG_TIMES
- struct timespec beginTime;
- clock_gettime(CLOCK_MONOTONIC, &beginTime);
+ timerSet(RS_TIMER_CLEAR_SWAP);
#endif
-
rsAssert(mRootScript->mEnviroment.mIsRoot);
//glColor4f(1,1,1,1);
//glEnable(GL_LIGHT0);
- glViewport(0, 0, mWidth, mHeight);
-
- glDepthMask(GL_TRUE);
+ glViewport(0, 0, mEGL.mWidth, mEGL.mHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(mRootScript->mEnviroment.mClearColor[0],
mRootScript->mEnviroment.mClearColor[1],
mRootScript->mEnviroment.mClearColor[2],
mRootScript->mEnviroment.mClearColor[3]);
- glClearDepthf(mRootScript->mEnviroment.mClearDepth);
- glClear(GL_COLOR_BUFFER_BIT);
- glClear(GL_DEPTH_BUFFER_BIT);
+ if (mUseDepth) {
+ glDepthMask(GL_TRUE);
+ glClearDepthf(mRootScript->mEnviroment.mClearDepth);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ } else {
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
#if RS_LOG_TIMES
- struct timespec startTime;
- clock_gettime(CLOCK_MONOTONIC, &startTime);
+ timerSet(RS_TIMER_SCRIPT);
#endif
bool ret = runScript(mRootScript.get(), 0);
-
-#if RS_LOG_TIMES
- struct timespec endTime;
- clock_gettime(CLOCK_MONOTONIC, &endTime);
-
- int t1 = ((unsigned long)startTime.tv_nsec - (unsigned long)beginTime.tv_nsec) / 1000 / 1000;
- int t2 = ((unsigned long)endTime.tv_nsec - (unsigned long)startTime.tv_nsec) / 1000 / 1000;
- LOGE("times %i, %i", t1, t2);
-#endif
-
return ret;
}
+uint64_t Context::getTime() const
+{
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+void Context::timerReset()
+{
+ for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) {
+ mTimers[ct] = 0;
+ }
+}
+
+void Context::timerInit()
+{
+ mTimeLast = getTime();
+ mTimerActive = RS_TIMER_INTERNAL;
+ timerReset();
+}
+
+void Context::timerSet(Timers tm)
+{
+ uint64_t last = mTimeLast;
+ mTimeLast = getTime();
+ mTimers[mTimerActive] += mTimeLast - last;
+ mTimerActive = tm;
+}
+
+void Context::timerPrint()
+{
+ double total = 0;
+ for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) {
+ total += mTimers[ct];
+ }
+
+ LOGV("RS Time Data: Idle %2.1f (%lli), Internal %2.1f (%lli), Script %2.1f (%lli), Clear & Swap %2.1f (%lli)",
+ 100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
+ 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000,
+ 100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000,
+ 100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimers[RS_TIMER_CLEAR_SWAP] / 1000000);
+}
+
void Context::setupCheck()
{
if (mFragmentStore.get()) {
- mFragmentStore->setupGL(&mStateFragmentStore);
+ mFragmentStore->setupGL(this, &mStateFragmentStore);
}
if (mFragment.get()) {
- mFragment->setupGL(&mStateFragment);
+ mFragment->setupGL(this, &mStateFragment);
}
if (mVertex.get()) {
- mVertex->setupGL(&mStateVertex);
+ mVertex->setupGL(this, &mStateVertex);
}
}
@@ -143,7 +197,6 @@
{
Context *rsc = static_cast<Context *>(vrsc);
- gIO = new ThreadIO();
rsc->initEGL();
ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
@@ -158,41 +211,53 @@
LOGE("pthread_setspecific %i", status);
}
- rsc->mStateVertex.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
rsc->setVertex(NULL);
- rsc->mStateFragment.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
rsc->setFragment(NULL);
- rsc->mStateFragmentStore.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
rsc->setFragmentStore(NULL);
rsc->mRunning = true;
bool mDraw = true;
while (!rsc->mExit) {
- mDraw |= gIO->playCoreCommands(rsc, !mDraw);
+ mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw);
mDraw &= (rsc->mRootScript.get() != NULL);
if (mDraw) {
mDraw = rsc->runRootScript();
- eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+#if RS_LOG_TIMES
+ rsc->timerSet(RS_TIMER_CLEAR_SWAP);
+#endif
+ eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
+#if RS_LOG_TIMES
+ rsc->timerSet(RS_TIMER_INTERNAL);
+ rsc->timerPrint();
+ rsc->timerReset();
+#endif
+ }
+ if (rsc->mObjDestroy.mNeedToEmpty) {
+ rsc->objDestroyOOBRun();
}
}
+ LOGV("RS Thread exiting");
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
- eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
- eglTerminate(rsc->mDisplay);
+ eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
+ eglTerminate(rsc->mEGL.mDisplay);
+ rsc->objDestroyOOBRun();
+ LOGV("RS Thread exited");
return NULL;
}
-Context::Context(Device *dev, Surface *sur)
+Context::Context(Device *dev, Surface *sur, bool useDepth)
{
dev->addContext(this);
mDev = dev;
mRunning = false;
mExit = false;
-
- // see comment in header
- gCon = this;
+ mUseDepth = useDepth;
int status;
pthread_attr_t threadAttr;
@@ -215,6 +280,9 @@
mWndSurface = sur;
+ objDestroyOOBInit();
+ timerInit();
+
LOGV("RS Launching thread");
status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
if (status) {
@@ -230,26 +298,20 @@
Context::~Context()
{
+ LOGV("Context::~Context");
mExit = true;
void *res;
+ mIO.shutdown();
int status = pthread_join(mThreadId, &res);
+ objDestroyOOBRun();
if (mDev) {
mDev->removeContext(this);
pthread_key_delete(gThreadTLSKey);
}
-}
-void Context::swapBuffers()
-{
- eglSwapBuffers(mDisplay, mSurface);
-}
-
-void rsContextSwap(RsContext vrsc)
-{
- Context *rsc = static_cast<Context *>(vrsc);
- rsc->swapBuffers();
+ objDestroyOOBDestroy();
}
void Context::setRootScript(Script *s)
@@ -350,6 +412,62 @@
}
}
+bool Context::objDestroyOOBInit()
+{
+ int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBInit mutex init failure");
+ return false;
+ }
+ return true;
+}
+
+void Context::objDestroyOOBRun()
+{
+ if (mObjDestroy.mNeedToEmpty) {
+ int status = pthread_mutex_lock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ return;
+ }
+
+ for (size_t ct = 0; ct < mObjDestroy.mDestroyList.size(); ct++) {
+ mObjDestroy.mDestroyList[ct]->decRef();
+ }
+ mObjDestroy.mDestroyList.clear();
+ mObjDestroy.mNeedToEmpty = false;
+
+ status = pthread_mutex_unlock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
+ }
+ }
+}
+
+void Context::objDestroyOOBDestroy()
+{
+ rsAssert(!mObjDestroy.mNeedToEmpty);
+ pthread_mutex_destroy(&mObjDestroy.mMutex);
+}
+
+void Context::objDestroyAdd(ObjectBase *obj)
+{
+ int status = pthread_mutex_lock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ return;
+ }
+
+ mObjDestroy.mNeedToEmpty = true;
+ mObjDestroy.mDestroyList.add(obj);
+
+ status = pthread_mutex_unlock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
+ }
+}
+
+
///////////////////////////////////////////////////////////////////////////////////////////
//
@@ -400,6 +518,13 @@
rsc->assignName(ob, name, len);
}
+void rsi_ObjDestroy(Context *rsc, void *obj)
+{
+ ObjectBase *ob = static_cast<ObjectBase *>(obj);
+ rsc->removeName(ob);
+ ob->decRef();
+}
+
void rsi_ContextSetDefineF(Context *rsc, const char* name, float value)
{
rsc->addInt32Define(name, value);
@@ -414,10 +539,10 @@
}
-RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version)
+RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version, bool useDepth)
{
Device * dev = static_cast<Device *>(vdev);
- Context *rsc = new Context(dev, (Surface *)sur);
+ Context *rsc = new Context(dev, (Surface *)sur, useDepth);
return rsc;
}
@@ -427,3 +552,9 @@
delete rsc;
}
+void rsObjDestroyOOB(RsContext vrsc, void *obj)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ rsc->objDestroyAdd(static_cast<ObjectBase *>(obj));
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 60a526b..c58a88c 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -21,6 +21,7 @@
#include <ui/Surface.h>
+#include "rsThreadIO.h"
#include "rsType.h"
#include "rsMatrix.h"
#include "rsAllocation.h"
@@ -48,7 +49,7 @@
class Context
{
public:
- Context(Device *, Surface *);
+ Context(Device *, Surface *, bool useDepth);
~Context();
static pthread_key_t gThreadTLSKey;
@@ -71,8 +72,6 @@
ScriptCState mScriptC;
- static Context * getContext() {return gCon;}
-
void swapBuffers();
void setRootScript(Script *);
void setVertex(ProgramVertex *);
@@ -112,24 +111,59 @@
mFloatDefines.add(String8(name), value);
}
- uint32_t getWidth() const {return mWidth;}
- uint32_t getHeight() const {return mHeight;}
+ uint32_t getWidth() const {return mEGL.mWidth;}
+ uint32_t getHeight() const {return mEGL.mHeight;}
+
+
+ ThreadIO mIO;
+ void objDestroyAdd(ObjectBase *);
+
+ // Timers
+ enum Timers {
+ RS_TIMER_IDLE,
+ RS_TIMER_INTERNAL,
+ RS_TIMER_SCRIPT,
+ RS_TIMER_CLEAR_SWAP,
+ _RS_TIMER_TOTAL
+ };
+ uint64_t getTime() const;
+ void timerInit();
+ void timerReset();
+ void timerSet(Timers);
+ void timerPrint();
+
+ bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); }
+ bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; }
protected:
Device *mDev;
- EGLint mNumConfigs;
- EGLint mMajorVersion;
- EGLint mMinorVersion;
- EGLConfig mConfig;
- EGLContext mContext;
- EGLSurface mSurface;
- EGLint mWidth;
- EGLint mHeight;
- EGLDisplay mDisplay;
+ struct {
+ EGLint mNumConfigs;
+ EGLint mMajorVersion;
+ EGLint mMinorVersion;
+ EGLConfig mConfig;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLDisplay mDisplay;
+ } mEGL;
+
+ struct {
+ const uint8_t * mVendor;
+ const uint8_t * mRenderer;
+ const uint8_t * mVersion;
+ const uint8_t * mExtensions;
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+
+ } mGL;
bool mRunning;
bool mExit;
+ bool mUseDepth;
pthread_t mThreadId;
@@ -138,6 +172,17 @@
ObjectBaseRef<ProgramVertex> mVertex;
ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+ struct ObjDestroyOOB {
+ pthread_mutex_t mMutex;
+ Vector<ObjectBase *> mDestroyList;
+ bool mNeedToEmpty;
+ };
+ ObjDestroyOOB mObjDestroy;
+ bool objDestroyOOBInit();
+ void objDestroyOOBRun();
+ void objDestroyOOBDestroy();
+
private:
Context();
@@ -148,13 +193,15 @@
static void * threadProc(void *);
- // todo: put in TLS
- static Context *gCon;
Surface *mWndSurface;
Vector<ObjectBase *> mNames;
KeyedVector<String8,int> mInt32Defines;
KeyedVector<String8,float> mFloatDefines;
+
+ uint64_t mTimers[_RS_TIMER_TOTAL];
+ Timers mTimerActive;
+ uint64_t mTimeLast;
};
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 97b18c0..389b2c0 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -416,12 +416,6 @@
return se;
}
-void rsi_ElementDestroy(Context *rsc, RsElement vse)
-{
- Element * se = static_cast<Element *>(vse);
- se->decRef();
-}
-
}
}
diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp
index 24b58b6..f780e52 100644
--- a/libs/rs/rsLight.cpp
+++ b/libs/rs/rsLight.cpp
@@ -82,7 +82,7 @@
////////////////////////////////////////////////////
-//
+//
namespace android {
namespace renderscript {
@@ -110,12 +110,6 @@
return l;
}
-void rsi_LightDestroy(Context *rsc, RsLight vl)
-{
- Light *l = static_cast<Light *>(vl);
- l->decRef();
-}
-
void rsi_LightSetColor(Context *rsc, RsLight vl, float r, float g, float b)
{
Light *l = static_cast<Light *>(vl);
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index c3fee54..0c403895 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -25,6 +25,16 @@
LocklessCommandFifo::~LocklessCommandFifo()
{
+ if (!mInShutdown) {
+ shutdown();
+ }
+ free(mBuffer);
+}
+
+void LocklessCommandFifo::shutdown()
+{
+ mInShutdown = true;
+ mSignalToWorker.set();
}
bool LocklessCommandFifo::init(uint32_t sizeInBytes)
@@ -42,6 +52,7 @@
return false;
}
+ mInShutdown = false;
mSize = sizeInBytes;
mPut = mBuffer;
mGet = mBuffer;
@@ -50,7 +61,7 @@
return true;
}
-uint32_t LocklessCommandFifo::getFreeSpace() const
+uint32_t LocklessCommandFifo::getFreeSpace() const
{
int32_t freeSpace = 0;
//dumpState("getFreeSpace");
@@ -115,7 +126,7 @@
{
while(1) {
//dumpState("get");
- while(isEmpty()) {
+ while(isEmpty() && !mInShutdown) {
mSignalToControl.set();
mSignalToWorker.wait();
}
@@ -126,7 +137,7 @@
// non-zero command is valid
return mGet+4;
}
-
+
// zero command means reset to beginning.
mGet = mBuffer;
}
@@ -161,7 +172,7 @@
while(getFreeSpace() < bytes) {
sleep(1);
}
-
+
}
void LocklessCommandFifo::dumpState(const char *s) const
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index abeddf7..d0a4356 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -25,13 +25,14 @@
// A simple FIFO to be used as a producer / consumer between two
// threads. One is writer and one is reader. The common cases
-// will not require locking. It is not threadsafe for multiple
+// will not require locking. It is not threadsafe for multiple
// readers or writers by design.
-class LocklessCommandFifo
+class LocklessCommandFifo
{
public:
bool init(uint32_t size);
+ void shutdown();
LocklessCommandFifo();
~LocklessCommandFifo();
@@ -59,6 +60,7 @@
uint8_t * mBuffer;
uint8_t * mEnd;
uint8_t mSize;
+ bool mInShutdown;
Signal mSignalToWorker;
Signal mSignalToControl;
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 6a5b7d8..07bbc1e 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -43,6 +43,11 @@
mRefCount --;
//LOGV("ObjectBase %p dec ref %i", this, mRefCount);
if (!mRefCount) {
+ if (mName) {
+ LOGV("Deleting RS object %p, name %s", this, mName);
+ } else {
+ LOGV("Deleting RS object %p, no name", this);
+ }
delete this;
}
}
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 6606daa..18eacfb 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -47,9 +47,3 @@
}
}
-void Program::setupGL()
-{
-
-}
-
-
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index 251072f..bb3d9ac 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -32,11 +32,7 @@
Program(Element *in, Element *out);
virtual ~Program();
-
void bindAllocation(Allocation *);
-
- virtual void setupGL();
-
void checkUpdatedAllocation(const Allocation *);
protected:
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index a315658..654974f 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -24,7 +24,7 @@
using namespace android::renderscript;
-ProgramFragment::ProgramFragment(Element *in, Element *out) :
+ProgramFragment::ProgramFragment(Element *in, Element *out, bool pointSpriteEnable) :
Program(in, out)
{
for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
@@ -32,6 +32,7 @@
mTextureDimensions[ct] = 2;
}
mTextureEnableMask = 0;
+ mPointSpriteEnable = pointSpriteEnable;
mEnvModes[1] = RS_TEX_ENV_MODE_DECAL;
}
@@ -39,7 +40,7 @@
{
}
-void ProgramFragment::setupGL(ProgramFragmentState *state)
+void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state)
{
if ((state->mLast.get() == this) && !mDirty) {
return;
@@ -54,6 +55,9 @@
}
glEnable(GL_TEXTURE_2D);
+ if (rsc->checkVersion1_1()) {
+ glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable);
+ }
glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
switch(mEnvModes[ct]) {
@@ -94,7 +98,6 @@
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
}
}
-
glActiveTexture(GL_TEXTURE0);
mDirty = false;
}
@@ -178,7 +181,7 @@
void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
{
- ProgramFragment *pf = new ProgramFragment(NULL, NULL);
+ ProgramFragment *pf = new ProgramFragment(NULL, NULL, false);
mDefault.set(pf);
}
@@ -186,10 +189,10 @@
namespace android {
namespace renderscript {
-void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out)
+void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out, bool pointSpriteEnable)
{
delete rsc->mStateFragment.mPF;
- rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out);
+ rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out, pointSpriteEnable);
}
void rsi_ProgramFragmentBindTexture(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsAllocation a)
@@ -204,27 +207,20 @@
pf->bindSampler(slot, static_cast<Sampler *>(s));
}
-void rsi_ProgramFragmentSetType(Context *rsc, uint32_t slot, RsType vt)
+void rsi_ProgramFragmentSetSlot(Context *rsc, uint32_t slot, bool enable, RsTexEnvMode env, RsType vt)
{
const Type *t = static_cast<const Type *>(vt);
- uint32_t dim = 1;
- if (t->getDimY()) {
- dim ++;
- if (t->getDimZ()) {
+ if (t) {
+ uint32_t dim = 1;
+ if (t->getDimY()) {
dim ++;
+ if (t->getDimZ()) {
+ dim ++;
+ }
}
+ rsc->mStateFragment.mPF->setType(slot, t->getElement(), dim);
}
-
- rsc->mStateFragment.mPF->setType(slot, t->getElement(), dim);
-}
-
-void rsi_ProgramFragmentSetEnvMode(Context *rsc, uint32_t slot, RsTexEnvMode env)
-{
rsc->mStateFragment.mPF->setEnvMode(slot, env);
-}
-
-void rsi_ProgramFragmentSetTexEnable(Context *rsc, uint32_t slot, bool enable)
-{
rsc->mStateFragment.mPF->setTexEnable(slot, enable);
}
@@ -236,15 +232,6 @@
return pf;
}
-void rsi_ProgramFragmentDestroy(Context *rsc, RsProgramFragment vpf)
-{
- ProgramFragment *pf = (ProgramFragment *)vpf;
- if (pf->getName()) {
- rsc->removeName(pf);
- }
- pf->decRef();
-}
-
}
}
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 57fb6a5..51117eb 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -32,10 +32,10 @@
- ProgramFragment(Element *in, Element *out);
+ ProgramFragment(Element *in, Element *out, bool pointSpriteEnable);
virtual ~ProgramFragment();
- virtual void setupGL(ProgramFragmentState *);
+ virtual void setupGL(const Context *, ProgramFragmentState *);
@@ -64,6 +64,7 @@
// Hacks to create a program for now
RsTexEnvMode mEnvModes[MAX_TEXTURE];
uint32_t mTextureEnableMask;
+ bool mPointSpriteEnable;
};
class ProgramFragmentState
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
index 27f4015..36ec615 100644
--- a/libs/rs/rsProgramFragmentStore.cpp
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -48,7 +48,7 @@
{
}
-void ProgramFragmentStore::setupGL(ProgramFragmentStoreState *state)
+void ProgramFragmentStore::setupGL(const Context *rsc, ProgramFragmentStoreState *state)
{
if (state->mLast.get() == this) {
return;
@@ -261,17 +261,6 @@
rsc->mStateFragmentStore.mPFS->setDitherEnable(enable);
}
-void rsi_ProgramFragmentStoreDestroy(Context *rsc, RsProgramFragmentStore vpfs)
-{
- ProgramFragmentStore *pfs = (ProgramFragmentStore *)vpfs;
- if (pfs->getName()) {
- rsc->removeName(pfs);
- }
- pfs->decRef();
-}
-
-
-
}
}
diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h
index 0de5c3a..e646e03 100644
--- a/libs/rs/rsProgramFragmentStore.h
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -31,7 +31,7 @@
ProgramFragmentStore(Element *in, Element *out);
virtual ~ProgramFragmentStore();
- virtual void setupGL(ProgramFragmentStoreState *);
+ virtual void setupGL(const Context *, ProgramFragmentStoreState *);
void setDepthFunc(RsDepthFunc);
void setDepthMask(bool);
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 6ef5456..dc57d34 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -44,7 +44,7 @@
LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]);
}
-void ProgramVertex::setupGL(ProgramVertexState *state)
+void ProgramVertex::setupGL(const Context *rsc, ProgramVertexState *state)
{
if ((state->mLast.get() == this) && !mDirty) {
return;
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index c9ce7aa..523c3ed 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -33,7 +33,7 @@
ProgramVertex(Element *in, Element *out);
virtual ~ProgramVertex();
- virtual void setupGL(ProgramVertexState *state);
+ virtual void setupGL(const Context *rsc, ProgramVertexState *state);
void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
index 418f127..332d532 100644
--- a/libs/rs/rsSampler.cpp
+++ b/libs/rs/rsSampler.cpp
@@ -138,20 +138,14 @@
SamplerState * ss = &rsc->mStateSampler;
- Sampler * s = new Sampler(ss->mMagFilter,
- ss->mMinFilter,
- ss->mWrapS,
+ Sampler * s = new Sampler(ss->mMagFilter,
+ ss->mMinFilter,
+ ss->mWrapS,
ss->mWrapT,
ss->mWrapR);
+ s->incRef();
return s;
}
-void rsi_SamplerDestroy(Context *rsc, RsSampler vs)
-{
- Sampler * s = static_cast<Sampler *>(vs);
- s->decRef();
-
-}
-
}}
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index 75c994b..fde31a1 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -37,12 +37,6 @@
namespace renderscript {
-void rsi_ScriptDestroy(Context * rsc, RsScript vs)
-{
- Script *s = static_cast<Script *>(vs);
- s->decRef();
-}
-
void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint32_t slot)
{
Script *s = static_cast<Script *>(vs);
@@ -76,11 +70,12 @@
s->mEnviroment.mClearStencil = v;
}
-void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, const char *name)
+void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, const char *name)
{
ScriptCState *ss = &rsc->mScriptC;
const Type *t = static_cast<const Type *>(vt);
ss->mConstantBufferTypes[slot].set(t);
+ ss->mSlotWritable[slot] = writable;
if (name) {
ss->mSlotNames[slot].setTo(name);
} else {
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index dc66763..60f83a6 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -61,6 +61,7 @@
ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
String8 mSlotNames[MAX_SCRIPT_BANKS];
+ bool mSlotWritable[MAX_SCRIPT_BANKS];
virtual bool run(Context *, uint32_t launchID) = 0;
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index ced2516..9419829 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -93,6 +93,7 @@
for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
mConstantBufferTypes[ct].clear();
mSlotNames[ct].setTo("");
+ mSlotWritable[ct] = false;
}
memset(&mEnviroment, 0, sizeof(mEnviroment));
@@ -266,7 +267,7 @@
tmp.append(c->getComponentName());
sprintf(buf, " %i\n", ct2);
tmp.append(buf);
- LOGD(tmp);
+ //LOGD(tmp);
str->append(tmp);
}
}
@@ -294,7 +295,7 @@
sprintf(buf, "%i, %i)\n", ct, ct2);
tmp.append(buf);
- LOGD(tmp);
+ //LOGD(tmp);
str->append(tmp);
}
}
@@ -341,6 +342,7 @@
for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
s->mSlotNames[ct] = ss->mSlotNames[ct];
+ s->mSlotWritable[ct] = ss->mSlotWritable[ct];
}
ss->clear();
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 32a9079..302515e 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -70,6 +70,7 @@
ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
String8 mSlotNames[MAX_SCRIPT_BANKS];
+ bool mSlotWritable[MAX_SCRIPT_BANKS];
void clear();
void runCompiler(Context *rsc);
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index c13894b..84a39aa 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -170,6 +170,44 @@
#define DEG_TO_RAD PI / 180.0f
#define RAD_TO_DEG 180.0f / PI
+static float SC_sinf_fast(float x)
+{
+ const float A = 1.0f / (2.0f * M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B * x * fabsf(x) + C * x;
+ return 0.2215f * (y * fabsf(y) - y) + y;
+}
+
+static float SC_cosf_fast(float x)
+{
+ x += float(M_PI / 2);
+
+ const float A = 1.0f / (2.0f * M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B * x * fabsf(x) + C * x;
+ return 0.2215f * (y * fabsf(y) - y) + y;
+}
+
static float SC_randf(float max)
{
float r = (float)rand();
@@ -465,6 +503,14 @@
}
+static void SC_vec2Rand(float *vec, float maxLen)
+{
+ float angle = SC_randf(PI * 2);
+ float len = SC_randf(maxLen);
+ vec[0] = len * sinf(angle);
+ vec[1] = len * cosf(angle);
+}
+
//////////////////////////////////////////////////////////////////////////////
@@ -683,7 +729,7 @@
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
}
-static void SC_hsb(float h, float s, float b, float a)
+static void SC_hsbToRgb(float h, float s, float b, float* rgb)
{
float red = 0.0f;
float green = 0.0f;
@@ -733,7 +779,26 @@
break;
}
- glColor4f(red, green, blue, a);
+ rgb[0] = red;
+ rgb[1] = green;
+ rgb[2] = blue;
+}
+
+static int SC_hsbToAbgr(float h, float s, float b, float a)
+{
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ return int(a * 255.0f) << 24 |
+ int(rgb[2] * 255.0f) << 16 |
+ int(rgb[1] * 255.0f) << 8 |
+ int(rgb[0] * 255.0f);
+}
+
+static void SC_hsb(float h, float s, float b, float a)
+{
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ glColor4f(rgb[0], rgb[1], rgb[2], a);
}
static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
@@ -763,11 +828,21 @@
LOGE("%s %f", s, f);
}
+static void SC_debugHexF(const char *s, float f)
+{
+ LOGE("%s 0x%x", s, *((int *) (&f)));
+}
+
static void SC_debugI32(const char *s, int32_t i)
{
LOGE("%s %i", s, i);
}
+static void SC_debugHexI32(const char *s, int32_t i)
+{
+ LOGE("%s 0x%x", s, i);
+}
+
static uint32_t SC_getWidth()
{
GET_TLS();
@@ -780,6 +855,24 @@
return rsc->getHeight();
}
+static uint32_t SC_colorFloatRGBAtoUNorm8(float r, float g, float b, float a)
+{
+ uint32_t c = 0;
+ c |= (uint32_t)(r * 255.f + 0.5f);
+ c |= ((uint32_t)(g * 255.f + 0.5f)) << 8;
+ c |= ((uint32_t)(b * 255.f + 0.5f)) << 16;
+ c |= ((uint32_t)(a * 255.f + 0.5f)) << 24;
+ return c;
+}
+
+static uint32_t SC_colorFloatRGBAto565(float r, float g, float b)
+{
+ uint32_t ir = (uint32_t)(r * 255.f + 0.5f);
+ uint32_t ig = (uint32_t)(g * 255.f + 0.5f);
+ uint32_t ib = (uint32_t)(b * 255.f + 0.5f);
+ return rs888to565(ir, ig, ib);
+}
+
//////////////////////////////////////////////////////////////////////////////
// Class implementation
//////////////////////////////////////////////////////////////////////////////
@@ -820,6 +913,10 @@
"int", "(int)" },
{ "absf", (void *)&fabs,
"float", "(float)" },
+ { "sinf_fast", (void *)&SC_sinf_fast,
+ "float", "(float)" },
+ { "cosf_fast", (void *)&SC_cosf_fast,
+ "float", "(float)" },
{ "sinf", (void *)&sinf,
"float", "(float)" },
{ "cosf", (void *)&cosf,
@@ -937,6 +1034,10 @@
{ "matrixTranslate", (void *)&SC_matrixTranslate,
"void", "(float *mat, float x, float y, float z)" },
+ // vector
+ { "vec2Rand", (void *)&SC_vec2Rand,
+ "void", "(float *vec, float maxLen)" },
+
// context
{ "bindProgramFragment", (void *)&SC_bindProgramFragment,
"void", "(int)" },
@@ -983,6 +1084,10 @@
"void", "(float, float, float, float)" },
{ "hsb", (void *)&SC_hsb,
"void", "(float, float, float, float)" },
+ { "hsbToRgb", (void *)&SC_hsbToRgb,
+ "void", "(float, float, float, float*)" },
+ { "hsbToAbgr", (void *)&SC_hsbToAbgr,
+ "int", "(float, float, float, float)" },
{ "ambient", (void *)&SC_ambient,
"void", "(float, float, float, float)" },
{ "diffuse", (void *)&SC_diffuse,
@@ -999,6 +1104,12 @@
{ "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
"void", "(int)" },
+ { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8,
+ "int", "(float, float, float, float)" },
+ { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565,
+ "int", "(float, float, float)" },
+
+
{ "getWidth", (void *)&SC_getWidth,
"int", "()" },
{ "getHeight", (void *)&SC_getHeight,
@@ -1010,6 +1121,10 @@
"void", "(void *, float)" },
{ "debugI32", (void *)&SC_debugI32,
"void", "(void *, int)" },
+ { "debugHexF", (void *)&SC_debugHexF,
+ "void", "(void *, float)" },
+ { "debugHexI32", (void *)&SC_debugHexI32,
+ "void", "(void *, int)" },
{ NULL, NULL, NULL, NULL }
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
index 08e36ac..0b745eb 100644
--- a/libs/rs/rsSimpleMesh.cpp
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -135,12 +135,6 @@
sm->mPrimitiveBuffer.set((Allocation *)va);
}
-void rsi_SimpleMeshDestroy(Context *rsc, RsSimpleMesh vtm)
-{
- SimpleMesh * tm = static_cast<SimpleMesh *>(vtm);
- tm->decRef();
-}
-
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 89df59d..db4bb81 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -21,8 +21,6 @@
using namespace android;
using namespace android::renderscript;
-ThreadIO *android::renderscript::gIO = NULL;
-
ThreadIO::ThreadIO()
{
mToCore.init(16 * 1024);
@@ -32,14 +30,25 @@
{
}
+void ThreadIO::shutdown()
+{
+ mToCore.shutdown();
+}
+
bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
{
- uint32_t cmdID = 0;
- uint32_t cmdSize = 0;
bool ret = false;
while(!mToCore.isEmpty() || waitForCommand) {
+ uint32_t cmdID = 0;
+ uint32_t cmdSize = 0;
ret = true;
+#if RS_LOG_TIMES
+ con->timerSet(Context::RS_TIMER_IDLE);
+#endif
const void * data = mToCore.get(&cmdID, &cmdSize);
+#if RS_LOG_TIMES
+ con->timerSet(Context::RS_TIMER_INTERNAL);
+#endif
waitForCommand = false;
//LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index 72746c5..1f6a0c2 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -31,6 +31,8 @@
ThreadIO();
~ThreadIO();
+ void shutdown();
+
// Plays back commands from the client.
// Returns true if any commands were processed.
bool playCoreCommands(Context *con, bool waitForCommand);
@@ -43,9 +45,6 @@
};
-extern ThreadIO *gIO;
-
-
}
}
diff --git a/libs/rs/rsTriangleMesh.cpp b/libs/rs/rsTriangleMesh.cpp
index 8c7bc92..99f8adb 100644
--- a/libs/rs/rsTriangleMesh.cpp
+++ b/libs/rs/rsTriangleMesh.cpp
@@ -199,6 +199,7 @@
memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize);
tm->analyzeElement();
+ tm->incRef();
return tm;
}
@@ -248,16 +249,16 @@
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(tm->mSizeCoord,
- GL_FLOAT,
- tm->mVertexElement->getSizeBytes(),
+ glVertexPointer(tm->mSizeCoord,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
(void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetCoord));
if (tm->mSizeTex) {
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(tm->mSizeTex,
- GL_FLOAT,
- tm->mVertexElement->getSizeBytes(),
+ glTexCoordPointer(tm->mSizeTex,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
(void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetTex));
} else {
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -265,8 +266,8 @@
if (tm->mSizeNorm) {
glEnableClientState(GL_NORMAL_ARRAY);
- glNormalPointer(GL_FLOAT,
- tm->mVertexElement->getSizeBytes(),
+ glNormalPointer(GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
(void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetNorm));
} else {
glDisableClientState(GL_NORMAL_ARRAY);
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 43c3bda..5a9090e 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -177,9 +177,16 @@
mGL.mColor.size = 3;
break;
case Component::ALPHA:
- rsAssert(mGL.mColor.size == 3);
- rsAssert(mGL.mColor.type == c->getGLType());
- mGL.mColor.size = 4;
+ // Can be RGBA or A at this point
+ if (mGL.mColor.size > 0) {
+ rsAssert(mGL.mColor.size == 3);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 4;
+ } else {
+ mGL.mColor.size = 1;
+ mGL.mColor.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mColor.type = c->getGLType();
+ }
break;
case Component::NX:
@@ -223,6 +230,13 @@
mGL.mTex[texNum].size = 4;
break;
+ case Component::POINT_SIZE:
+ rsAssert(!mGL.mPointSize.size);
+ mGL.mPointSize.size = 1;
+ mGL.mPointSize.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mPointSize.type = c->getGLType();
+ break;
+
default:
break;
}
@@ -273,6 +287,13 @@
}
glClientActiveTexture(GL_TEXTURE0);
+ if (mGL.mPointSize.size) {
+ glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
+ glPointSizePointerOES(mGL.mPointSize.type,
+ stride,
+ (void *)mGL.mPointSize.offset);
+ }
+
}
@@ -352,11 +373,6 @@
return st;
}
-void rsi_TypeDestroy(Context *rsc, RsType vst)
-{
- Type * st = static_cast<Type *>(vst);
- st->decRef();
-}
}
}
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 60d75d7..6c39a4c 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -118,6 +118,7 @@
VertexComponent_t mNorm;
VertexComponent_t mColor;
VertexComponent_t mTex[RS_MAX_TEXTURE];
+ VertexComponent_t mPointSize;
};
GLState_t mGL;
void makeGLComponents();
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 7cf6bb6..e3f816f 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -103,8 +103,10 @@
fprintf(f, " %s%s (", prefix, api->name);
if (addContext) {
fprintf(f, "Context *");
+ } else {
+ fprintf(f, "RsContext rsc");
}
- printArgList(f, api, addContext);
+ printArgList(f, api, 1);
fprintf(f, ")");
}
@@ -147,7 +149,7 @@
printFuncDecl(f, api, "rs", 0);
fprintf(f, "\n{\n");
- fprintf(f, " ThreadIO *io = gIO;\n");
+ fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n");
//fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name);
fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
@@ -200,7 +202,7 @@
fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
fprintf(f, " ");
if (api->ret.typeName[0]) {
- fprintf(f, "gIO->mToCoreRet = (intptr_t)");
+ fprintf(f, "con->mIO.mToCoreRet = (intptr_t)");
}
fprintf(f, "rsi_%s(con", api->name);
for(ct2=0; ct2 < api->paramCount; ct2++) {
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 419574c..fd54e35 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -730,14 +730,6 @@
return owner;
}
-
-void LayerBaseClient::Surface::getSurfaceData(
- ISurfaceFlingerClient::surface_data_t* params) const
-{
- params->token = mToken;
- params->identity = mIdentity;
-}
-
status_t LayerBaseClient::Surface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 65bf55b..7791941 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -321,10 +321,9 @@
class Surface : public BnSurface
{
public:
+ int32_t getToken() const { return mToken; }
+ int32_t getIdentity() const { return mIdentity; }
- virtual void getSurfaceData(
- ISurfaceFlingerClient::surface_data_t* params) const;
-
protected:
Surface(const sp<SurfaceFlinger>& flinger,
SurfaceID id, int identity,
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 5e74451..dd61e1a 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -97,11 +97,9 @@
err = allocator.alloc(w, h, format, usage, &handle, &stride);
if (err == NO_ERROR) {
- if (err == NO_ERROR) {
- width = w;
- height = h;
- mVStride = 0;
- }
+ width = w;
+ height = h;
+ mVStride = 0;
}
return err;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 102899c..a72294a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -186,6 +186,10 @@
mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugBackground(0),
+ mDebugInSwapBuffers(0),
+ mLastSwapBufferTime(0),
+ mDebugInTransaction(0),
+ mLastTransactionTime(0),
mConsoleSignals(0),
mSecureFrameBuffer(0)
{
@@ -517,7 +521,11 @@
if (!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const nsecs_t now = systemTime();
+ mDebugInSwapBuffers = now;
hw.flip(mInvalidRegion);
+ mLastSwapBufferTime = systemTime() - now;
+ mDebugInSwapBuffers = 0;
mInvalidRegion.clear();
}
}
@@ -555,7 +563,11 @@
{ // scope for the lock
Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
handleTransactionLocked(transactionFlags, ditchedLayers);
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
}
// do this without lock held
@@ -1239,9 +1251,11 @@
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(client, d, id, w, h, flags);
+ layer = createPushBuffersSurfaceLocked(client, d, id,
+ w, h, flags);
} else {
- layer = createNormalSurfaceLocked(client, d, id, w, h, format, flags);
+ layer = createNormalSurfaceLocked(client, d, id,
+ w, h, flags, format);
}
break;
case eFXSurfaceBlur:
@@ -1255,8 +1269,13 @@
if (layer != 0) {
setTransactionFlags(eTransactionNeeded);
surfaceHandle = layer->getSurface();
- if (surfaceHandle != 0)
- surfaceHandle->getSurfaceData(params);
+ if (surfaceHandle != 0) {
+ params->token = surfaceHandle->getToken();
+ params->identity = surfaceHandle->getIdentity();
+ params->width = w;
+ params->height = h;
+ params->format = format;
+ }
}
return surfaceHandle;
@@ -1264,7 +1283,8 @@
sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
const sp<Client>& client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format)
{
// initialize the surfaces
switch (format) { // TODO: take h/w into account
@@ -1459,7 +1479,29 @@
IPCThreadState::self()->getCallingUid());
result.append(buffer);
} else {
- Mutex::Autolock _l(mStateLock);
+
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ // Try to get the main lock, but don't insist if we can't
+ // (this would indicate SF is stuck, but we want to be able to
+ // print something in dumpsys).
+ int retry = 3;
+ while (mStateLock.tryLock()<0 && --retry>=0) {
+ usleep(1000000);
+ }
+ const bool locked(retry >= 0);
+ if (!locked) {
+ snprintf(buffer, SIZE,
+ "SurfaceFlinger appears to be unresponsive, "
+ "dumping anyways (no locks held)\n");
+ result.append(buffer);
+ }
+
size_t s = mClientsMap.size();
char name[64];
for (size_t i=0 ; i<s ; i++) {
@@ -1530,10 +1572,29 @@
mFreezeDisplay?"yes":"no", mFreezeCount,
mCurrentState.orientation, hw.canDraw());
result.append(buffer);
+ snprintf(buffer, SIZE,
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n",
+ mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
+ result.append(buffer);
+ if (inSwapBuffersDuration || !locked) {
+ snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+ result.append(buffer);
+ }
+ if (inTransactionDuration || !locked) {
+ snprintf(buffer, SIZE, " transaction time: %f us\n",
+ inTransactionDuration/1000.0);
+ result.append(buffer);
+ }
snprintf(buffer, SIZE, " client count: %d\n", mClientsMap.size());
result.append(buffer);
const BufferAllocator& alloc(BufferAllocator::get());
alloc.dump(result);
+
+ if (locked) {
+ mStateLock.unlock();
+ }
}
write(fd, result.string(), result.size());
return NO_ERROR;
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 2569a0f..69e2f2e 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -195,8 +195,8 @@
sp<LayerBaseClient> createNormalSurfaceLocked(
const sp<Client>& client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags);
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format);
sp<LayerBaseClient> createBlurSurfaceLocked(
const sp<Client>& client, DisplayID display,
@@ -348,6 +348,10 @@
// don't use a lock for these, we don't care
int mDebugRegion;
int mDebugBackground;
+ volatile nsecs_t mDebugInSwapBuffers;
+ nsecs_t mLastSwapBufferTime;
+ volatile nsecs_t mDebugInTransaction;
+ nsecs_t mLastTransactionTime;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index 51e8422..4a6a1d7 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -189,8 +189,11 @@
status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
{
- token = parcel.readInt32();
- identity = parcel.readInt32();
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ width = parcel.readInt32();
+ height = parcel.readInt32();
+ format = parcel.readInt32();
return NO_ERROR;
}
@@ -198,6 +201,9 @@
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
return NO_ERROR;
}
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 2b6905f..474308a 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -64,11 +64,16 @@
{
// we own the handle in this case
width = data.readInt32();
- height = data.readInt32();
- stride = data.readInt32();
- format = data.readInt32();
- usage = data.readInt32();
- handle = data.readNativeHandle();
+ if (width < 0) {
+ width = height = stride = format = usage = 0;
+ handle = 0;
+ } else {
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
+ }
}
SurfaceBuffer::~SurfaceBuffer()
@@ -108,16 +113,25 @@
status_t SurfaceBuffer::writeToParcel(Parcel* reply,
android_native_buffer_t const* buffer)
{
- if (buffer == NULL) {
+ if (buffer == NULL)
return BAD_VALUE;
+
+ if (buffer->width < 0 || buffer->height < 0)
+ return BAD_VALUE;
+
+ status_t err = NO_ERROR;
+ if (buffer->handle == NULL) {
+ // this buffer doesn't have a handle
+ reply->writeInt32(NO_MEMORY);
+ } else {
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ err = reply->writeNativeHandle(buffer->handle);
}
- reply->writeInt32(buffer->width);
- reply->writeInt32(buffer->height);
- reply->writeInt32(buffer->stride);
- reply->writeInt32(buffer->format);
- reply->writeInt32(buffer->usage);
- reply->writeNativeHandle(buffer->handle);
- return NO_ERROR;
+ return err;
}
// ----------------------------------------------------------------------
@@ -183,7 +197,8 @@
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
: mClient(client), mSurface(surface),
mToken(data.token), mIdentity(data.identity),
- mWidth(w), mHeight(h), mFormat(format), mFlags(flags)
+ mWidth(data.width), mHeight(data.height), mFormat(data.format),
+ mFlags(flags)
{
}
@@ -382,9 +397,9 @@
Surface::Surface(const sp<SurfaceControl>& surface)
: mClient(surface->mClient), mSurface(surface->mSurface),
mToken(surface->mToken), mIdentity(surface->mIdentity),
- mWidth(surface->mWidth), mHeight(surface->mHeight),
mFormat(surface->mFormat), mFlags(surface->mFlags),
- mBufferMapper(BufferMapper::get())
+ mBufferMapper(BufferMapper::get()),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
{
init();
}
@@ -426,15 +441,15 @@
const_cast<uint32_t&>(android_native_window_t::flags) = 0;
// be default we request a hardware surface
mUsage = GRALLOC_USAGE_HW_RENDER;
+ mUsageChanged = true;
}
-
Surface::~Surface()
{
// this is a client-side operation, the surface is destroyed, unmap
// its buffers in this process.
for (int i=0 ; i<2 ; i++) {
- if (mBuffers[i] != 0) {
+ if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
}
}
@@ -446,11 +461,24 @@
IPCThreadState::self()->flushCommands();
}
+sp<SurfaceComposerClient> Surface::getClient() const {
+ return mClient;
+}
+
+sp<ISurface> Surface::getISurface() const {
+ return mSurface;
+}
+
+bool Surface::isValid() {
+ return mToken>=0 && mClient!=0;
+}
+
status_t Surface::validate(per_client_cblk_t const* cblk) const
{
+ sp<SurfaceComposerClient> client(getClient());
if (mToken<0 || mClient==0) {
LOGE("invalid token (%d, identity=%u) or client (%p)",
- mToken, mIdentity, mClient.get());
+ mToken, mIdentity, client.get());
return NO_INIT;
}
if (cblk == 0) {
@@ -477,6 +505,7 @@
{
if (lhs == 0 || rhs == 0)
return false;
+
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
@@ -532,10 +561,9 @@
{
android_native_buffer_t* out;
status_t err = dequeueBuffer(&out);
- *buffer = SurfaceBuffer::getSelf(out);
- // reset the width/height with the what we get from the buffer
- mWidth = uint32_t(out->width);
- mHeight = uint32_t(out->height);
+ if (err == NO_ERROR) {
+ *buffer = SurfaceBuffer::getSelf(out);
+ }
return err;
}
@@ -557,7 +585,8 @@
Mutex::Autolock _l(mSurfaceLock);
- per_client_cblk_t* const cblk = mClient->mControl;
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
if (err != NO_ERROR)
return err;
@@ -572,18 +601,38 @@
mBackbufferIndex = backIdx;
layer_cblk_t* const lcblk = &(cblk->layers[index]);
-
volatile const surface_info_t* const back = lcblk->surface + backIdx;
- if (back->flags & surface_info_t::eNeedNewBuffer) {
+
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+
+ if (backBuffer==0 &&
+ !((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged)) {
+ LOGW("dequeueBuffer: backbuffer is null, but eNeedNewBuffer "
+ "is not set, fetching a buffer anyways...");
+ }
+
+ if ((back->flags & surface_info_t::eNeedNewBuffer) ||mUsageChanged ||
+ backBuffer==0)
+ {
+ mUsageChanged = false;
err = getBufferLocked(backIdx, mUsage);
+ if (err == NO_ERROR) {
+ // reset the width/height with the what we get from the buffer
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ }
}
if (err == NO_ERROR) {
- const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
- mDirtyRegion.set(backBuffer->width, backBuffer->height);
- *buffer = backBuffer.get();
+ if (backBuffer != 0) {
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ } else {
+ err = NO_MEMORY;
+ }
}
-
+
return err;
}
@@ -591,7 +640,8 @@
{
Mutex::Autolock _l(mSurfaceLock);
- per_client_cblk_t* const cblk = mClient->mControl;
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
if (err != NO_ERROR)
return err;
@@ -604,7 +654,8 @@
{
Mutex::Autolock _l(mSurfaceLock);
- per_client_cblk_t* const cblk = mClient->mControl;
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
status_t err = validate(cblk);
if (err != NO_ERROR)
return err;
@@ -620,7 +671,7 @@
uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
if (!(newstate & eNextFlipPending))
- mClient->signalServer();
+ client->signalServer();
return NO_ERROR;
}
@@ -646,7 +697,7 @@
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_SET_USAGE:
- mUsage = va_arg(args, int);
+ setUsage( va_arg(args, int) );
break;
default:
res = NAME_NOT_FOUND;
@@ -655,6 +706,15 @@
return res;
}
+void Surface::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ if (mUsage != reqUsage) {
+ mUsageChanged = true;
+ mUsage = reqUsage;
+ }
+}
+
// ----------------------------------------------------------------------------
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@@ -663,11 +723,9 @@
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
{
- // FIXME: needs some locking here
-
// we're intending to do software rendering from this point
- mUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
sp<SurfaceBuffer> backBuffer;
status_t err = dequeueBuffer(&backBuffer);
if (err == NO_ERROR) {
@@ -679,7 +737,8 @@
Region scratch(bounds);
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
- per_client_cblk_t* const cblk = mClient->mControl;
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
if (back->flags & surface_info_t::eBufferDirty) {
@@ -689,7 +748,8 @@
} else {
newDirtyRegion.andSelf(bounds);
const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
- if (backBuffer->width == frontBuffer->width &&
+ if (frontBuffer !=0 &&
+ backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
!(lcblk->flags & eNoCopyBack))
{
@@ -725,8 +785,6 @@
status_t Surface::unlockAndPost()
{
- // FIXME: needs some locking here
-
if (mLockedBuffer == 0)
return BAD_VALUE;
@@ -753,24 +811,34 @@
}
void Surface::setSwapRectangle(const Rect& r) {
+ Mutex::Autolock _l(mSurfaceLock);
mSwapRectangle = r;
}
status_t Surface::getBufferLocked(int index, int usage)
{
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
status_t err = NO_MEMORY;
- sp<SurfaceBuffer> buffer = mSurface->getBuffer(usage);
+
+ // free the current buffer
+ sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ getBufferMapper().unregisterBuffer(currentBuffer->handle);
+ currentBuffer.clear();
+ }
+
+ sp<SurfaceBuffer> buffer = s->getBuffer(usage);
LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
- if (buffer != 0) {
- sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
- if (currentBuffer != 0) {
- getBufferMapper().unregisterBuffer(currentBuffer->handle);
- currentBuffer.clear();
- }
- err = getBufferMapper().registerBuffer(buffer->handle);
- LOGW_IF(err, "registerBuffer(...) failed %d (%s)", err, strerror(-err));
- if (err == NO_ERROR) {
- currentBuffer = buffer;
+ if (buffer != 0) { // this should never happen by construction
+ if (buffer->handle != NULL) {
+ err = getBufferMapper().registerBuffer(buffer->handle);
+ LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
+ err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
+ }
}
}
return err;
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index bdef01f..0b4fb88 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -728,7 +728,7 @@
mStarted = true;
int positionMode;
if (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ASSISTED_GPS_ENABLED, 0) != 0) {
+ Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
positionMode = GPS_POSITION_MODE_MS_BASED;
} else {
positionMode = GPS_POSITION_MODE_STANDALONE;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 16bf8a2..de944ee 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -816,37 +816,44 @@
/* Routing bits for setRouting/getRouting API */
/**
* Routing audio output to earpiece
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
/**
- * Routing audio output to spaker
- * @deprecated
+ * Routing audio output to speaker
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
/**
* @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to bluetooth SCO
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to headset
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
/**
* Routing audio output to bluetooth A2DP
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
/**
* Used for mask parameter of {@link #setRouting(int,int,int)}.
- * @deprecated
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5a59712..d1b9351 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -17,16 +17,16 @@
package android.media;
import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.bluetooth.BluetoothIntent;
-import android.content.BroadcastReceiver;
-import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothHeadset;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
@@ -144,16 +144,16 @@
/** @hide Maximum volume index values for audio streams */
private int[] MAX_STREAM_VOLUME = new int[] {
- 6, // STREAM_VOICE_CALL
- 8, // STREAM_SYSTEM
- 8, // STREAM_RING
- 16, // STREAM_MUSIC
- 8, // STREAM_ALARM
- 8, // STREAM_NOTIFICATION
- 16, // STREAM_BLUETOOTH_SCO
- 8, // STREAM_SYSTEM_ENFORCED
- 16, // STREAM_DTMF
- 16 // STREAM_TTS
+ 5, // STREAM_VOICE_CALL
+ 7, // STREAM_SYSTEM
+ 7, // STREAM_RING
+ 15, // STREAM_MUSIC
+ 7, // STREAM_ALARM
+ 7, // STREAM_NOTIFICATION
+ 15, // STREAM_BLUETOOTH_SCO
+ 7, // STREAM_SYSTEM_ENFORCED
+ 15, // STREAM_DTMF
+ 15 // STREAM_TTS
};
/* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings
* of another stream: This avoids multiplying the volume settings for hidden
@@ -236,8 +236,6 @@
// Forced device usage for communications
private int mForcedUseForComm;
- private BluetoothDevice mBluetoothDevice = null;
-
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -1371,8 +1369,8 @@
if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
BluetoothA2dp.STATE_DISCONNECTED);
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
-
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+ String address = btDevice.getAddress();
boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address));
@@ -1387,19 +1385,21 @@
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE,
address);
- mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address);
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+ address);
}
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
BluetoothHeadset.STATE_ERROR);
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
- if (mBluetoothDevice == null) {
- mBluetoothDevice = (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- }
- if (mBluetoothDevice != null) {
- int btClass = mBluetoothDevice.getRemoteClass(address);
- if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) {
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+ String address = null;
+ int btClass = BluetoothClass.ERROR;
+ if (btDevice != null) {
+ address = btDevice.getAddress();
+ btClass = btDevice.getBluetoothClass();
+ if (BluetoothClass.Device.Major.getDeviceMajor(btClass) ==
+ BluetoothClass.Device.Major.AUDIO_VIDEO) {
switch (BluetoothClass.Device.getDevice(btClass)) {
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
@@ -1426,7 +1426,7 @@
AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE,
address);
- mConnectedDevices.put( new Integer(device), address);
+ mConnectedDevices.put(new Integer(device), address);
}
} else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", 0);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d587f65..dbf6d9d 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -93,8 +93,9 @@
*
* return the current audio mode (NORMAL, RINGTONE, or IN_CALL).
* Returns the current current audio state from the HAL.
+ *
*/
- /** @deprecated */
+ /** @deprecated Do not use. */
public static int getMode() {
return MODE_INVALID;
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 6d7c0ae..d578c81 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -18,6 +18,9 @@
import android.util.Log;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -59,7 +62,7 @@
// The Exif tag names
public static final String TAG_ORIENTATION = "Orientation";
- public static final String TAG_DATE_TIME_ORIGINAL = "DateTimeOriginal";
+ public static final String TAG_DATETIME = "DateTime";
public static final String TAG_MAKE = "Make";
public static final String TAG_MODEL = "Model";
public static final String TAG_FLASH = "Flash";
@@ -321,6 +324,28 @@
return latlng;
}
+ private static SimpleDateFormat sFormatter =
+ new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
+
+ // Returns number of milliseconds since Jan. 1, 1970, midnight GMT.
+ // Returns -1 if the date time information if not available.
+ public static long getDateTime(HashMap<String, String> exifData) {
+ if (exifData == null) {
+ return -1;
+ }
+
+ String dateTimeString = exifData.get(ExifInterface.TAG_DATETIME);
+ if (dateTimeString == null) return -1;
+
+ ParsePosition pos = new ParsePosition(0);
+ try {
+ Date date = sFormatter.parse(dateTimeString, pos);
+ return date.getTime();
+ } catch (IllegalArgumentException ex) {
+ return -1;
+ }
+ }
+
public static float convertRationalLatLonToFloat(
String rationalString, String ref) {
try {
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index c6a9ae8..cecf4f8 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -254,5 +254,6 @@
public static final int METADATA_KEY_VIDEO_FORMAT = 18;
public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
public static final int METADATA_KEY_VIDEO_WIDTH = 20;
+ public static final int METADATA_KEY_WRITER = 21;
// Add more here...
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index a8689f2..6a9a9bd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -539,7 +539,7 @@
* @param request Parcel with the data for the extension. The
* caller must use {@link #newRequest()} to get one.
*
- * @param[out] reply Parcel with the data returned by the
+ * @param reply Output parcel with the data returned by the
* native player.
*
* @return The status code see utils/Errors.h
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 46ede7f..9bb00c6 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -168,7 +168,7 @@
/** The following formats are audio only .aac or .amr formats **/
/** @deprecated Deprecated in favor of AMR_NB */
- /** @todo change link when AMR_NB is exposed. Deprecated in favor of {@link MediaRecorder.OutputFormat#AMR_NB} */
+ /** TODO: change link when AMR_NB is exposed. Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
public static final int RAW_AMR = 3;
/** @hide AMR NB file format */
public static final int AMR_NB = 3;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 71af909..3d5aae3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -396,6 +396,7 @@
private String mPath;
private long mLastModified;
private long mFileSize;
+ private String mWriter;
public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) {
@@ -479,6 +480,7 @@
mDuration = 0;
mPath = path;
mLastModified = lastModified;
+ mWriter = null;
return entry;
}
@@ -593,6 +595,8 @@
mTrack = (num * 1000) + (mTrack % 1000);
} else if (name.equalsIgnoreCase("duration")) {
mDuration = parseSubstring(value, 0, 0);
+ } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) {
+ mWriter = value.trim();
}
}
@@ -716,6 +720,11 @@
values.put(Images.Media.LATITUDE, latlng[0]);
values.put(Images.Media.LONGITUDE, latlng[1]);
}
+
+ long time = ExifInterface.getDateTime(exifData);
+ if (time != -1) {
+ values.put(Images.Media.DATE_TAKEN, time);
+ }
}
}
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d1dbc5c..10bebd0 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -18,6 +18,8 @@
SEND_COMMAND,
GET_PARAMETER,
SET_PARAMETER,
+ GET_CONFIG,
+ SET_CONFIG,
USE_BUFFER,
ALLOC_BUFFER,
ALLOC_BUFFER_WITH_BACKUP,
@@ -25,6 +27,7 @@
OBSERVE_NODE,
FILL_BUFFER,
EMPTY_BUFFER,
+ GET_EXTENSION_INDEX,
CREATE_RENDERER,
OBSERVER_ON_MSG,
RENDERER_RENDER,
@@ -42,16 +45,6 @@
displayWidth, displayHeight);
}
-static void *readVoidStar(const Parcel *parcel) {
- // FIX if sizeof(void *) != sizeof(int32)
- return (void *)parcel->readInt32();
-}
-
-static void writeVoidStar(void *x, Parcel *parcel) {
- // FIX if sizeof(void *) != sizeof(int32)
- parcel->writeInt32((int32_t)x);
-}
-
class BpOMX : public BpInterface<IOMX> {
public:
BpOMX(const sp<IBinder> &impl)
@@ -83,7 +76,7 @@
status_t err = reply.readInt32();
if (err == OK) {
- *node = readVoidStar(&reply);
+ *node = (void*)reply.readIntPtr();
} else {
*node = 0;
}
@@ -94,7 +87,7 @@
virtual status_t free_node(node_id node) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
remote()->transact(FREE_NODE, data, &reply);
return reply.readInt32();
@@ -104,7 +97,7 @@
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(cmd);
data.writeInt32(param);
remote()->transact(SEND_COMMAND, data, &reply);
@@ -117,7 +110,7 @@
void *params, size_t size) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(index);
data.writeInt32(size);
data.write(params, size);
@@ -138,7 +131,7 @@
const void *params, size_t size) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(index);
data.writeInt32(size);
data.write(params, size);
@@ -147,12 +140,47 @@
return reply.readInt32();
}
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(GET_CONFIG, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ return err;
+ }
+
+ reply.read(params, size);
+
+ return OK;
+ }
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(SET_CONFIG, data, &reply);
+
+ return reply.readInt32();
+ }
+
virtual status_t use_buffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(port_index);
data.writeStrongBinder(params->asBinder());
remote()->transact(USE_BUFFER, data, &reply);
@@ -164,7 +192,7 @@
return err;
}
- *buffer = readVoidStar(&reply);
+ *buffer = (void*)reply.readIntPtr();
return err;
}
@@ -174,7 +202,7 @@
buffer_id *buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(port_index);
data.writeInt32(size);
remote()->transact(ALLOC_BUFFER, data, &reply);
@@ -186,7 +214,7 @@
return err;
}
- *buffer = readVoidStar(&reply);
+ *buffer = (void*)reply.readIntPtr();
return err;
}
@@ -196,7 +224,7 @@
buffer_id *buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(port_index);
data.writeStrongBinder(params->asBinder());
remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
@@ -208,7 +236,7 @@
return err;
}
- *buffer = readVoidStar(&reply);
+ *buffer = (void*)reply.readIntPtr();
return err;
}
@@ -217,9 +245,9 @@
node_id node, OMX_U32 port_index, buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(port_index);
- writeVoidStar(buffer, &data);
+ data.writeIntPtr((intptr_t)buffer);
remote()->transact(FREE_BUFFER, data, &reply);
return reply.readInt32();
@@ -229,7 +257,7 @@
node_id node, const sp<IOMXObserver> &observer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
+ data.writeIntPtr((intptr_t)node);
data.writeStrongBinder(observer->asBinder());
remote()->transact(OBSERVE_NODE, data, &reply);
@@ -239,8 +267,8 @@
virtual void fill_buffer(node_id node, buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
- writeVoidStar(buffer, &data);
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
}
@@ -251,8 +279,8 @@
OMX_U32 flags, OMX_TICKS timestamp) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- writeVoidStar(node, &data);
- writeVoidStar(buffer, &data);
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
data.writeInt32(range_offset);
data.writeInt32(range_length);
data.writeInt32(flags);
@@ -260,6 +288,27 @@
remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
}
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeCString(parameter_name);
+
+ remote()->transact(GET_EXTENSION_INDEX, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ *index = static_cast<OMX_INDEXTYPE>(reply.readInt32());
+ } else {
+ *index = OMX_IndexComponentStartUnused;
+ }
+
+ return err;
+ }
+
virtual sp<IOMXRenderer> createRenderer(
const sp<ISurface> &surface,
const char *componentName,
@@ -320,7 +369,7 @@
status_t err = allocate_node(data.readCString(), &node);
reply->writeInt32(err);
if (err == OK) {
- writeVoidStar(node, reply);
+ reply->writeIntPtr((intptr_t)node);
}
return NO_ERROR;
@@ -330,7 +379,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
reply->writeInt32(free_node(node));
@@ -341,7 +390,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_COMMANDTYPE cmd =
static_cast<OMX_COMMANDTYPE>(data.readInt32());
@@ -356,7 +405,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
size_t size = data.readInt32();
@@ -383,7 +432,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
size_t size = data.readInt32();
@@ -394,11 +443,53 @@
return NO_ERROR;
}
+ case GET_CONFIG:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+
+ // XXX I am not happy with this but Parcel::readInplace didn't work.
+ void *params = malloc(size);
+ data.read(params, size);
+
+ status_t err = get_config(node, index, params, size);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->write(params, size);
+ }
+
+ free(params);
+ params = NULL;
+
+ return NO_ERROR;
+ }
+
+ case SET_CONFIG:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+ void *params = const_cast<void *>(data.readInplace(size));
+
+ reply->writeInt32(set_config(node, index, params, size));
+
+ return NO_ERROR;
+ }
+
case USE_BUFFER:
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_U32 port_index = data.readInt32();
sp<IMemory> params =
interface_cast<IMemory>(data.readStrongBinder());
@@ -408,7 +499,7 @@
reply->writeInt32(err);
if (err == OK) {
- writeVoidStar(buffer, reply);
+ reply->writeIntPtr((intptr_t)buffer);
}
return NO_ERROR;
@@ -418,7 +509,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_U32 port_index = data.readInt32();
size_t size = data.readInt32();
@@ -427,7 +518,7 @@
reply->writeInt32(err);
if (err == OK) {
- writeVoidStar(buffer, reply);
+ reply->writeIntPtr((intptr_t)buffer);
}
return NO_ERROR;
@@ -437,7 +528,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_U32 port_index = data.readInt32();
sp<IMemory> params =
interface_cast<IMemory>(data.readStrongBinder());
@@ -449,7 +540,7 @@
reply->writeInt32(err);
if (err == OK) {
- writeVoidStar(buffer, reply);
+ reply->writeIntPtr((intptr_t)buffer);
}
return NO_ERROR;
@@ -459,9 +550,9 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
OMX_U32 port_index = data.readInt32();
- buffer_id buffer = readVoidStar(&data);
+ buffer_id buffer = (void*)data.readIntPtr();
reply->writeInt32(free_buffer(node, port_index, buffer));
return NO_ERROR;
@@ -471,7 +562,7 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
sp<IOMXObserver> observer =
interface_cast<IOMXObserver>(data.readStrongBinder());
reply->writeInt32(observe_node(node, observer));
@@ -483,8 +574,8 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
- buffer_id buffer = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
+ buffer_id buffer = (void*)data.readIntPtr();
fill_buffer(node, buffer);
return NO_ERROR;
@@ -494,8 +585,8 @@
{
CHECK_INTERFACE(IOMX, data, reply);
- node_id node = readVoidStar(&data);
- buffer_id buffer = readVoidStar(&data);
+ node_id node = (void*)data.readIntPtr();
+ buffer_id buffer = (void*)data.readIntPtr();
OMX_U32 range_offset = data.readInt32();
OMX_U32 range_length = data.readInt32();
OMX_U32 flags = data.readInt32();
@@ -508,6 +599,25 @@
return NO_ERROR;
}
+ case GET_EXTENSION_INDEX:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ const char *parameter_name = data.readCString();
+
+ OMX_INDEXTYPE index;
+ status_t err = get_extension_index(node, parameter_name, &index);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeInt32(index);
+ }
+
+ return OK;
+ }
+
case CREATE_RENDERER:
{
CHECK_INTERFACE(IOMX, data, reply);
@@ -591,7 +701,7 @@
virtual void render(IOMX::buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
- writeVoidStar(buffer, &data);
+ data.writeIntPtr((intptr_t)buffer);
// NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
// so that the caller knows when to recycle the buffer.
@@ -608,7 +718,7 @@
{
CHECK_INTERFACE(IOMXRenderer, data, reply);
- IOMX::buffer_id buffer = readVoidStar(&data);
+ IOMX::buffer_id buffer = (void*)data.readIntPtr();
render(buffer);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 00ba1ac..0c40b91 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@
MediaSource.cpp \
MetaData.cpp \
MmapSource.cpp \
+ OMXCodec.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
TimeSource.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index d547556..140bc68 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-#undef NDEBUG
-#include <assert.h>
-
#define LOG_TAG "AudioPlayer"
#include <utils/Log.h>
#include <media/AudioTrack.h>
#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
namespace android {
AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
- : mSource(NULL),
- mAudioTrack(NULL),
+ : mAudioTrack(NULL),
mInputBuffer(NULL),
mSampleRate(0),
mLatencyUs(0),
@@ -48,37 +45,37 @@
}
}
-void AudioPlayer::setSource(MediaSource *source) {
- assert(mSource == NULL);
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK_EQ(mSource, NULL);
mSource = source;
}
void AudioPlayer::start() {
- assert(!mStarted);
- assert(mSource != NULL);
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
status_t err = mSource->start();
- assert(err == OK);
+ CHECK_EQ(err, OK);
sp<MetaData> format = mSource->getFormat();
const char *mime;
bool success = format->findCString(kKeyMIMEType, &mime);
- assert(success);
- assert(!strcasecmp(mime, "audio/raw"));
+ CHECK(success);
+ CHECK(!strcasecmp(mime, "audio/raw"));
success = format->findInt32(kKeySampleRate, &mSampleRate);
- assert(success);
+ CHECK(success);
int32_t numChannels;
success = format->findInt32(kKeyChannelCount, &numChannels);
- assert(success);
+ CHECK(success);
if (mAudioSink.get() != NULL) {
status_t err = mAudioSink->open(
mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&AudioPlayer::AudioSinkCallback, this);
- assert(err == OK);
+ CHECK_EQ(err, OK);
mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
mFrameSize = mAudioSink->frameSize();
@@ -92,7 +89,7 @@
: AudioSystem::CHANNEL_OUT_MONO,
8192, 0, &AudioCallback, this, 0);
- assert(mAudioTrack->initCheck() == OK);
+ CHECK_EQ(mAudioTrack->initCheck(), OK);
mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
mFrameSize = mAudioTrack->frameSize();
@@ -104,7 +101,7 @@
}
void AudioPlayer::pause() {
- assert(mStarted);
+ CHECK(mStarted);
if (mAudioSink.get() != NULL) {
mAudioSink->pause();
@@ -114,7 +111,7 @@
}
void AudioPlayer::resume() {
- assert(mStarted);
+ CHECK(mStarted);
if (mAudioSink.get() != NULL) {
mAudioSink->start();
@@ -124,7 +121,7 @@
}
void AudioPlayer::stop() {
- assert(mStarted);
+ CHECK(mStarted);
if (mAudioSink.get() != NULL) {
mAudioSink->stop();
@@ -203,7 +200,7 @@
if (mInputBuffer == NULL) {
status_t err = mSource->read(&mInputBuffer, &options);
- assert((err == OK && mInputBuffer != NULL)
+ CHECK((err == OK && mInputBuffer != NULL)
|| (err != OK && mInputBuffer == NULL));
if (err != OK) {
@@ -216,7 +213,7 @@
mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
success = success &&
mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- assert(success);
+ CHECK(success);
Mutex::Autolock autoLock(mLock);
mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index 0fd71d5..fd00576 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -14,18 +14,16 @@
* limitations under the License.
*/
-#include <media/stagefright/CachingDataSource.h>
-
-#undef NDEBUG
-#include <assert.h>
-
#include <stdlib.h>
#include <string.h>
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/MediaDebug.h>
+
namespace android {
CachingDataSource::CachingDataSource(
- DataSource *source, size_t pageSize, int numPages)
+ const sp<DataSource> &source, size_t pageSize, int numPages)
: mSource(source),
mData(malloc(pageSize * numPages)),
mPageSize(pageSize),
@@ -61,9 +59,6 @@
free(mData);
mData = NULL;
-
- delete mSource;
- mSource = NULL;
}
status_t CachingDataSource::InitCheck() const {
@@ -78,7 +73,7 @@
Page *page = mFirst;
while (page != NULL) {
if (page->mOffset >= 0 && offset >= page->mOffset
- && offset < page->mOffset + page->mLength) {
+ && offset < page->mOffset + (off_t)page->mLength) {
break;
}
page = page->mNext;
@@ -102,7 +97,7 @@
return n;
}
- if (offset >= page->mOffset + page->mLength) {
+ if (offset >= page->mOffset + (off_t)page->mLength) {
break;
}
} else {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index ee12873..f75b173 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -16,13 +16,11 @@
#include <sys/time.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <OMX_Component.h>
#include <binder/IServiceManager.h>
#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <ui/ICameraClient.h>
@@ -56,12 +54,12 @@
}
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
- assert(mSource != NULL);
+ CHECK(mSource != NULL);
mSource->notifyCallback(msgType, ext1, ext2);
}
virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
- assert(mSource != NULL);
+ CHECK(mSource != NULL);
mSource->dataCallback(msgType, data);
}
@@ -128,16 +126,16 @@
}
status_t CameraSource::start(MetaData *) {
- assert(!mStarted);
+ CHECK(!mStarted);
status_t err = mCamera->lock();
- assert(err == OK);
+ CHECK_EQ(err, OK);
err = mCamera->setPreviewDisplay(new DummySurface);
- assert(err == OK);
+ CHECK_EQ(err, OK);
mCamera->setPreviewCallbackFlag(1);
mCamera->startPreview();
- assert(err == OK);
+ CHECK_EQ(err, OK);
mStarted = true;
@@ -145,7 +143,7 @@
}
status_t CameraSource::stop() {
- assert(mStarted);
+ CHECK(mStarted);
mCamera->stopPreview();
mCamera->unlock();
@@ -167,7 +165,7 @@
status_t CameraSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
- assert(mStarted);
+ CHECK(mStarted);
*buffer = NULL;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 6e6b43d..02a276b 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -22,6 +22,19 @@
namespace android {
+bool DataSource::getUInt16(off_t offset, uint16_t *x) {
+ *x = 0;
+
+ uint8_t byte[2];
+ if (read_at(offset, byte, 2) != 2) {
+ return false;
+ }
+
+ *x = (byte[0] << 8) | byte[1];
+
+ return true;
+}
+
status_t DataSource::getSize(off_t *size) {
*size = 0;
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index c26d0a0..f6b90b2 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -15,9 +15,7 @@
*/
#include <media/stagefright/FileSource.h>
-
-#undef NDEBUG
-#include <assert.h>
+#include <media/stagefright/MediaDebug.h>
namespace android {
@@ -40,7 +38,7 @@
Mutex::Autolock autoLock(mLock);
int err = fseeko(mFile, offset, SEEK_SET);
- assert(err != -1);
+ CHECK(err != -1);
ssize_t result = fread(data, 1, size, mFile);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index d1f8cd4..698223b 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-#undef NDEBUG
-#include <assert.h>
-
#include <stdlib.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/string.h>
namespace android {
@@ -32,7 +30,7 @@
mBuffer(malloc(kBufferSize)),
mBufferLength(0),
mBufferOffset(0) {
- assert(!strncasecmp("http://", uri, 7));
+ CHECK(!strncasecmp("http://", uri, 7));
string host;
string path;
@@ -53,8 +51,8 @@
} else {
char *end;
long tmp = strtol(colon + 1, &end, 10);
- assert(end > colon + 1);
- assert(tmp > 0 && tmp < 65536);
+ CHECK(end > colon + 1);
+ CHECK(tmp > 0 && tmp < 65536);
port = tmp;
host = string(host, 0, colon - host.c_str());
@@ -68,7 +66,7 @@
mPath = strdup(path.c_str());
status_t err = mHttp.connect(mHost, mPort);
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
@@ -79,7 +77,7 @@
mBufferLength(0),
mBufferOffset(0) {
status_t err = mHttp.connect(mHost, mPort);
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
HTTPDataSource::~HTTPDataSource() {
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 29e6f72..098ddbd 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -17,7 +17,6 @@
#include <sys/socket.h>
#include <arpa/inet.h>
-#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
@@ -27,6 +26,7 @@
#include <unistd.h>
#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
namespace android {
@@ -49,7 +49,7 @@
return ERROR_ALREADY_CONNECTED;
}
- assert(mSocket == -1);
+ CHECK_EQ(mSocket, -1);
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mSocket < 0) {
@@ -89,7 +89,7 @@
return ERROR_NOT_CONNECTED;
}
- assert(mSocket >= 0);
+ CHECK(mSocket >= 0);
close(mSocket);
mSocket = -1;
@@ -165,7 +165,7 @@
saw_CR = (c == '\r');
- assert(length + 1 < size);
+ CHECK(length + 1 < size);
line[length++] = c;
}
}
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 01cb2d9..14f3e0c 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -18,13 +18,11 @@
#define LOG_TAG "MP3Extractor"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MP3Extractor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
@@ -165,7 +163,7 @@
}
static bool Resync(
- DataSource *source, uint32_t match_header,
+ const sp<DataSource> &source, uint32_t match_header,
off_t *inout_pos, uint32_t *out_header) {
// Everything must match except for
// protection, bitrate, padding, private bits and mode extension.
@@ -281,11 +279,9 @@
class MP3Source : public MediaSource {
public:
MP3Source(
- const sp<MetaData> &meta, DataSource *source,
+ const sp<MetaData> &meta, const sp<DataSource> &source,
off_t first_frame_pos, uint32_t fixed_header);
- virtual ~MP3Source();
-
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -294,9 +290,12 @@
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
+protected:
+ virtual ~MP3Source();
+
private:
sp<MetaData> mMeta;
- DataSource *mDataSource;
+ sp<DataSource> mDataSource;
off_t mFirstFramePos;
uint32_t mFixedHeader;
off_t mCurrentPos;
@@ -309,14 +308,14 @@
MP3Source &operator=(const MP3Source &);
};
-MP3Extractor::MP3Extractor(DataSource *source)
+MP3Extractor::MP3Extractor(const sp<DataSource> &source)
: mDataSource(source),
mFirstFramePos(-1),
mFixedHeader(0) {
off_t pos = 0;
uint32_t header;
bool success = Resync(mDataSource, 0, &pos, &header);
- assert(success);
+ CHECK(success);
if (success) {
mFirstFramePos = pos;
@@ -347,28 +346,22 @@
}
MP3Extractor::~MP3Extractor() {
- delete mDataSource;
- mDataSource = NULL;
}
-status_t MP3Extractor::countTracks(int *num_tracks) {
- *num_tracks = mFirstFramePos < 0 ? 0 : 1;
-
- return OK;
+size_t MP3Extractor::countTracks() {
+ return (mFirstFramePos < 0) ? 0 : 1;
}
-status_t MP3Extractor::getTrack(int index, MediaSource **source) {
+sp<MediaSource> MP3Extractor::getTrack(size_t index) {
if (mFirstFramePos < 0 || index != 0) {
- return ERROR_OUT_OF_RANGE;
+ return NULL;
}
- *source = new MP3Source(
+ return new MP3Source(
mMeta, mDataSource, mFirstFramePos, mFixedHeader);
-
- return OK;
}
-sp<MetaData> MP3Extractor::getTrackMetaData(int index) {
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
if (mFirstFramePos < 0 || index != 0) {
return NULL;
}
@@ -379,7 +372,7 @@
////////////////////////////////////////////////////////////////////////////////
MP3Source::MP3Source(
- const sp<MetaData> &meta, DataSource *source,
+ const sp<MetaData> &meta, const sp<DataSource> &source,
off_t first_frame_pos, uint32_t fixed_header)
: mMeta(meta),
mDataSource(source),
@@ -398,7 +391,7 @@
}
status_t MP3Source::start(MetaData *) {
- assert(!mStarted);
+ CHECK(!mStarted);
mGroup = new MediaBufferGroup;
@@ -414,7 +407,7 @@
}
status_t MP3Source::stop() {
- assert(mStarted);
+ CHECK(mStarted);
delete mGroup;
mGroup = NULL;
@@ -486,7 +479,7 @@
// Try again with the new position.
}
- assert(frame_size <= buffer->size());
+ CHECK(frame_size <= buffer->size());
ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
if (n < (ssize_t)frame_size) {
@@ -509,7 +502,8 @@
return OK;
}
-bool SniffMP3(DataSource *source, String8 *mimeType, float *confidence) {
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
off_t pos = 0;
uint32_t header;
if (!Resync(source, 0, &pos, &header)) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 4c883c6..894d46c 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,9 +19,6 @@
#include <arpa/inet.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
@@ -31,6 +28,7 @@
#include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/SampleTable.h>
@@ -42,10 +40,9 @@
class MPEG4Source : public MediaSource {
public:
// Caller retains ownership of both "dataSource" and "sampleTable".
- MPEG4Source(const sp<MetaData> &format, DataSource *dataSource,
- SampleTable *sampleTable);
-
- virtual ~MPEG4Source();
+ MPEG4Source(const sp<MetaData> &format,
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -55,11 +52,14 @@
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
+protected:
+ virtual ~MPEG4Source();
+
private:
sp<MetaData> mFormat;
- DataSource *mDataSource;
+ sp<DataSource> mDataSource;
int32_t mTimescale;
- SampleTable *mSampleTable;
+ sp<SampleTable> mSampleTable;
uint32_t mCurrentSampleIndex;
bool mIsAVC;
@@ -68,10 +68,8 @@
MediaBufferGroup *mGroup;
MediaBuffer *mBuffer;
- size_t mBufferOffset;
- size_t mBufferSizeRemaining;
- bool mNeedsNALFraming;
+ bool mWantsNALFragments;
uint8_t *mSrcBuffer;
@@ -136,12 +134,12 @@
return "video/avc";
default:
- assert(!"should not be here.");
+ CHECK(!"should not be here.");
return NULL;
}
}
-MPEG4Extractor::MPEG4Extractor(DataSource *source)
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
: mDataSource(source),
mHaveMetadata(false),
mFirstTrack(NULL),
@@ -153,39 +151,29 @@
while (track) {
Track *next = track->next;
- delete track->sampleTable;
- track->sampleTable = NULL;
-
delete track;
track = next;
}
mFirstTrack = mLastTrack = NULL;
-
- delete mDataSource;
- mDataSource = NULL;
}
-status_t MPEG4Extractor::countTracks(int *num_tracks) {
+size_t MPEG4Extractor::countTracks() {
status_t err;
if ((err = readMetaData()) != OK) {
- return err;
+ return 0;
}
- *num_tracks = 0;
+ size_t n = 0;
Track *track = mFirstTrack;
while (track) {
- ++*num_tracks;
+ ++n;
track = track->next;
}
- return OK;
+ return n;
}
-sp<MetaData> MPEG4Extractor::getTrackMetaData(int index) {
- if (index < 0) {
- return NULL;
- }
-
+sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -287,7 +275,7 @@
return err;
}
}
- assert(*offset == stop_offset);
+ CHECK_EQ(*offset, stop_offset);
if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
mHaveMetadata = true;
@@ -299,7 +287,7 @@
case FOURCC('t', 'k', 'h', 'd'):
{
- assert(chunk_data_size >= 4);
+ CHECK(chunk_data_size >= 4);
uint8_t version;
if (mDataSource->read_at(data_offset, &version, 1) < 1) {
@@ -452,7 +440,7 @@
}
uint8_t buffer[8];
- assert(chunk_data_size >= (off_t)sizeof(buffer));
+ CHECK(chunk_data_size >= (off_t)sizeof(buffer));
if (mDataSource->read_at(
data_offset, buffer, 8) < 8) {
return ERROR_IO;
@@ -478,7 +466,7 @@
return err;
}
}
- assert(*offset == stop_offset);
+ CHECK_EQ(*offset, stop_offset);
break;
}
@@ -526,7 +514,7 @@
return err;
}
}
- assert(*offset == stop_offset);
+ CHECK_EQ(*offset, stop_offset);
break;
}
@@ -568,7 +556,7 @@
return err;
}
}
- assert(*offset == stop_offset);
+ CHECK_EQ(*offset, stop_offset);
break;
}
@@ -701,39 +689,32 @@
return OK;
}
-status_t MPEG4Extractor::getTrack(int index, MediaSource **source) {
- *source = NULL;
-
- if (index < 0) {
- return ERROR_OUT_OF_RANGE;
- }
-
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
- return err;
+ return NULL;
}
Track *track = mFirstTrack;
while (index > 0) {
if (track == NULL) {
- return ERROR_OUT_OF_RANGE;
+ return NULL;
}
track = track->next;
--index;
}
- *source = new MPEG4Source(
+ return new MPEG4Source(
track->meta, mDataSource, track->sampleTable);
-
- return OK;
}
////////////////////////////////////////////////////////////////////////////////
MPEG4Source::MPEG4Source(
const sp<MetaData> &format,
- DataSource *dataSource, SampleTable *sampleTable)
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable)
: mFormat(format),
mDataSource(dataSource),
mTimescale(0),
@@ -743,16 +724,14 @@
mStarted(false),
mGroup(NULL),
mBuffer(NULL),
- mBufferOffset(0),
- mBufferSizeRemaining(0),
- mNeedsNALFraming(false),
+ mWantsNALFragments(false),
mSrcBuffer(NULL) {
const char *mime;
bool success = mFormat->findCString(kKeyMIMEType, &mime);
- assert(success);
+ CHECK(success);
success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
- assert(success);
+ CHECK(success);
mIsAVC = !strcasecmp(mime, "video/avc");
}
@@ -764,21 +743,21 @@
}
status_t MPEG4Source::start(MetaData *params) {
- assert(!mStarted);
+ CHECK(!mStarted);
int32_t val;
- if (mIsAVC && params && params->findInt32(kKeyNeedsNALFraming, &val)
+ if (params && params->findInt32(kKeyWantsNALFragments, &val)
&& val != 0) {
- mNeedsNALFraming = true;
+ mWantsNALFragments = true;
} else {
- mNeedsNALFraming = false;
+ mWantsNALFragments = false;
}
mGroup = new MediaBufferGroup;
size_t max_size;
status_t err = mSampleTable->getMaxSampleSize(&max_size);
- assert(err == OK);
+ CHECK_EQ(err, OK);
// Assume that a given buffer only contains at most 10 fragments,
// each fragment originally prefixed with a 2 byte length will
@@ -794,7 +773,7 @@
}
status_t MPEG4Source::stop() {
- assert(mStarted);
+ CHECK(mStarted);
if (mBuffer != NULL) {
mBuffer->release();
@@ -819,7 +798,7 @@
status_t MPEG4Source::read(
MediaBuffer **out, const ReadOptions *options) {
- assert(mStarted);
+ CHECK(mStarted);
*out = NULL;
@@ -845,38 +824,124 @@
off_t offset;
size_t size;
- status_t err = mSampleTable->getSampleOffsetAndSize(
- mCurrentSampleIndex, &offset, &size);
-
- if (err != OK) {
- return err;
- }
-
uint32_t dts;
- err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+ bool newBuffer = false;
+ if (mBuffer == NULL) {
+ newBuffer = true;
- if (err != OK) {
- return err;
+ status_t err = mSampleTable->getSampleOffsetAndSize(
+ mCurrentSampleIndex, &offset, &size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = mGroup->acquire_buffer(&mBuffer);
+ if (err != OK) {
+ CHECK_EQ(mBuffer, NULL);
+ return err;
+ }
}
- err = mGroup->acquire_buffer(&mBuffer);
- if (err != OK) {
- assert(mBuffer == NULL);
- return err;
- }
+ if (!mIsAVC || mWantsNALFragments) {
+ if (newBuffer) {
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
- if (!mIsAVC || !mNeedsNALFraming) {
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+ }
+
+ if (!mIsAVC) {
+ *out = mBuffer;
+ mBuffer = NULL;
+
+ return OK;
+ }
+
+ // Each NAL unit is split up into its constituent fragments and
+ // each one of them returned in its own buffer.
+
+ CHECK(mBuffer->range_length() >= 2);
+
+ const uint8_t *src =
+ (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
+
+ size_t nal_size = U16_AT(src);
+
+ CHECK(mBuffer->range_length() >= 2 + nal_size);
+
+ MediaBuffer *clone = mBuffer->clone();
+ clone->set_range(mBuffer->range_offset() + 2, nal_size);
+
+ mBuffer->set_range(
+ mBuffer->range_offset() + 2 + nal_size,
+ mBuffer->range_length() - 2 - nal_size);
+
+ if (mBuffer->range_length() == 0) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ *out = clone;
+
+ return OK;
+ } else {
+ // Whole NAL units are returned but each fragment is prefixed by
+ // the start code (0x00 00 00 01).
+
ssize_t num_bytes_read =
- mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+ mDataSource->read_at(offset, mSrcBuffer, size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
mBuffer = NULL;
- return err;
+ return ERROR_IO;
}
- mBuffer->set_range(0, size);
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
+ while (srcOffset < size) {
+ CHECK(srcOffset + 1 < size);
+ size_t nalLength =
+ (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+ CHECK(srcOffset + 1 + nalLength < size);
+ srcOffset += 2;
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ CHECK(dstOffset + 4 <= mBuffer->size());
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
+ }
+
+ mBuffer->set_range(0, dstOffset);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
@@ -887,55 +952,10 @@
return OK;
}
-
- ssize_t num_bytes_read =
- mDataSource->read_at(offset, mSrcBuffer, size);
-
- if (num_bytes_read < (ssize_t)size) {
- mBuffer->release();
- mBuffer = NULL;
-
- return err;
- }
-
- uint8_t *dstData = (uint8_t *)mBuffer->data();
- size_t srcOffset = 0;
- size_t dstOffset = 0;
- while (srcOffset < size) {
- assert(srcOffset + 1 < size);
- size_t nalLength =
- (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
- assert(srcOffset + 1 + nalLength < size);
- srcOffset += 2;
-
- if (nalLength == 0) {
- continue;
- }
-
- assert(dstOffset + 4 <= mBuffer->size());
-
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 1;
- memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
- srcOffset += nalLength;
- dstOffset += nalLength;
- }
-
- mBuffer->set_range(0, dstOffset);
- mBuffer->meta_data()->clear();
- mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
- mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
- ++mCurrentSampleIndex;
-
- *out = mBuffer;
- mBuffer = NULL;
-
- return OK;
}
-bool SniffMPEG4(DataSource *source, String8 *mimeType, float *confidence) {
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
uint8_t header[8];
ssize_t n = source->read_at(4, header, sizeof(header));
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b53bb29..90b1b9a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -16,15 +16,13 @@
#include <arpa/inet.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <ctype.h>
#include <pthread.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
@@ -32,7 +30,8 @@
class MPEG4Writer::Track {
public:
- Track(MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source);
+ Track(MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source);
~Track();
void start();
@@ -44,7 +43,7 @@
private:
MPEG4Writer *mOwner;
sp<MetaData> mMeta;
- MediaSource *mSource;
+ sp<MediaSource> mSource;
volatile bool mDone;
pthread_t mThread;
@@ -70,7 +69,7 @@
: mFile(fopen(filename, "wb")),
mOffset(0),
mMdatOffset(0) {
- assert(mFile != NULL);
+ CHECK(mFile != NULL);
}
MPEG4Writer::~MPEG4Writer() {
@@ -83,7 +82,8 @@
mTracks.clear();
}
-void MPEG4Writer::addSource(const sp<MetaData> &meta, MediaSource *source) {
+void MPEG4Writer::addSource(
+ const sp<MetaData> &meta, const sp<MediaSource> &source) {
Track *track = new Track(this, meta, source);
mTracks.push_back(track);
}
@@ -171,7 +171,7 @@
}
endBox(); // moov
- assert(mBoxes.empty());
+ CHECK(mBoxes.empty());
fclose(mFile);
mFile = NULL;
@@ -191,7 +191,7 @@
}
void MPEG4Writer::beginBox(const char *fourcc) {
- assert(strlen(fourcc) == 4);
+ CHECK_EQ(strlen(fourcc), 4);
mBoxes.push_back(mOffset);
@@ -200,7 +200,7 @@
}
void MPEG4Writer::endBox() {
- assert(!mBoxes.empty());
+ CHECK(!mBoxes.empty());
off_t offset = *--mBoxes.end();
mBoxes.erase(--mBoxes.end());
@@ -242,7 +242,7 @@
}
void MPEG4Writer::writeFourcc(const char *s) {
- assert(strlen(s) == 4);
+ CHECK_EQ(strlen(s), 4);
fwrite(s, 1, 4, mFile);
mOffset += 4;
}
@@ -255,7 +255,8 @@
////////////////////////////////////////////////////////////////////////////////
MPEG4Writer::Track::Track(
- MPEG4Writer *owner, const sp<MetaData> &meta, MediaSource *source)
+ MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source)
: mOwner(owner),
mMeta(meta),
mSource(source),
@@ -283,7 +284,7 @@
mDone = false;
int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
- assert(err == 0);
+ CHECK_EQ(err, 0);
pthread_attr_destroy(&attr);
}
@@ -342,7 +343,7 @@
++offset;
}
- // assert(offset + 3 < size);
+ // CHECK(offset + 3 < size);
if (offset + 3 >= size) {
// XXX assume the entire first chunk of data is the codec specific
// data.
@@ -365,10 +366,10 @@
int32_t units, scale;
bool success =
buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
- assert(success);
+ CHECK(success);
success =
buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- assert(success);
+ CHECK(success);
info.timestamp = (int64_t)units * 1000 / scale;
@@ -386,7 +387,7 @@
void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
- assert(success);
+ CHECK(success);
bool is_audio = !strncasecmp(mime, "audio/", 6);
@@ -425,7 +426,7 @@
int32_t width, height;
bool success = mMeta->findInt32(kKeyWidth, &width);
success = success && mMeta->findInt32(kKeyHeight, &height);
- assert(success);
+ CHECK(success);
mOwner->writeInt32(width);
mOwner->writeInt32(height);
@@ -502,7 +503,7 @@
int32_t samplerate;
bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
- assert(success);
+ CHECK(success);
mOwner->writeInt32(samplerate << 16);
mOwner->endBox();
@@ -512,7 +513,7 @@
} else if (!strcasecmp("video/3gpp", mime)) {
mOwner->beginBox("s263");
} else {
- assert(!"should not be here, unknown mime type.");
+ CHECK(!"should not be here, unknown mime type.");
}
mOwner->writeInt32(0); // reserved
@@ -527,7 +528,7 @@
int32_t width, height;
bool success = mMeta->findInt32(kKeyWidth, &width);
success = success && mMeta->findInt32(kKeyHeight, &height);
- assert(success);
+ CHECK(success);
mOwner->writeInt16(width);
mOwner->writeInt16(height);
@@ -539,7 +540,7 @@
mOwner->writeInt16(0x18); // depth
mOwner->writeInt16(-1); // predefined
- assert(23 + mCodecSpecificDataSize < 128);
+ CHECK(23 + mCodecSpecificDataSize < 128);
if (!strcasecmp("video/mp4v-es", mime)) {
mOwner->beginBox("esds");
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index cd78dbd..f3c0e73 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -17,14 +17,12 @@
#define LOG_TAG "MediaBuffer"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
namespace android {
@@ -65,7 +63,7 @@
void MediaBuffer::release() {
if (mObserver == NULL) {
- assert(mRefCount == 0);
+ CHECK_EQ(mRefCount, 0);
delete this;
return;
}
@@ -79,12 +77,12 @@
mObserver->signalBufferReturned(this);
}
- assert(prevCount > 0);
+ CHECK(prevCount > 0);
}
void MediaBuffer::claim() {
- assert(mObserver != NULL);
- assert(mRefCount == 1);
+ CHECK(mObserver != NULL);
+ CHECK_EQ(mRefCount, 1);
mRefCount = 0;
}
@@ -113,7 +111,7 @@
if (offset < 0 || offset + length > mSize) {
LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
}
- assert(offset >= 0 && offset + length <= mSize);
+ CHECK(offset >= 0 && offset + length <= mSize);
mRangeOffset = offset;
mRangeLength = length;
@@ -129,7 +127,7 @@
}
MediaBuffer::~MediaBuffer() {
- assert(mObserver == NULL);
+ CHECK_EQ(mObserver, NULL);
if (mOwnsData && mData != NULL) {
free(mData);
@@ -143,7 +141,7 @@
}
void MediaBuffer::setObserver(MediaBufferObserver *observer) {
- assert(observer == NULL || mObserver == NULL);
+ CHECK(observer == NULL || mObserver == NULL);
mObserver = observer;
}
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
index aec7722..c8d05f4 100644
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -17,11 +17,9 @@
#define LOG_TAG "MediaBufferGroup"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
namespace android {
@@ -36,7 +34,7 @@
buffer = next) {
next = buffer->nextBuffer();
- assert(buffer->refcount() == 0);
+ CHECK_EQ(buffer->refcount(), 0);
buffer->setObserver(NULL);
buffer->release();
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index bc66794..5f78e12 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -27,7 +27,8 @@
namespace android {
// static
-MediaExtractor *MediaExtractor::Create(DataSource *source, const char *mime) {
+sp<MediaExtractor> MediaExtractor::Create(
+ const sp<DataSource> &source, const char *mime) {
String8 tmp;
if (mime == NULL) {
float confidence;
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index f2e62f5..e5301bb 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,9 +18,6 @@
#define LOG_TAG "MediaPlayerImpl"
#include "utils/Log.h"
-#undef NDEBUG
-#include <assert.h>
-
#include <OMX_Component.h>
#include <unistd.h>
@@ -30,36 +27,33 @@
// #include <media/stagefright/CameraSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
#include <media/stagefright/ShoutcastSource.h>
#include <media/stagefright/TimeSource.h>
#include <ui/PixelFormat.h>
#include <ui/Surface.h>
+#define USE_OMX_CODEC 1
+
namespace android {
MediaPlayerImpl::MediaPlayerImpl(const char *uri)
: mInitCheck(NO_INIT),
- mExtractor(NULL),
mTimeSource(NULL),
- mAudioSource(NULL),
- mAudioDecoder(NULL),
mAudioPlayer(NULL),
- mVideoSource(NULL),
- mVideoDecoder(NULL),
mVideoWidth(0),
mVideoHeight(0),
mVideoPosition(0),
mDuration(0),
mPlaying(false),
mPaused(false),
- mSeeking(false),
- mFrameSize(0),
- mUseSoftwareColorConversion(false) {
+ mSeeking(false) {
LOGI("MediaPlayerImpl(%s)", uri);
DataSource::RegisterDefaultSniffers();
@@ -78,7 +72,7 @@
mVideoDecoder = CameraSource::Create();
#endif
} else {
- DataSource *source = NULL;
+ sp<DataSource> source;
if (!strncasecmp("file://", uri, 7)) {
source = new MmapSource(uri + 7);
} else if (!strncasecmp("http://", uri, 7)) {
@@ -103,22 +97,15 @@
MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
: mInitCheck(NO_INIT),
- mExtractor(NULL),
mTimeSource(NULL),
- mAudioSource(NULL),
- mAudioDecoder(NULL),
mAudioPlayer(NULL),
- mVideoSource(NULL),
- mVideoDecoder(NULL),
mVideoWidth(0),
mVideoHeight(0),
mVideoPosition(0),
mDuration(0),
mPlaying(false),
mPaused(false),
- mSeeking(false),
- mFrameSize(0),
- mUseSoftwareColorConversion(false) {
+ mSeeking(false) {
LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
DataSource::RegisterDefaultSniffers();
@@ -148,23 +135,6 @@
stop();
setSurface(NULL);
- LOGV("Shutting down audio.");
- delete mAudioDecoder;
- mAudioDecoder = NULL;
-
- delete mAudioSource;
- mAudioSource = NULL;
-
- LOGV("Shutting down video.");
- delete mVideoDecoder;
- mVideoDecoder = NULL;
-
- delete mVideoSource;
- mVideoSource = NULL;
-
- delete mExtractor;
- mExtractor = NULL;
-
if (mInitCheck == OK) {
mClient.disconnect();
}
@@ -255,7 +225,7 @@
bool eof = false;
status_t err = mVideoDecoder->start();
- assert(err == OK);
+ CHECK_EQ(err, OK);
while (mPlaying) {
MediaBuffer *buffer;
@@ -281,7 +251,7 @@
}
status_t err = mVideoDecoder->read(&buffer, &options);
- assert((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
+ CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
if (err == ERROR_END_OF_STREAM || err != OK) {
eof = true;
@@ -297,10 +267,10 @@
int32_t units, scale;
bool success =
buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
- assert(success);
+ CHECK(success);
success =
buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- assert(success);
+ CHECK(success);
int64_t pts_us = (int64_t)units * 1000000 / scale;
{
@@ -384,14 +354,13 @@
void MediaPlayerImpl::init() {
if (mExtractor != NULL) {
- int num_tracks;
- assert(mExtractor->countTracks(&num_tracks) == OK);
+ size_t num_tracks = mExtractor->countTracks();
mDuration = 0;
- for (int i = 0; i < num_tracks; ++i) {
+ for (size_t i = 0; i < num_tracks; ++i) {
const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
- assert(meta != NULL);
+ CHECK(meta != NULL);
const char *mime;
if (!meta->findCString(kKeyMIMEType, &mime)) {
@@ -411,10 +380,7 @@
continue;
}
- MediaSource *source;
- if (mExtractor->getTrack(i, &source) != OK) {
- continue;
- }
+ sp<MediaSource> source = mExtractor->getTrack(i);
int32_t units, scale;
if (meta->findInt32(kKeyDuration, &units)
@@ -434,30 +400,40 @@
}
}
-void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
LOGI("setAudioSource");
mAudioSource = source;
sp<MetaData> meta = source->getFormat();
- mAudioDecoder = OMXDecoder::Create(&mClient, meta);
- mAudioDecoder->setSource(source);
+#if !USE_OMX_CODEC
+ mAudioDecoder = OMXDecoder::Create(
+ &mClient, meta, false /* createEncoder */, source);
+#else
+ mAudioDecoder = OMXCodec::Create(
+ mClient.interface(), meta, false /* createEncoder */, source);
+#endif
}
-void MediaPlayerImpl::setVideoSource(MediaSource *source) {
+void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
LOGI("setVideoSource");
mVideoSource = source;
sp<MetaData> meta = source->getFormat();
bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
- assert(success);
+ CHECK(success);
success = meta->findInt32(kKeyHeight, &mVideoHeight);
- assert(success);
+ CHECK(success);
- mVideoDecoder = OMXDecoder::Create(&mClient, meta);
- ((OMXDecoder *)mVideoDecoder)->setSource(source);
+#if !USE_OMX_CODEC
+ mVideoDecoder = OMXDecoder::Create(
+ &mClient, meta, false /* createEncoder */, source);
+#else
+ mVideoDecoder = OMXCodec::Create(
+ mClient.interface(), meta, false /* createEncoder */, source);
+#endif
if (mISurface.get() != NULL || mSurface.get() != NULL) {
depopulateISurface();
@@ -517,8 +493,8 @@
} else {
char *end;
long tmp = strtol(colon + 1, &end, 10);
- assert(end > colon + 1);
- assert(tmp > 0 && tmp < 65536);
+ CHECK(end > colon + 1);
+ CHECK(tmp > 0 && tmp < 65536);
port = tmp;
host = string(host, 0, colon - host.c_str());
@@ -532,7 +508,7 @@
for (;;) {
status_t err = http->connect(host.c_str(), port);
- assert(err == OK);
+ CHECK_EQ(err, OK);
err = http->send("GET ");
err = http->send(path.c_str());
@@ -542,13 +518,13 @@
err = http->send("\r\n");
err = http->send("Icy-MetaData: 1\r\n\r\n");
- assert(OK == http->receive_header(&http_status));
+ CHECK_EQ(OK, http->receive_header(&http_status));
if (http_status == 301 || http_status == 302) {
string location;
- assert(http->find_header_value("Location", &location));
+ CHECK(http->find_header_value("Location", &location));
- assert(string(location, 0, 7) == "http://");
+ CHECK(string(location, 0, 7) == "http://");
location.erase(0, 7);
string::size_type slashPos = location.find('/');
if (slashPos == string::npos) {
@@ -567,7 +543,7 @@
const char *start = host.c_str() + colonPos + 1;
char *end;
long tmp = strtol(start, &end, 10);
- assert(end > start && *end == '\0');
+ CHECK(end > start && (*end == '\0'));
port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
} else {
@@ -644,7 +620,7 @@
success = success && meta->findCString(kKeyDecoderComponent, &component);
success = success && meta->findInt32(kKeyWidth, &decodedWidth);
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
- assert(success);
+ CHECK(success);
if (mSurface.get() != NULL) {
mVideoRenderer =
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 5d23732b..6b067cb 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
namespace android {
@@ -87,7 +87,7 @@
return false;
}
- assert(size == sizeof(*value));
+ CHECK_EQ(size, sizeof(*value));
*value = *(int32_t *)data;
@@ -102,7 +102,7 @@
return false;
}
- assert(size == sizeof(*value));
+ CHECK_EQ(size, sizeof(*value));
*value = *(float *)data;
@@ -117,7 +117,7 @@
return false;
}
- assert(size == sizeof(*value));
+ CHECK_EQ(size, sizeof(*value));
*value = *(void **)data;
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
index 7cb861c..47d95f9 100644
--- a/media/libstagefright/MmapSource.cpp
+++ b/media/libstagefright/MmapSource.cpp
@@ -20,13 +20,11 @@
#include <sys/mman.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MmapSource.h>
namespace android {
@@ -36,7 +34,7 @@
mBase(NULL),
mSize(0) {
LOGV("MmapSource '%s'", filename);
- assert(mFd >= 0);
+ CHECK(mFd >= 0);
off_t size = lseek(mFd, 0, SEEK_END);
mSize = (size_t)size;
@@ -56,7 +54,7 @@
mBase(NULL),
mSize(length) {
LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length);
- assert(fd >= 0);
+ CHECK(fd >= 0);
mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset);
@@ -86,7 +84,7 @@
ssize_t MmapSource::read_at(off_t offset, void *data, size_t size) {
LOGV("read_at offset:%ld data:%p size:%d", offset, data, size);
- assert(offset >= 0);
+ CHECK(offset >= 0);
size_t avail = 0;
if (offset >= 0 && offset < (off_t)mSize) {
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 3e7cf3c..2a32b4c 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -20,12 +20,10 @@
#include <sys/socket.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
#include <media/IOMX.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/OMXClient.h>
namespace android {
@@ -44,10 +42,10 @@
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- assert(service.get() != NULL);
+ CHECK(service.get() != NULL);
mOMX = service->createOMX();
- assert(mOMX.get() != NULL);
+ CHECK(mOMX.get() != NULL);
mReflector = new OMXClientReflector(this);
@@ -61,7 +59,7 @@
return;
}
- assert(mObservers.isEmpty());
+ CHECK(mObservers.isEmpty());
mReflector->reset();
mReflector.clear();
@@ -88,7 +86,7 @@
Mutex::Autolock autoLock(mLock);
ssize_t index = mObservers.indexOfKey(node);
- assert(index >= 0);
+ CHECK(index >= 0);
if (index < 0) {
return;
@@ -132,7 +130,7 @@
}
Mutex::Autolock autoLock(mLock);
- ssize_t index = mObservers.indexOfKey(msg.u.buffer_data.node);
+ ssize_t index = mObservers.indexOfKey(msg.node);
if (index >= 0) {
mObservers.editValueAt(index)->postMessage(msg);
@@ -155,7 +153,7 @@
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
- assert(err == 0);
+ CHECK_EQ(err, 0);
pthread_attr_destroy(&attr);
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
new file mode 100644
index 0000000..cdaba7c
--- /dev/null
+++ b/media/libstagefright/OMXCodec.cpp
@@ -0,0 +1,2097 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OMXCodec"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <binder/ProcessState.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/ESDS.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+#include <utils/Vector.h>
+
+#include <OMX_Audio.h>
+#include <OMX_Component.h>
+
+namespace android {
+
+struct CodecInfo {
+ const char *mime;
+ const char *codec;
+};
+
+static const CodecInfo kDecoderInfo[] = {
+ { "image/jpeg", "OMX.TI.JPEG.decode" },
+ { "audio/mpeg", "OMX.TI.MP3.decode" },
+ { "audio/mpeg", "OMX.PV.mp3dec" },
+ { "audio/3gpp", "OMX.TI.AMR.decode" },
+ { "audio/3gpp", "OMX.PV.amrdec" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
+ { "audio/mp4a-latm", "OMX.PV.aacdec" },
+ { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.Decoder" },
+ { "video/mp4v-es", "OMX.PV.mpeg4dec" },
+ { "video/3gpp", "OMX.qcom.video.decoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.Decoder" },
+ { "video/3gpp", "OMX.PV.h263dec" },
+ { "video/avc", "OMX.qcom.video.decoder.avc" },
+ { "video/avc", "OMX.TI.Video.Decoder" },
+ { "video/avc", "OMX.PV.avcdec" },
+};
+
+static const CodecInfo kEncoderInfo[] = {
+ { "audio/3gpp", "OMX.TI.AMR.encode" },
+ { "audio/3gpp", "OMX.PV.amrencnb" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
+ { "audio/mp4a-latm", "OMX.PV.aacenc" },
+ { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.encoder" },
+ { "video/mp4v-es", "OMX.PV.mpeg4enc" },
+ { "video/3gpp", "OMX.qcom.video.encoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.encoder" },
+ { "video/3gpp", "OMX.PV.h263enc" },
+ { "video/avc", "OMX.TI.Video.encoder" },
+ { "video/avc", "OMX.PV.avcenc" },
+};
+
+struct OMXCodecObserver : public BnOMXObserver {
+ OMXCodecObserver(const wp<OMXCodec> &target)
+ : mTarget(target) {
+ }
+
+ // from IOMXObserver
+ virtual void on_message(const omx_message &msg) {
+ sp<OMXCodec> codec = mTarget.promote();
+
+ if (codec.get() != NULL) {
+ codec->on_message(msg);
+ }
+ }
+
+protected:
+ virtual ~OMXCodecObserver() {}
+
+private:
+ wp<OMXCodec> mTarget;
+
+ OMXCodecObserver(const OMXCodecObserver &);
+ OMXCodecObserver &operator=(const OMXCodecObserver &);
+};
+
+static const char *GetCodec(const CodecInfo *info, size_t numInfos,
+ const char *mime, int index) {
+ CHECK(index >= 0);
+ for(size_t i = 0; i < numInfos; ++i) {
+ if (!strcasecmp(mime, info[i].mime)) {
+ if (index == 0) {
+ return info[i].codec;
+ }
+
+ --index;
+ }
+ }
+
+ return NULL;
+}
+
+enum {
+ kAVCProfileBaseline = 0x42,
+ kAVCProfileMain = 0x4d,
+ kAVCProfileExtended = 0x58,
+ kAVCProfileHigh = 0x64,
+ kAVCProfileHigh10 = 0x6e,
+ kAVCProfileHigh422 = 0x7a,
+ kAVCProfileHigh444 = 0xf4,
+ kAVCProfileCAVLC444Intra = 0x2c
+};
+
+static const char *AVCProfileToString(uint8_t profile) {
+ switch (profile) {
+ case kAVCProfileBaseline:
+ return "Baseline";
+ case kAVCProfileMain:
+ return "Main";
+ case kAVCProfileExtended:
+ return "Extended";
+ case kAVCProfileHigh:
+ return "High";
+ case kAVCProfileHigh10:
+ return "High 10";
+ case kAVCProfileHigh422:
+ return "High 422";
+ case kAVCProfileHigh444:
+ return "High 444";
+ case kAVCProfileCAVLC444Intra:
+ return "CAVLC 444 Intra";
+ default: return "Unknown";
+ }
+}
+
+// static
+sp<OMXCodec> OMXCodec::Create(
+ const sp<IOMX> &omx,
+ const sp<MetaData> &meta, bool createEncoder,
+ const sp<MediaSource> &source) {
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+
+ const char *componentName = NULL;
+ IOMX::node_id node = 0;
+ for (int index = 0;; ++index) {
+ if (createEncoder) {
+ componentName = GetCodec(
+ kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ componentName = GetCodec(
+ kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
+
+ if (!componentName) {
+ return NULL;
+ }
+
+ LOGV("Attempting to allocate OMX node '%s'", componentName);
+
+ status_t err = omx->allocate_node(componentName, &node);
+ if (err == OK) {
+ break;
+ }
+ }
+
+ uint32_t quirks = 0;
+ if (!strcmp(componentName, "OMX.PV.avcdec")) {
+ quirks |= kWantsNALFragments;
+ }
+ if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ quirks |= kRequiresFlushCompleteEmulation;
+ }
+ if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+
+ sp<OMXCodec> codec = new OMXCodec(
+ omx, node, quirks, createEncoder, mime, componentName,
+ source);
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
+
+ printf("found codec-specific data of size %d\n",
+ codec_specific_data_size);
+
+ codec->addCodecSpecificData(
+ codec_specific_data, codec_specific_data_size);
+ } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ printf("found avcc of size %d\n", size);
+
+ // Parse the AVCDecoderConfigurationRecord
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
+
+ CHECK((ptr[4] >> 2) == 0x3f); // reserved
+
+ size_t lengthSize = 1 + (ptr[4] & 3);
+
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
+
+ size_t numSeqParameterSets = ptr[5] & 31;
+
+ ptr += 6;
+ size -= 6;
+
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
+
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ LOGI("AVC profile = %d (%s), level = %d",
+ (int)profile, AVCProfileToString(profile), (int)level / 10);
+
+ if (!strcmp(componentName, "OMX.TI.Video.Decoder")
+ && (profile != kAVCProfileBaseline || level > 39)) {
+ // This stream exceeds the decoder's capabilities.
+
+ LOGE("Profile and/or level exceed the decoder's capabilities.");
+ return NULL;
+ }
+ }
+
+ if (!strcasecmp("audio/3gpp", mime)) {
+ codec->setAMRFormat();
+ }
+ if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
+ codec->setAACFormat();
+ }
+ if (!strncasecmp(mime, "video/", 6)) {
+ int32_t width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+ CHECK(success);
+
+ if (createEncoder) {
+ codec->setVideoInputFormat(mime, width, height);
+ } else {
+ codec->setVideoOutputFormat(mime, width, height);
+ }
+ }
+ if (!strcasecmp(mime, "image/jpeg")
+ && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
+ OMX_COLOR_FORMATTYPE format =
+ OMX_COLOR_Format32bitARGB8888;
+ // OMX_COLOR_FormatYUV420PackedPlanar;
+ // OMX_COLOR_FormatCbYCrY;
+ // OMX_COLOR_FormatYUV411Planar;
+
+ int32_t width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+
+ int32_t compressedSize;
+ success = success && meta->findInt32(
+ kKeyCompressedSize, &compressedSize);
+
+ CHECK(success);
+ CHECK(compressedSize > 0);
+
+ codec->setImageOutputFormat(format, width, height);
+ codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
+ }
+
+ codec->initOutputFormat(meta);
+
+ return codec;
+}
+
+status_t OMXCodec::setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat) {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = portIndex;
+ format.nIndex = 0;
+ bool found = false;
+
+ OMX_U32 index = 0;
+ for (;;) {
+ format.nIndex = index;
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ if (err != OK) {
+ return err;
+ }
+
+ // The following assertion is violated by TI's video decoder.
+ // CHECK_EQ(format.nIndex, index);
+
+#if 1
+ LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+ portIndex,
+ index, format.eCompressionFormat, format.eColorFormat);
+#endif
+
+ if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
+ if (portIndex == kPortIndexInput
+ && colorFormat == format.eColorFormat) {
+ // eCompressionFormat does not seem right.
+ found = true;
+ break;
+ }
+ if (portIndex == kPortIndexOutput
+ && compressionFormat == format.eCompressionFormat) {
+ // eColorFormat does not seem right.
+ found = true;
+ break;
+ }
+ }
+
+ if (format.eCompressionFormat == compressionFormat
+ && format.eColorFormat == colorFormat) {
+ found = true;
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!found) {
+ return UNKNOWN_ERROR;
+ }
+
+ LOGI("found a match.");
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ return err;
+}
+
+void OMXCodec::setVideoInputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ LOGE("Not a supported video mime type: %s", mime);
+ CHECK(!"Should not be here. Not a supported video mime type.");
+ }
+
+ OMX_COLOR_FORMATTYPE colorFormat =
+ 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
+
+ if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
+ colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, OMX_VIDEO_CodingUnused,
+ colorFormat);
+
+ setVideoPortFormatType(
+ kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ video_def->eCompressionFormat = compressionFormat;
+ video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
+ LOGI("setting nBufferSize = %ld", def.nBufferSize);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+ video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
+ video_def->eColorFormat = colorFormat;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the TI decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+#if 1
+ if (!strcmp("OMX.TI.Video.Decoder", mComponentName)
+ && !strcasecmp("video/avc", mime)) {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ CHECK_EQ(err, OK);
+ }
+#endif
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ LOGE("Not a supported video mime type: %s", mime);
+ CHECK(!"Should not be here. Not a supported video mime type.");
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ CHECK_EQ(err, OK);
+ CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ CHECK_EQ(err, OK);
+ }
+#endif
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+
+#if 1
+ // XXX Need a (much) better heuristic to compute input buffer sizes.
+ const size_t X = 64 * 1024;
+ if (def.nBufferSize < X) {
+ def.nBufferSize = X;
+ }
+#endif
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+#if 0
+ def.nBufferSize =
+ (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
+#endif
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+
+OMXCodec::OMXCodec(
+ const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ bool isEncoder,
+ const char *mime,
+ const char *componentName,
+ const sp<MediaSource> &source)
+ : mOMX(omx),
+ mNode(node),
+ mQuirks(quirks),
+ mIsEncoder(isEncoder),
+ mMIME(strdup(mime)),
+ mComponentName(strdup(componentName)),
+ mSource(source),
+ mCodecSpecificDataIndex(0),
+ mState(LOADED),
+ mSignalledEOS(false),
+ mNoMoreOutputData(false),
+ mSeekTimeUs(-1) {
+ mPortStatus[kPortIndexInput] = ENABLED;
+ mPortStatus[kPortIndexOutput] = ENABLED;
+
+ mObserver = new OMXCodecObserver(this);
+ mOMX->observe_node(mNode, mObserver);
+}
+
+OMXCodec::~OMXCodec() {
+ CHECK(mState == LOADED || mState == ERROR);
+
+ status_t err = mOMX->observe_node(mNode, NULL);
+ CHECK_EQ(err, OK);
+
+ err = mOMX->free_node(mNode);
+ CHECK_EQ(err, OK);
+
+ mNode = NULL;
+ setState(DEAD);
+
+ clearCodecSpecificData();
+
+ free(mComponentName);
+ mComponentName = NULL;
+
+ free(mMIME);
+ mMIME = NULL;
+}
+
+status_t OMXCodec::init() {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK_EQ(mState, LOADED);
+
+ status_t err;
+ if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
+ err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+
+ setState(LOADED_TO_IDLE);
+ }
+
+ err = allocateBuffers();
+ CHECK_EQ(err, OK);
+
+ if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
+ err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+
+ setState(LOADED_TO_IDLE);
+ }
+
+ while (mState != EXECUTING && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ return mState == ERROR ? UNKNOWN_ERROR : OK;
+}
+
+// static
+bool OMXCodec::isIntermediateState(State state) {
+ return state == LOADED_TO_IDLE
+ || state == IDLE_TO_EXECUTING
+ || state == EXECUTING_TO_IDLE
+ || state == IDLE_TO_LOADED
+ || state == RECONFIGURING;
+}
+
+status_t OMXCodec::allocateBuffers() {
+ status_t err = allocateBuffersOnPort(kPortIndexInput);
+
+ if (err != OK) {
+ return err;
+ }
+
+ return allocateBuffersOnPort(kPortIndexOutput);
+}
+
+status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nVersion.s.nRevision = 0;
+ def.nVersion.s.nStep = 0;
+ def.nPortIndex = portIndex;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ if (err != OK) {
+ return err;
+ }
+
+ size_t totalSize = def.nBufferCountActual * def.nBufferSize;
+ mDealer[portIndex] = new MemoryDealer(totalSize);
+
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
+ CHECK(mem.get() != NULL);
+
+ IOMX::buffer_id buffer;
+ if (portIndex == kPortIndexInput
+ && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+ err = mOMX->allocate_buffer_with_backup(
+ mNode, portIndex, mem, &buffer);
+ } else if (portIndex == kPortIndexOutput
+ && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
+ err = mOMX->allocate_buffer(
+ mNode, portIndex, def.nBufferSize, &buffer);
+ } else {
+ err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
+ }
+
+ if (err != OK) {
+ LOGE("allocate_buffer_with_backup failed");
+ return err;
+ }
+
+ BufferInfo info;
+ info.mBuffer = buffer;
+ info.mOwnedByComponent = false;
+ info.mMem = mem;
+ info.mMediaBuffer = NULL;
+
+ if (portIndex == kPortIndexOutput) {
+ info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
+ info.mMediaBuffer->setObserver(this);
+ }
+
+ mPortBuffers[portIndex].push(info);
+
+ LOGV("allocated buffer %p on %s port", buffer,
+ portIndex == kPortIndexInput ? "input" : "output");
+ }
+
+ dumpPortStatus(portIndex);
+
+ return OK;
+}
+
+void OMXCodec::on_message(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+
+ switch (msg.type) {
+ case omx_message::EVENT:
+ {
+ onEvent(
+ msg.u.event_data.event, msg.u.event_data.data1,
+ msg.u.event_data.data2);
+
+ break;
+ }
+
+ case omx_message::EMPTY_BUFFER_DONE:
+ {
+ IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+
+ LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ size_t i = 0;
+ while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+ ++i;
+ }
+
+ CHECK(i < buffers->size());
+ if (!(*buffers)[i].mOwnedByComponent) {
+ LOGW("We already own input buffer %p, yet received "
+ "an EMPTY_BUFFER_DONE.", buffer);
+ }
+
+ buffers->editItemAt(i).mOwnedByComponent = false;
+
+ if (mPortStatus[kPortIndexInput] == DISABLING) {
+ LOGV("Port is disabled, freeing buffer %p", buffer);
+
+ status_t err =
+ mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+ CHECK_EQ(err, OK);
+
+ buffers->removeAt(i);
+ } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
+ CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
+
+ break;
+ }
+
+ case omx_message::FILL_BUFFER_DONE:
+ {
+ IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+ OMX_U32 flags = msg.u.extended_buffer_data.flags;
+
+ LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
+ buffer,
+ msg.u.extended_buffer_data.range_length,
+ flags);
+
+ LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
+ msg.u.extended_buffer_data.timestamp,
+ msg.u.extended_buffer_data.timestamp / 1E6);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ size_t i = 0;
+ while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+ ++i;
+ }
+
+ CHECK(i < buffers->size());
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (!info->mOwnedByComponent) {
+ LOGW("We already own output buffer %p, yet received "
+ "a FILL_BUFFER_DONE.", buffer);
+ }
+
+ info->mOwnedByComponent = false;
+
+ if (mPortStatus[kPortIndexOutput] == DISABLING) {
+ LOGV("Port is disabled, freeing buffer %p", buffer);
+
+ status_t err =
+ mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+ CHECK_EQ(err, OK);
+
+ buffers->removeAt(i);
+ } else if (mPortStatus[kPortIndexOutput] == ENABLED
+ && (flags & OMX_BUFFERFLAG_EOS)) {
+ LOGV("No more output data.");
+ mNoMoreOutputData = true;
+ mBufferFilled.signal();
+ } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
+ CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+
+ MediaBuffer *buffer = info->mMediaBuffer;
+
+ buffer->set_range(
+ msg.u.extended_buffer_data.range_offset,
+ msg.u.extended_buffer_data.range_length);
+
+ buffer->meta_data()->clear();
+
+ buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+
+ buffer->meta_data()->setInt32(
+ kKeyTimeScale, 1000);
+
+ if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
+ buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
+ }
+
+ buffer->meta_data()->setPointer(
+ kKeyPlatformPrivate,
+ msg.u.extended_buffer_data.platform_private);
+
+ buffer->meta_data()->setPointer(
+ kKeyBufferID,
+ msg.u.extended_buffer_data.buffer);
+
+ mFilledBuffers.push_back(i);
+ mBufferFilled.signal();
+ }
+
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+}
+
+void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+ switch (event) {
+ case OMX_EventCmdComplete:
+ {
+ onCmdComplete((OMX_COMMANDTYPE)data1, data2);
+ break;
+ }
+
+ case OMX_EventError:
+ {
+ LOGE("ERROR(%ld, %ld)", data1, data2);
+
+ setState(ERROR);
+ break;
+ }
+
+ case OMX_EventPortSettingsChanged:
+ {
+ onPortSettingsChanged(data1);
+ break;
+ }
+
+ case OMX_EventBufferFlag:
+ {
+ LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
+
+ if (data1 == kPortIndexOutput) {
+ mNoMoreOutputData = true;
+ }
+ break;
+ }
+
+ default:
+ {
+ LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
+ break;
+ }
+ }
+}
+
+void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
+ switch (cmd) {
+ case OMX_CommandStateSet:
+ {
+ onStateChange((OMX_STATETYPE)data);
+ break;
+ }
+
+ case OMX_CommandPortDisable:
+ {
+ OMX_U32 portIndex = data;
+ LOGV("PORT_DISABLED(%ld)", portIndex);
+
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+ CHECK_EQ(mPortStatus[portIndex], DISABLING);
+ CHECK_EQ(mPortBuffers[portIndex].size(), 0);
+
+ mPortStatus[portIndex] = DISABLED;
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ enablePortAsync(portIndex);
+
+ status_t err = allocateBuffersOnPort(portIndex);
+ CHECK_EQ(err, OK);
+ }
+ break;
+ }
+
+ case OMX_CommandPortEnable:
+ {
+ OMX_U32 portIndex = data;
+ LOGV("PORT_ENABLED(%ld)", portIndex);
+
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+ CHECK_EQ(mPortStatus[portIndex], ENABLING);
+
+ mPortStatus[portIndex] = ENABLED;
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ setState(EXECUTING);
+
+ fillOutputBuffers();
+ }
+ break;
+ }
+
+ case OMX_CommandFlush:
+ {
+ OMX_U32 portIndex = data;
+
+ LOGV("FLUSH_DONE(%ld)", portIndex);
+
+ CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
+ mPortStatus[portIndex] = ENABLED;
+
+ CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
+ mPortBuffers[portIndex].size());
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ disablePortAsync(portIndex);
+ } else {
+ // We're flushing both ports in preparation for seeking.
+
+ if (mPortStatus[kPortIndexInput] == ENABLED
+ && mPortStatus[kPortIndexOutput] == ENABLED) {
+ LOGV("Finished flushing both ports, now continuing from"
+ " seek-time.");
+
+ drainInputBuffers();
+ fillOutputBuffers();
+ }
+ }
+
+ break;
+ }
+
+ default:
+ {
+ LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
+ break;
+ }
+ }
+}
+
+void OMXCodec::onStateChange(OMX_STATETYPE newState) {
+ switch (newState) {
+ case OMX_StateIdle:
+ {
+ LOGV("Now Idle.");
+ if (mState == LOADED_TO_IDLE) {
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateExecuting);
+
+ CHECK_EQ(err, OK);
+
+ setState(IDLE_TO_EXECUTING);
+ } else {
+ CHECK_EQ(mState, EXECUTING_TO_IDLE);
+
+ CHECK_EQ(
+ countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
+ mPortBuffers[kPortIndexInput].size());
+
+ CHECK_EQ(
+ countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
+ mPortBuffers[kPortIndexOutput].size());
+
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateLoaded);
+
+ CHECK_EQ(err, OK);
+
+ err = freeBuffersOnPort(kPortIndexInput);
+ CHECK_EQ(err, OK);
+
+ err = freeBuffersOnPort(kPortIndexOutput);
+ CHECK_EQ(err, OK);
+
+ mPortStatus[kPortIndexInput] = ENABLED;
+ mPortStatus[kPortIndexOutput] = ENABLED;
+
+ setState(IDLE_TO_LOADED);
+ }
+ break;
+ }
+
+ case OMX_StateExecuting:
+ {
+ CHECK_EQ(mState, IDLE_TO_EXECUTING);
+
+ LOGV("Now Executing.");
+
+ setState(EXECUTING);
+
+ drainInputBuffers();
+ fillOutputBuffers();
+ break;
+ }
+
+ case OMX_StateLoaded:
+ {
+ CHECK_EQ(mState, IDLE_TO_LOADED);
+
+ LOGV("Now Loaded.");
+
+ setState(LOADED);
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+}
+
+// static
+size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
+ size_t n = 0;
+ for (size_t i = 0; i < buffers.size(); ++i) {
+ if (!buffers[i].mOwnedByComponent) {
+ ++n;
+ }
+ }
+
+ return n;
+}
+
+status_t OMXCodec::freeBuffersOnPort(
+ OMX_U32 portIndex, bool onlyThoseWeOwn) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+
+ status_t stickyErr = OK;
+
+ for (size_t i = buffers->size(); i-- > 0;) {
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (onlyThoseWeOwn && info->mOwnedByComponent) {
+ continue;
+ }
+
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ status_t err =
+ mOMX->free_buffer(mNode, portIndex, info->mBuffer);
+
+ if (err != OK) {
+ stickyErr = err;
+ }
+
+ if (info->mMediaBuffer != NULL) {
+ info->mMediaBuffer->setObserver(NULL);
+
+ // Make sure nobody but us owns this buffer at this point.
+ CHECK_EQ(info->mMediaBuffer->refcount(), 0);
+
+ info->mMediaBuffer->release();
+ }
+
+ buffers->removeAt(i);
+ }
+
+ CHECK(onlyThoseWeOwn || buffers->isEmpty());
+
+ return stickyErr;
+}
+
+void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
+ LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
+
+ CHECK_EQ(mState, EXECUTING);
+ CHECK_EQ(portIndex, kPortIndexOutput);
+ setState(RECONFIGURING);
+
+ if (mQuirks & kNeedsFlushBeforeDisable) {
+ if (!flushPortAsync(portIndex)) {
+ onCmdComplete(OMX_CommandFlush, portIndex);
+ }
+ } else {
+ disablePortAsync(portIndex);
+ }
+}
+
+bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
+ portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
+ mPortBuffers[portIndex].size());
+
+ CHECK_EQ(mPortStatus[portIndex], ENABLED);
+ mPortStatus[portIndex] = SHUTTING_DOWN;
+
+ if ((mQuirks & kRequiresFlushCompleteEmulation)
+ && countBuffersWeOwn(mPortBuffers[portIndex])
+ == mPortBuffers[portIndex].size()) {
+ // No flush is necessary and this component fails to send a
+ // flush-complete event in this case.
+
+ return false;
+ }
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+ CHECK_EQ(err, OK);
+
+ return true;
+}
+
+void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ CHECK_EQ(mPortStatus[portIndex], ENABLED);
+ mPortStatus[portIndex] = DISABLING;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
+ CHECK_EQ(err, OK);
+
+ freeBuffersOnPort(portIndex, true);
+}
+
+void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ CHECK_EQ(mPortStatus[portIndex], DISABLED);
+ mPortStatus[portIndex] = ENABLING;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::fillOutputBuffers() {
+ CHECK_EQ(mState, EXECUTING);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ fillOutputBuffer(&buffers->editItemAt(i));
+ }
+}
+
+void OMXCodec::drainInputBuffers() {
+ CHECK_EQ(mState, EXECUTING);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
+}
+
+void OMXCodec::drainInputBuffer(BufferInfo *info) {
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ if (mSignalledEOS) {
+ return;
+ }
+
+ if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+ const CodecSpecificData *specific =
+ mCodecSpecificData[mCodecSpecificDataIndex];
+
+ size_t size = specific->mSize;
+
+ if (!strcasecmp("video/avc", mMIME)
+ && !(mQuirks & kWantsNALFragments)) {
+ static const uint8_t kNALStartCode[4] =
+ { 0x00, 0x00, 0x00, 0x01 };
+
+ CHECK(info->mMem->size() >= specific->mSize + 4);
+
+ size += 4;
+
+ memcpy(info->mMem->pointer(), kNALStartCode, 4);
+ memcpy((uint8_t *)info->mMem->pointer() + 4,
+ specific->mData, specific->mSize);
+ } else {
+ CHECK(info->mMem->size() >= specific->mSize);
+ memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
+ }
+
+ mOMX->empty_buffer(
+ mNode, info->mBuffer, 0, size,
+ OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
+ 0);
+
+ info->mOwnedByComponent = true;
+
+ ++mCodecSpecificDataIndex;
+ return;
+ }
+
+ MediaBuffer *srcBuffer;
+ status_t err;
+ if (mSeekTimeUs >= 0) {
+ MediaSource::ReadOptions options;
+ options.setSeekTo(mSeekTimeUs);
+ mSeekTimeUs = -1;
+
+ err = mSource->read(&srcBuffer, &options);
+ } else {
+ err = mSource->read(&srcBuffer);
+ }
+
+ OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
+ OMX_TICKS timestamp = 0;
+ size_t srcLength = 0;
+
+ if (err != OK) {
+ LOGV("signalling end of input stream.");
+ flags |= OMX_BUFFERFLAG_EOS;
+
+ mSignalledEOS = true;
+ } else {
+ srcLength = srcBuffer->range_length();
+
+ if (info->mMem->size() < srcLength) {
+ LOGE("info->mMem->size() = %d, srcLength = %d",
+ info->mMem->size(), srcLength);
+ }
+ CHECK(info->mMem->size() >= srcLength);
+ memcpy(info->mMem->pointer(),
+ (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
+ srcLength);
+
+ int32_t units, scale;
+ if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
+ && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
+ timestamp = ((OMX_TICKS)units * 1000000) / scale;
+
+ LOGV("Calling empty_buffer on buffer %p (length %d)",
+ info->mBuffer, srcLength);
+ LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
+ timestamp, timestamp / 1E6);
+ }
+ }
+
+ mOMX->empty_buffer(
+ mNode, info->mBuffer, 0, srcLength,
+ flags, timestamp);
+
+ info->mOwnedByComponent = true;
+
+ if (srcBuffer != NULL) {
+ srcBuffer->release();
+ srcBuffer = NULL;
+ }
+}
+
+void OMXCodec::fillOutputBuffer(BufferInfo *info) {
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ if (mNoMoreOutputData) {
+ LOGV("There is no more output data available, not "
+ "calling fillOutputBuffer");
+ return;
+ }
+
+ LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
+ mOMX->fill_buffer(mNode, info->mBuffer);
+
+ info->mOwnedByComponent = true;
+}
+
+void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if ((*buffers)[i].mBuffer == buffer) {
+ drainInputBuffer(&buffers->editItemAt(i));
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if ((*buffers)[i].mBuffer == buffer) {
+ fillOutputBuffer(&buffers->editItemAt(i));
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+void OMXCodec::setState(State newState) {
+ mState = newState;
+ mAsyncCompletion.signal();
+
+ // This may cause some spurious wakeups but is necessary to
+ // unblock the reader if we enter ERROR state.
+ mBufferFilled.signal();
+}
+
+void OMXCodec::setAMRFormat() {
+ if (!mIsEncoder) {
+ OMX_AUDIO_PARAM_AMRTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err =
+ mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+
+ def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+ def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
+
+ err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+ }
+
+ ////////////////////////
+
+ if (mIsEncoder) {
+ sp<MetaData> format = mSource->getFormat();
+ int32_t sampleRate;
+ int32_t numChannels;
+ CHECK(format->findInt32(kKeySampleRate, &sampleRate));
+ CHECK(format->findInt32(kKeyChannelCount, &numChannels));
+
+ OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+ pcmParams.nSize = sizeof(pcmParams);
+ pcmParams.nVersion.s.nVersionMajor = 1;
+ pcmParams.nVersion.s.nVersionMinor = 1;
+ pcmParams.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+ CHECK_EQ(err, OK);
+
+ pcmParams.nChannels = numChannels;
+ pcmParams.eNumData = OMX_NumericalDataSigned;
+ pcmParams.bInterleaved = OMX_TRUE;
+ pcmParams.nBitPerSample = 16;
+ pcmParams.nSamplingRate = sampleRate;
+ pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+ if (numChannels == 1) {
+ pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+ } else {
+ CHECK_EQ(numChannels, 2);
+
+ pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+ }
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+ CHECK_EQ(err, OK);
+ }
+}
+
+void OMXCodec::setAACFormat() {
+ OMX_AUDIO_PARAM_AACPROFILETYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err =
+ mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setImageOutputFormat(
+ OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
+ LOGV("setImageOutputFormat(%ld, %ld)", width, height);
+
+#if 0
+ OMX_INDEXTYPE index;
+ status_t err = mOMX->get_extension_index(
+ mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
+ CHECK_EQ(err, OK);
+
+ err = mOMX->set_config(mNode, index, &format, sizeof(format));
+ CHECK_EQ(err, OK);
+#endif
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainImage);
+
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+ imageDef->eColorFormat = format;
+ imageDef->nFrameWidth = width;
+ imageDef->nFrameHeight = height;
+
+ switch (format) {
+ case OMX_COLOR_FormatYUV420PackedPlanar:
+ case OMX_COLOR_FormatYUV411Planar:
+ {
+ def.nBufferSize = (width * height * 3) / 2;
+ break;
+ }
+
+ case OMX_COLOR_FormatCbYCrY:
+ {
+ def.nBufferSize = width * height * 2;
+ break;
+ }
+
+ case OMX_COLOR_Format32bitARGB8888:
+ {
+ def.nBufferSize = width * height * 4;
+ break;
+ }
+
+ default:
+ CHECK(!"Should not be here. Unknown color format.");
+ break;
+ }
+
+ def.nBufferCountActual = def.nBufferCountMin;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setJPEGInputFormat(
+ OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainImage);
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
+ imageDef->nFrameWidth = width;
+ imageDef->nFrameHeight = height;
+
+ def.nBufferSize = compressedSize;
+ def.nBufferCountActual = def.nBufferCountMin;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+ CodecSpecificData *specific =
+ (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+
+ specific->mSize = size;
+ memcpy(specific->mData, data, size);
+
+ mCodecSpecificData.push(specific);
+}
+
+void OMXCodec::clearCodecSpecificData() {
+ for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
+ free(mCodecSpecificData.editItemAt(i));
+ }
+ mCodecSpecificData.clear();
+ mCodecSpecificDataIndex = 0;
+}
+
+status_t OMXCodec::start(MetaData *) {
+ if (mState != LOADED) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> params = new MetaData;
+ if (mQuirks & kWantsNALFragments) {
+ params->setInt32(kKeyWantsNALFragments, true);
+ }
+ status_t err = mSource->start(params.get());
+
+ if (err != OK) {
+ return err;
+ }
+
+ mCodecSpecificDataIndex = 0;
+ mSignalledEOS = false;
+ mNoMoreOutputData = false;
+ mSeekTimeUs = -1;
+ mFilledBuffers.clear();
+
+ return init();
+}
+
+status_t OMXCodec::stop() {
+ LOGV("stop");
+
+ Mutex::Autolock autoLock(mLock);
+
+ while (isIntermediateState(mState)) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ switch (mState) {
+ case LOADED:
+ case ERROR:
+ break;
+
+ case EXECUTING:
+ {
+ setState(EXECUTING_TO_IDLE);
+
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+
+ while (mState != LOADED && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+
+ mSource->stop();
+
+ return OK;
+}
+
+sp<MetaData> OMXCodec::getFormat() {
+ return mOutputFormat;
+}
+
+status_t OMXCodec::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ *buffer = NULL;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != EXECUTING && mState != RECONFIGURING) {
+ return UNKNOWN_ERROR;
+ }
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+
+ mSignalledEOS = false;
+ mNoMoreOutputData = false;
+
+ CHECK(seekTimeUs >= 0);
+ mSeekTimeUs = seekTimeUs;
+
+ mFilledBuffers.clear();
+
+ CHECK_EQ(mState, EXECUTING);
+
+ bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
+ bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
+
+ if (emulateInputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+ }
+
+ if (emulateOutputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+ }
+ }
+
+ while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
+ mBufferFilled.wait(mLock);
+ }
+
+ if (mState == ERROR) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mFilledBuffers.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ size_t index = *mFilledBuffers.begin();
+ mFilledBuffers.erase(mFilledBuffers.begin());
+
+ BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+ info->mMediaBuffer->add_ref();
+ *buffer = info->mMediaBuffer;
+
+ return OK;
+}
+
+void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (info->mMediaBuffer == buffer) {
+ CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+ fillOutputBuffer(info);
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_IMAGE_CodingUnused",
+ "OMX_IMAGE_CodingAutoDetect",
+ "OMX_IMAGE_CodingJPEG",
+ "OMX_IMAGE_CodingJPEG2K",
+ "OMX_IMAGE_CodingEXIF",
+ "OMX_IMAGE_CodingTIFF",
+ "OMX_IMAGE_CodingGIF",
+ "OMX_IMAGE_CodingPNG",
+ "OMX_IMAGE_CodingLZW",
+ "OMX_IMAGE_CodingBMP",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
+ static const char *kNames[] = {
+ "OMX_COLOR_FormatUnused",
+ "OMX_COLOR_FormatMonochrome",
+ "OMX_COLOR_Format8bitRGB332",
+ "OMX_COLOR_Format12bitRGB444",
+ "OMX_COLOR_Format16bitARGB4444",
+ "OMX_COLOR_Format16bitARGB1555",
+ "OMX_COLOR_Format16bitRGB565",
+ "OMX_COLOR_Format16bitBGR565",
+ "OMX_COLOR_Format18bitRGB666",
+ "OMX_COLOR_Format18bitARGB1665",
+ "OMX_COLOR_Format19bitARGB1666",
+ "OMX_COLOR_Format24bitRGB888",
+ "OMX_COLOR_Format24bitBGR888",
+ "OMX_COLOR_Format24bitARGB1887",
+ "OMX_COLOR_Format25bitARGB1888",
+ "OMX_COLOR_Format32bitBGRA8888",
+ "OMX_COLOR_Format32bitARGB8888",
+ "OMX_COLOR_FormatYUV411Planar",
+ "OMX_COLOR_FormatYUV411PackedPlanar",
+ "OMX_COLOR_FormatYUV420Planar",
+ "OMX_COLOR_FormatYUV420PackedPlanar",
+ "OMX_COLOR_FormatYUV420SemiPlanar",
+ "OMX_COLOR_FormatYUV422Planar",
+ "OMX_COLOR_FormatYUV422PackedPlanar",
+ "OMX_COLOR_FormatYUV422SemiPlanar",
+ "OMX_COLOR_FormatYCbYCr",
+ "OMX_COLOR_FormatYCrYCb",
+ "OMX_COLOR_FormatCbYCrY",
+ "OMX_COLOR_FormatCrYCbY",
+ "OMX_COLOR_FormatYUV444Interleaved",
+ "OMX_COLOR_FormatRawBayer8bit",
+ "OMX_COLOR_FormatRawBayer10bit",
+ "OMX_COLOR_FormatRawBayer8bitcompressed",
+ "OMX_COLOR_FormatL2",
+ "OMX_COLOR_FormatL4",
+ "OMX_COLOR_FormatL8",
+ "OMX_COLOR_FormatL16",
+ "OMX_COLOR_FormatL24",
+ "OMX_COLOR_FormatL32",
+ "OMX_COLOR_FormatYUV420PackedSemiPlanar",
+ "OMX_COLOR_FormatYUV422PackedSemiPlanar",
+ "OMX_COLOR_Format18BitBGR666",
+ "OMX_COLOR_Format24BitARGB6666",
+ "OMX_COLOR_Format24BitABGR6666",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
+ return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
+ } else if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_VIDEO_CodingUnused",
+ "OMX_VIDEO_CodingAutoDetect",
+ "OMX_VIDEO_CodingMPEG2",
+ "OMX_VIDEO_CodingH263",
+ "OMX_VIDEO_CodingMPEG4",
+ "OMX_VIDEO_CodingWMV",
+ "OMX_VIDEO_CodingRV",
+ "OMX_VIDEO_CodingAVC",
+ "OMX_VIDEO_CodingMJPEG",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_AUDIO_CodingUnused",
+ "OMX_AUDIO_CodingAutoDetect",
+ "OMX_AUDIO_CodingPCM",
+ "OMX_AUDIO_CodingADPCM",
+ "OMX_AUDIO_CodingAMR",
+ "OMX_AUDIO_CodingGSMFR",
+ "OMX_AUDIO_CodingGSMEFR",
+ "OMX_AUDIO_CodingGSMHR",
+ "OMX_AUDIO_CodingPDCFR",
+ "OMX_AUDIO_CodingPDCEFR",
+ "OMX_AUDIO_CodingPDCHR",
+ "OMX_AUDIO_CodingTDMAFR",
+ "OMX_AUDIO_CodingTDMAEFR",
+ "OMX_AUDIO_CodingQCELP8",
+ "OMX_AUDIO_CodingQCELP13",
+ "OMX_AUDIO_CodingEVRC",
+ "OMX_AUDIO_CodingSMV",
+ "OMX_AUDIO_CodingG711",
+ "OMX_AUDIO_CodingG723",
+ "OMX_AUDIO_CodingG726",
+ "OMX_AUDIO_CodingG729",
+ "OMX_AUDIO_CodingAAC",
+ "OMX_AUDIO_CodingMP3",
+ "OMX_AUDIO_CodingSBC",
+ "OMX_AUDIO_CodingVORBIS",
+ "OMX_AUDIO_CodingWMA",
+ "OMX_AUDIO_CodingRA",
+ "OMX_AUDIO_CodingMIDI",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
+ static const char *kNames[] = {
+ "OMX_AUDIO_PCMModeLinear",
+ "OMX_AUDIO_PCMModeALaw",
+ "OMX_AUDIO_PCMModeMULaw",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+
+void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = portIndex;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
+
+ CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
+ || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
+
+ printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
+ printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
+ printf(" nBufferSize = %ld\n", def.nBufferSize);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainImage:
+ {
+ const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ printf("\n");
+ printf(" // Image\n");
+ printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
+ printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
+ printf(" nStride = %ld\n", imageDef->nStride);
+
+ printf(" eCompressionFormat = %s\n",
+ imageCompressionFormatString(imageDef->eCompressionFormat));
+
+ printf(" eColorFormat = %s\n",
+ colorFormatString(imageDef->eColorFormat));
+
+ break;
+ }
+
+ case OMX_PortDomainVideo:
+ {
+ OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+
+ printf("\n");
+ printf(" // Video\n");
+ printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
+ printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
+ printf(" nStride = %ld\n", videoDef->nStride);
+
+ printf(" eCompressionFormat = %s\n",
+ videoCompressionFormatString(videoDef->eCompressionFormat));
+
+ printf(" eColorFormat = %s\n",
+ colorFormatString(videoDef->eColorFormat));
+
+ break;
+ }
+
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
+
+ printf("\n");
+ printf(" // Audio\n");
+ printf(" eEncoding = %s\n",
+ audioCodingTypeString(audioDef->eEncoding));
+
+ if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ params.nSize = sizeof(params);
+ params.nVersion.s.nVersionMajor = 1;
+ params.nVersion.s.nVersionMinor = 1;
+ params.nPortIndex = portIndex;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
+ CHECK_EQ(err, OK);
+
+ printf(" nSamplingRate = %ld\n", params.nSamplingRate);
+ printf(" nChannels = %ld\n", params.nChannels);
+ printf(" bInterleaved = %d\n", params.bInterleaved);
+ printf(" nBitPerSample = %ld\n", params.nBitPerSample);
+
+ printf(" eNumData = %s\n",
+ params.eNumData == OMX_NumericalDataSigned
+ ? "signed" : "unsigned");
+
+ printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+ }
+
+ break;
+ }
+
+ default:
+ {
+ printf(" // Unknown\n");
+ break;
+ }
+ }
+
+ printf("}\n");
+}
+
+void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
+ mOutputFormat = new MetaData;
+ mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainImage:
+ {
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+
+ mOutputFormat->setCString(kKeyMIMEType, "image/raw");
+ mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
+ mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
+ mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
+ break;
+ }
+
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+
+ CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
+
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ params.nSize = sizeof(params);
+ params.nVersion.s.nVersionMajor = 1;
+ params.nVersion.s.nVersionMinor = 1;
+ params.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+ CHECK_EQ(params.nBitPerSample, 16);
+ CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
+
+ int32_t numChannels, sampleRate;
+ inputFormat->findInt32(kKeyChannelCount, &numChannels);
+ inputFormat->findInt32(kKeySampleRate, &sampleRate);
+
+ mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+ mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+ mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+ break;
+ }
+
+ case OMX_PortDomainVideo:
+ {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+ } else {
+ CHECK(!"Unknown compression format.");
+ }
+
+ if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
+ // This component appears to be lying to me.
+ mOutputFormat->setInt32(
+ kKeyWidth, (video_def->nFrameWidth + 15) & -16);
+ mOutputFormat->setInt32(
+ kKeyHeight, (video_def->nFrameHeight + 15) & -16);
+ } else {
+ mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
+ mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
+ }
+
+ mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here, neither audio nor video.");
+ break;
+ }
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index a00872f..a3172ed 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -18,13 +18,12 @@
#define LOG_TAG "OMXDecoder"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
#include <ctype.h>
#include <OMX_Component.h>
#include <media/stagefright/ESDS.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXDecoder.h>
@@ -87,7 +86,7 @@
static const char *GetCodec(const CodecInfo *info, size_t numInfos,
const char *mime, int index) {
- assert(index >= 0);
+ CHECK(index >= 0);
for(size_t i = 0; i < numInfos; ++i) {
if (!strcasecmp(mime, info[i].mime)) {
if (index == 0) {
@@ -102,12 +101,13 @@
}
// static
-OMXDecoder *OMXDecoder::Create(
+sp<OMXDecoder> OMXDecoder::Create(
OMXClient *client, const sp<MetaData> &meta,
- bool createEncoder) {
+ bool createEncoder,
+ const sp<MediaSource> &source) {
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
+ CHECK(success);
sp<IOMX> omx = client->interface();
@@ -138,7 +138,7 @@
uint32_t quirks = 0;
if (!strcmp(codec, "OMX.PV.avcdec")) {
- quirks |= kWantsRawNALFrames;
+ quirks |= kWantsNALFragments;
}
if (!strcmp(codec, "OMX.TI.AAC.decode")
|| !strcmp(codec, "OMX.TI.MP3.decode")) {
@@ -158,15 +158,16 @@
quirks |= kRequiresLoadedToIdleAfterAllocation;
}
- OMXDecoder *decoder = new OMXDecoder(
- client, node, mime, codec, createEncoder, quirks);
+ sp<OMXDecoder> decoder = new OMXDecoder(
+ client, node, mime, codec, createEncoder, quirks,
+ source);
uint32_t type;
const void *data;
size_t size;
if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
- assert(esds.InitCheck() == OK);
+ CHECK_EQ(esds.InitCheck(), OK);
const void *codec_specific_data;
size_t codec_specific_data_size;
@@ -191,7 +192,7 @@
// printf("length = %d, size = %d\n", length, size);
- assert(size >= length);
+ CHECK(size >= length);
decoder->addCodecSpecificData(ptr, length);
@@ -213,7 +214,8 @@
OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
const char *mime, const char *codec,
bool is_encoder,
- uint32_t quirks)
+ uint32_t quirks,
+ const sp<MediaSource> &source)
: mClient(client),
mOMX(mClient->interface()),
mNode(node),
@@ -223,7 +225,7 @@
mIsAVC(!strcasecmp(mime, "video/avc")),
mIsEncoder(is_encoder),
mQuirks(quirks),
- mSource(NULL),
+ mSource(source),
mCodecSpecificDataIterator(mCodecSpecificData.begin()),
mState(OMX_StateLoaded),
mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
@@ -237,6 +239,8 @@
mBuffers.push(); // input buffers
mBuffers.push(); // output buffers
+
+ setup();
}
OMXDecoder::~OMXDecoder() {
@@ -253,7 +257,7 @@
mClient->unregisterObserver(mNode);
status_t err = mOMX->free_node(mNode);
- assert(err == OK);
+ CHECK_EQ(err, OK);
mNode = 0;
free(mMIME);
@@ -263,23 +267,14 @@
mComponentName = NULL;
}
-void OMXDecoder::setSource(MediaSource *source) {
- Mutex::Autolock autoLock(mLock);
-
- assert(mSource == NULL);
-
- mSource = source;
- setup();
-}
-
status_t OMXDecoder::start(MetaData *) {
- assert(!mStarted);
+ CHECK(!mStarted);
// mDealer->dump("Decoder Dealer");
sp<MetaData> params = new MetaData;
- if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
- params->setInt32(kKeyNeedsNALFraming, true);
+ if (mQuirks & kWantsNALFragments) {
+ params->setInt32(kKeyWantsNALFragments, true);
}
status_t err = mSource->start(params.get());
@@ -296,7 +291,7 @@
}
status_t OMXDecoder::stop() {
- assert(mStarted);
+ CHECK(mStarted);
LOGI("Initiating OMX Node shutdown, busy polling.");
initiateShutdown();
@@ -344,7 +339,7 @@
status_t OMXDecoder::read(
MediaBuffer **out, const ReadOptions *options) {
- assert(mStarted);
+ CHECK(mStarted);
*out = NULL;
@@ -388,7 +383,7 @@
// never sends the completion event... FIXME
status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
- assert(err == OK);
+ CHECK_EQ(err, OK);
// Once flushing is completed buffers will again be scheduled to be
// filled/emptied.
@@ -406,7 +401,7 @@
return OK;
} else {
- assert(mErrorCondition != OK);
+ CHECK(mErrorCondition != OK);
return mErrorCondition;
}
}
@@ -467,13 +462,13 @@
status_t err =
mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::setAACFormat() {
@@ -485,12 +480,12 @@
status_t err =
mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
status_t OMXDecoder::setVideoPortFormatType(
@@ -516,8 +511,8 @@
return err;
}
- // The following assertion is violated by TI's video decoder.
- // assert(format.nIndex == index);
+ // The following CHECKion is violated by TI's video decoder.
+ // CHECK_EQ(format.nIndex, index);
#if 1
LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
@@ -574,12 +569,16 @@
compressionFormat = OMX_VIDEO_CodingH263;
} else {
LOGE("Not a supported video mime type: %s", mime);
- assert(!"Should not be here. Not a supported video mime type.");
+ CHECK(!"Should not be here. Not a supported video mime type.");
}
OMX_COLOR_FORMATTYPE colorFormat =
0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
+ if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
+ colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+ }
+
setVideoPortFormatType(
kPortIndexInput, OMX_VIDEO_CodingUnused,
colorFormat);
@@ -598,9 +597,9 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
- assert(def.eDomain == OMX_PortDomainVideo);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
@@ -610,7 +609,7 @@
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
////////////////////////////////////////////////////////////////////////////
@@ -621,12 +620,12 @@
err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
LOGI("setting nBufferSize = %ld", def.nBufferSize);
- assert(def.eDomain == OMX_PortDomainVideo);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
@@ -635,7 +634,7 @@
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::setVideoOutputFormat(
@@ -659,7 +658,7 @@
status_t err = mOMX->set_parameter(
mNode, OMX_IndexParamStandardComponentRole,
&role, sizeof(role));
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
#endif
@@ -672,7 +671,7 @@
compressionFormat = OMX_VIDEO_CodingH263;
} else {
LOGE("Not a supported video mime type: %s", mime);
- assert(!"Should not be here. Not a supported video mime type.");
+ CHECK(!"Should not be here. Not a supported video mime type.");
}
setVideoPortFormatType(
@@ -690,13 +689,13 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
- assert(err == OK);
+ CHECK_EQ(err, OK);
- assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+ CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
- assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
|| format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
|| format.eColorFormat == OMX_COLOR_FormatCbYCrY
|| format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
@@ -704,7 +703,7 @@
err = mOMX->set_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
#endif
@@ -719,7 +718,7 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
#if 1
// XXX Need a (much) better heuristic to compute input buffer sizes.
@@ -729,7 +728,7 @@
}
#endif
- assert(def.eDomain == OMX_PortDomainVideo);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
@@ -738,7 +737,7 @@
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
////////////////////////////////////////////////////////////////////////////
@@ -749,9 +748,9 @@
err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
- assert(def.eDomain == OMX_PortDomainVideo);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
#if 0
def.nBufferSize =
@@ -763,7 +762,7 @@
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::setup() {
@@ -771,7 +770,7 @@
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
+ CHECK(success);
if (!strcasecmp(mime, "audio/3gpp")) {
setAMRFormat();
@@ -781,7 +780,7 @@
int32_t width, height;
bool success = meta->findInt32(kKeyWidth, &width);
success = success && meta->findInt32(kKeyHeight, &height);
- assert(success);
+ CHECK(success);
if (mIsEncoder) {
setVideoInputFormat(mime, width, height);
@@ -804,14 +803,14 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
switch (def.eDomain) {
case OMX_PortDomainAudio:
{
OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
- assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM);
+ CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
OMX_AUDIO_PARAM_PCMMODETYPE params;
params.nSize = sizeof(params);
@@ -821,11 +820,11 @@
err = mOMX->get_parameter(
mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
- assert(err == OK);
+ CHECK_EQ(err, OK);
- assert(params.eNumData == OMX_NumericalDataSigned);
- assert(params.nBitPerSample == 16);
- assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+ CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+ CHECK_EQ(params.nBitPerSample, 16);
+ CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
int32_t numChannels, sampleRate;
meta->findInt32(kKeyChannelCount, &numChannels);
@@ -850,7 +849,7 @@
} else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
mOutputFormat->setCString(kKeyMIMEType, "video/avc");
} else {
- assert(!"Unknown compression format.");
+ CHECK(!"Unknown compression format.");
}
if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
@@ -870,7 +869,7 @@
default:
{
- assert(!"should not be here, neither audio nor video.");
+ CHECK(!"should not be here, neither audio nor video.");
break;
}
}
@@ -880,7 +879,7 @@
if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
allocateBuffers(kPortIndexInput);
@@ -891,12 +890,12 @@
// h264 vdec disagrees.
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
}
void OMXDecoder::allocateBuffers(OMX_U32 port_index) {
- assert(mBuffers[port_index].empty());
+ CHECK(mBuffers[port_index].empty());
OMX_U32 num_buffers;
OMX_U32 buffer_size;
@@ -911,7 +910,7 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
num_buffers = def.nBufferCountActual;
buffer_size = def.nBufferSize;
@@ -925,7 +924,7 @@
LOGE("[%s] allocating IMemory of size %ld FAILED.",
mComponentName, buffer_size);
}
- assert(mem.get() != NULL);
+ CHECK(mem.get() != NULL);
IOMX::buffer_id buffer;
status_t err;
@@ -960,7 +959,7 @@
mComponentName, err);
}
}
- assert(err == OK);
+ CHECK_EQ(err, OK);
LOGV("allocated %s buffer %p.",
port_index == kPortIndexInput ? "INPUT" : "OUTPUT",
@@ -1019,7 +1018,7 @@
case OMX_CommandPortDisable: {
OMX_U32 port_index = data;
- assert(getPortStatus(port_index) == kPortStatusDisabled);
+ CHECK_EQ(getPortStatus(port_index), kPortStatusDisabled);
status_t err =
mOMX->send_command(mNode, OMX_CommandPortEnable, port_index);
@@ -1031,10 +1030,10 @@
case OMX_CommandPortEnable: {
OMX_U32 port_index = data;
- assert(getPortStatus(port_index) ==kPortStatusDisabled);
+ CHECK(getPortStatus(port_index) ==kPortStatusDisabled);
setPortStatus(port_index, kPortStatusActive);
- assert(port_index == kPortIndexOutput);
+ CHECK_EQ(port_index, kPortIndexOutput);
BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
while (!obuffers->empty()) {
@@ -1053,7 +1052,7 @@
PortStatus status = getPortStatus(port_index);
- assert(status == kPortStatusFlushing
+ CHECK(status == kPortStatusFlushing
|| status == kPortStatusFlushingToDisabled
|| status == kPortStatusFlushingToShutdown);
@@ -1085,7 +1084,7 @@
setPortStatus(port_index, kPortStatusDisabled);
status_t err = mOMX->send_command(
mNode, OMX_CommandPortDisable, port_index);
- assert(err == OK);
+ CHECK_EQ(err, OK);
freePortBuffers(port_index);
break;
@@ -1093,14 +1092,14 @@
default:
{
- assert(status == kPortStatusFlushingToShutdown);
+ CHECK_EQ(status, kPortStatusFlushingToShutdown);
setPortStatus(port_index, kPortStatusShutdown);
if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
&& getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
status_t err = mOMX->send_command(
mNode, OMX_CommandStateSet, OMX_StateIdle);
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
break;
}
@@ -1114,7 +1113,7 @@
}
void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
- assert(getPortStatus(port_index) == kPortStatusActive);
+ CHECK_EQ(getPortStatus(port_index), kPortStatusActive);
status_t err;
@@ -1131,18 +1130,18 @@
err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
}
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::onStateChanged(OMX_STATETYPE to) {
if (mState == OMX_StateLoaded) {
- assert(to == OMX_StateIdle);
+ CHECK_EQ(to, OMX_StateIdle);
mState = to;
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateExecuting);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
} else if (mState == OMX_StateIdle) {
if (to == OMX_StateExecuting) {
mState = to;
@@ -1163,7 +1162,7 @@
postInitialFillBuffer(buffer);
}
} else {
- assert(to == OMX_StateLoaded);
+ CHECK_EQ(to, OMX_StateLoaded);
mState = to;
@@ -1171,14 +1170,14 @@
setPortStatus(kPortIndexOutput, kPortStatusActive);
}
} else if (mState == OMX_StateExecuting) {
- assert(to == OMX_StateIdle);
+ CHECK_EQ(to, OMX_StateIdle);
mState = to;
LOGV("Executing->Idle complete, initiating Idle->Loaded");
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
freePortBuffers(kPortIndexInput);
freePortBuffers(kPortIndexOutput);
@@ -1196,7 +1195,7 @@
return;
}
- assert(mState == OMX_StateExecuting);
+ CHECK_EQ(mState, OMX_StateExecuting);
mShutdownInitiated = true;
@@ -1204,7 +1203,7 @@
if (mQuirks & kDoesntFlushOnExecutingToIdle) {
if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
- assert(err == OK);
+ CHECK_EQ(err, OK);
err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
} else {
@@ -1220,7 +1219,7 @@
setPortStatus(kPortIndexInput, kPortStatusShutdown);
setPortStatus(kPortIndexOutput, kPortStatusShutdown);
}
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
@@ -1266,7 +1265,7 @@
err = NO_ERROR;
break;
}
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::onFillBufferDone(const omx_message &msg) {
@@ -1310,7 +1309,7 @@
break;
}
}
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
}
void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -1322,7 +1321,7 @@
}
const sp<IMemory> mem = mBufferMap.valueFor(buffer);
- assert(mem.get() != NULL);
+ CHECK(mem.get() != NULL);
static const uint8_t kNALStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
@@ -1331,15 +1330,15 @@
size_t range_length = 0;
- if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
- assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
+ if (mIsAVC && !(mQuirks & kWantsNALFragments)) {
+ CHECK((*mCodecSpecificDataIterator).size + 4 <= mem->size());
memcpy(mem->pointer(), kNALStartCode, 4);
memcpy((uint8_t *)mem->pointer() + 4, (*it).data, (*it).size);
range_length = (*it).size + 4;
} else {
- assert((*mCodecSpecificDataIterator).size <= mem->size());
+ CHECK((*mCodecSpecificDataIterator).size <= mem->size());
memcpy((uint8_t *)mem->pointer(), (*it).data, (*it).size);
range_length = (*it).size;
@@ -1371,7 +1370,7 @@
} else {
err = mSource->read(&input_buffer);
}
- assert((err == OK && input_buffer != NULL)
+ CHECK((err == OK && input_buffer != NULL)
|| (err != OK && input_buffer == NULL));
if (err == ERROR_END_OF_STREAM) {
@@ -1415,7 +1414,7 @@
src_length, mem->size());
}
- assert(src_length <= mem->size());
+ CHECK(src_length <= mem->size());
memcpy(mem->pointer(), src_data, src_length);
OMX_U32 flags = 0;
@@ -1520,7 +1519,7 @@
LOGV("freeInputBuffer %p", buffer);
status_t err = mOMX->free_buffer(mNode, kPortIndexInput, buffer);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
mBufferMap.removeItem(buffer);
LOGV("freeInputBuffer %p done", buffer);
@@ -1530,11 +1529,11 @@
LOGV("freeOutputBuffer %p", buffer);
status_t err = mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
mBufferMap.removeItem(buffer);
ssize_t index = mMediaBufferMap.indexOfKey(buffer);
- assert(index >= 0);
+ CHECK(index >= 0);
MediaBuffer *mbuffer = mMediaBufferMap.editValueAt(index);
mMediaBufferMap.removeItemsAt(index);
mbuffer->setObserver(NULL);
@@ -1553,7 +1552,7 @@
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- assert(err == NO_ERROR);
+ CHECK_EQ(err, NO_ERROR);
LOGI("DumpPortDefinition on port %ld", port_index);
LOGI("nBufferCountActual = %ld, nBufferCountMin = %ld, nBufferSize = %ld",
@@ -1565,7 +1564,7 @@
if (port_index == kPortIndexOutput) {
OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
- assert(audio_def->eEncoding == OMX_AUDIO_CodingPCM);
+ CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
OMX_AUDIO_PARAM_PCMMODETYPE params;
params.nSize = sizeof(params);
@@ -1575,12 +1574,12 @@
err = mOMX->get_parameter(
mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
- assert(err == OK);
+ CHECK_EQ(err, OK);
- assert(params.nChannels == 1 || params.bInterleaved);
- assert(params.eNumData == OMX_NumericalDataSigned);
- assert(params.nBitPerSample == 16);
- assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+ CHECK(params.nChannels == 1 || params.bInterleaved);
+ CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+ CHECK_EQ(params.nBitPerSample, 16);
+ CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
LOGI("nChannels = %ld, nSamplingRate = %ld",
params.nChannels, params.nSamplingRate);
@@ -1621,7 +1620,7 @@
void OMXDecoder::postEmptyBufferDone(IOMX::buffer_id buffer) {
omx_message msg;
msg.type = omx_message::EMPTY_BUFFER_DONE;
- msg.u.buffer_data.node = mNode;
+ msg.node = mNode;
msg.u.buffer_data.buffer = buffer;
postMessage(msg);
}
@@ -1629,7 +1628,7 @@
void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) {
omx_message msg;
msg.type = omx_message::INITIAL_FILL_BUFFER;
- msg.u.buffer_data.node = mNode;
+ msg.node = mNode;
msg.u.buffer_data.buffer = buffer;
postMessage(msg);
}
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8f1fa67..5e32559 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -18,9 +18,9 @@
#include <utils/Log.h>
#include <arpa/inet.h>
-#include <assert.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/SampleTable.h>
#include <media/stagefright/Utils.h>
@@ -31,7 +31,7 @@
static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
-SampleTable::SampleTable(DataSource *source)
+SampleTable::SampleTable(const sp<DataSource> &source)
: mDataSource(source),
mChunkOffsetOffset(-1),
mChunkOffsetType(0),
@@ -59,7 +59,7 @@
return ERROR_MALFORMED;
}
- assert(type == kChunkOffsetType32 || type == kChunkOffsetType64);
+ CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
mChunkOffsetOffset = data_offset;
mChunkOffsetType = type;
@@ -132,7 +132,7 @@
return ERROR_MALFORMED;
}
- assert(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
+ CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
mSampleSizeOffset = data_offset;
@@ -272,7 +272,7 @@
*offset = ntohl(offset32);
} else {
- assert(mChunkOffsetOffset == kChunkOffsetType64);
+ CHECK_EQ(mChunkOffsetOffset, kChunkOffsetType64);
uint64_t offset64;
if (mDataSource->read_at(
@@ -399,7 +399,7 @@
default:
{
- assert(mSampleSizeFieldSize == 4);
+ CHECK_EQ(mSampleSizeFieldSize, 4);
uint8_t x;
if (mDataSource->read_at(
@@ -569,26 +569,6 @@
}
}
-#if 1
- // Make sure we return a sample at or _after_ the requested one.
- // Seeking to a particular time in a media source containing audio and
- // video will most likely be able to sync fairly close to the requested
- // time in the audio track but may only be able to seek a fair distance
- // from the requested time in the video track.
- // If we seek the video track to a time earlier than the audio track,
- // we'll cause the video track to be late for quite a while, the decoder
- // trying to catch up.
- // If we seek the video track to a time later than the audio track,
- // audio will start playing fine while no video will be output for a
- // while, the video decoder will not stress the system.
- if (mDataSource->read_at(
- mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
- return ERROR_IO;
- }
- x = ntohl(x);
- assert((x - 1) >= start_sample_index);
-#endif
-
*sample_index = x - 1;
return OK;
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 17b626e..4375f38 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -19,6 +19,7 @@
#include <media/stagefright/HTTPStream.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/ShoutcastSource.h>
#include <media/stagefright/string.h>
@@ -36,8 +37,8 @@
char *end;
const char *start = metaint.c_str();
mMetaDataOffset = strtol(start, &end, 10);
- assert(end > start && *end == '\0');
- assert(mMetaDataOffset > 0);
+ CHECK(end > start && *end == '\0');
+ CHECK(mMetaDataOffset > 0);
mBytesUntilMetaData = mMetaDataOffset;
}
@@ -53,7 +54,7 @@
}
status_t ShoutcastSource::start(MetaData *) {
- assert(!mStarted);
+ CHECK(!mStarted);
mGroup = new MediaBufferGroup;
mGroup->add_buffer(new MediaBuffer(4096)); // XXX
@@ -64,7 +65,7 @@
}
status_t ShoutcastSource::stop() {
- assert(mStarted);
+ CHECK(mStarted);
delete mGroup;
mGroup = NULL;
@@ -85,7 +86,7 @@
status_t ShoutcastSource::read(
MediaBuffer **out, const ReadOptions *options) {
- assert(mStarted);
+ CHECK(mStarted);
*out = NULL;
@@ -120,7 +121,7 @@
if (mBytesUntilMetaData == 0) {
unsigned char num_16_byte_blocks = 0;
n = mHttp->receive((char *)&num_16_byte_blocks, 1);
- assert(n == 1);
+ CHECK_EQ(n, 1);
char meta[255 * 16];
size_t meta_size = num_16_byte_blocks * 16;
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 2f8a19f..3d85f75 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -24,9 +24,7 @@
#include <sys/time.h>
-#undef NDEBUG
-#include <assert.h>
-
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/TimedEventQueue.h>
namespace android {
@@ -89,7 +87,7 @@
void TimedEventQueue::postEventWithDelay(
const sp<Event> &event, int64_t delay_us) {
- assert(delay_us >= 0);
+ CHECK(delay_us >= 0);
postTimedEvent(event, getRealTimeUs() + delay_us);
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index ecd3b2e..77e42be 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -6,6 +6,8 @@
LOCAL_C_INCLUDES := $(PV_INCLUDES)
LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
+LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
+
LOCAL_SRC_FILES:= \
OMX.cpp \
QComHardwareRenderer.cpp \
@@ -15,11 +17,15 @@
LOCAL_SHARED_LIBRARIES := \
libbinder \
libmedia \
- libutils \
+ libutils \
libui \
libcutils \
libopencore_common
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
LOCAL_PRELINK_MODULE:= false
LOCAL_MODULE:= libstagefright_omx
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index d44e3a3..1e59b52 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -20,15 +20,13 @@
#include <sys/socket.h>
-#undef NDEBUG
-#include <assert.h>
-
#include "OMX.h"
#include "OMXRenderer.h"
#include "pv_omxcore.h"
#include <binder/IMemory.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/QComHardwareRenderer.h>
#include <media/stagefright/SoftwareRenderer.h>
#include <media/stagefright/TIHardwareRenderer.h>
@@ -50,7 +48,7 @@
}
void setHandle(OMX_HANDLETYPE handle) {
- assert(mHandle == NULL);
+ CHECK_EQ(mHandle, NULL);
mHandle = handle;
}
@@ -75,6 +73,102 @@
NodeMeta &operator=(const NodeMeta &);
};
+////////////////////////////////////////////////////////////////////////////////
+
+struct OMX::CallbackDispatcher : public RefBase {
+ CallbackDispatcher();
+
+ void post(const omx_message &msg);
+
+protected:
+ virtual ~CallbackDispatcher();
+
+private:
+ Mutex mLock;
+ bool mDone;
+ Condition mQueueChanged;
+ List<omx_message> mQueue;
+
+ pthread_t mThread;
+
+ void dispatch(const omx_message &msg);
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ CallbackDispatcher(const CallbackDispatcher &);
+ CallbackDispatcher &operator=(const CallbackDispatcher &);
+};
+
+OMX::CallbackDispatcher::CallbackDispatcher()
+ : mDone(false) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+}
+
+OMX::CallbackDispatcher::~CallbackDispatcher() {
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ mDone = true;
+ mQueueChanged.signal();
+ }
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+}
+
+void OMX::CallbackDispatcher::post(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+ mQueue.push_back(msg);
+ mQueueChanged.signal();
+}
+
+void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
+ NodeMeta *meta = static_cast<NodeMeta *>(msg.node);
+
+ sp<IOMXObserver> observer = meta->observer();
+ if (observer.get() != NULL) {
+ observer->on_message(msg);
+ }
+}
+
+// static
+void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
+ static_cast<CallbackDispatcher *>(me)->threadEntry();
+
+ return NULL;
+}
+
+void OMX::CallbackDispatcher::threadEntry() {
+ for (;;) {
+ omx_message msg;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ while (!mDone && mQueue.empty()) {
+ mQueueChanged.wait(mLock);
+ }
+
+ if (mDone) {
+ break;
+ }
+
+ msg = *mQueue.begin();
+ mQueue.erase(mQueue.begin());
+ }
+
+ dispatch(msg);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
class BufferMeta {
public:
BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
@@ -154,7 +248,8 @@
return meta->owner()->OnFillBufferDone(meta, pBuffer);
}
-OMX::OMX() {
+OMX::OMX()
+ : mDispatcher(new CallbackDispatcher) {
}
status_t OMX::list_nodes(List<String8> *list) {
@@ -249,6 +344,29 @@
return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
}
+status_t OMX::get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err = OMX_GetConfig(meta->handle(), index, params);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_SetConfig(meta->handle(), index, const_cast<void *>(params));
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
status_t OMX::use_buffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) {
@@ -357,15 +475,12 @@
omx_message msg;
msg.type = omx_message::EVENT;
- msg.u.event_data.node = meta;
+ msg.node = meta;
msg.u.event_data.event = eEvent;
msg.u.event_data.data1 = nData1;
msg.u.event_data.data2 = nData2;
- sp<IOMXObserver> observer = meta->observer();
- if (observer.get() != NULL) {
- observer->on_message(msg);
- }
+ mDispatcher->post(msg);
return OMX_ErrorNone;
}
@@ -376,13 +491,10 @@
omx_message msg;
msg.type = omx_message::EMPTY_BUFFER_DONE;
- msg.u.buffer_data.node = meta;
+ msg.node = meta;
msg.u.buffer_data.buffer = pBuffer;
- sp<IOMXObserver> observer = meta->observer();
- if (observer.get() != NULL) {
- observer->on_message(msg);
- }
+ mDispatcher->post(msg);
return OMX_ErrorNone;
}
@@ -395,7 +507,7 @@
omx_message msg;
msg.type = omx_message::FILL_BUFFER_DONE;
- msg.u.extended_buffer_data.node = meta;
+ msg.node = meta;
msg.u.extended_buffer_data.buffer = pBuffer;
msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
@@ -403,10 +515,7 @@
msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
- sp<IOMXObserver> observer = meta->observer();
- if (observer.get() != NULL) {
- observer->on_message(msg);
- }
+ mDispatcher->post(msg);
return OMX_ErrorNone;
}
@@ -430,7 +539,7 @@
OMX_ERRORTYPE err =
OMX_FillThisBuffer(node_meta->handle(), header);
- assert(err == OMX_ErrorNone);
+ CHECK_EQ(err, OMX_ErrorNone);
}
void OMX::empty_buffer(
@@ -452,7 +561,21 @@
OMX_ERRORTYPE err =
OMX_EmptyThisBuffer(node_meta->handle(), header);
- assert(err == OMX_ErrorNone);
+ CHECK_EQ(err, OMX_ErrorNone);
+}
+
+status_t OMX::get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_GetExtensionIndex(
+ node_meta->handle(),
+ const_cast<char *>(parameter_name), index);
+
+ return err == OMX_ErrorNone ? OK : UNKNOWN_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
index 8ac311c..6325f79 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/omx/OMX.h
@@ -44,6 +44,14 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size);
+
virtual status_t use_buffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer);
@@ -70,6 +78,11 @@
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp);
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index);
+
virtual sp<IOMXRenderer> createRenderer(
const sp<ISurface> &surface,
const char *componentName,
@@ -82,6 +95,9 @@
Mutex mLock;
+ struct CallbackDispatcher;
+ sp<CallbackDispatcher> mDispatcher;
+
static OMX_ERRORTYPE OnEvent(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
index 5a23792..e9930be 100644
--- a/media/libstagefright/omx/QComHardwareRenderer.cpp
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-#undef NDEBUG
-#include <assert.h>
-
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryHeapPmem.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/QComHardwareRenderer.h>
#include <ui/ISurface.h>
@@ -68,9 +66,9 @@
mDecodedWidth(decodedWidth),
mDecodedHeight(decodedHeight),
mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
- assert(mISurface.get() != NULL);
- assert(mDecodedWidth > 0);
- assert(mDecodedHeight > 0);
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
}
QComHardwareRenderer::~QComHardwareRenderer() {
@@ -133,7 +131,7 @@
mMemoryHeap);
status_t err = mISurface->registerBuffers(bufferHeap);
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
} // namespace android
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 5483238..da97d55 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -17,10 +17,8 @@
#define LOG_TAG "SoftwareRenderer"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/SoftwareRenderer.h>
#include <ui/ISurface.h>
@@ -40,10 +38,10 @@
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
mIndex(0) {
- assert(mISurface.get() != NULL);
- assert(mDecodedWidth > 0);
- assert(mDecodedHeight > 0);
- assert(mMemoryHeap->heapID() >= 0);
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
+ CHECK(mMemoryHeap->heapID() >= 0);
ISurface::BufferHeap bufferHeap(
mDisplayWidth, mDisplayHeight,
@@ -52,7 +50,7 @@
mMemoryHeap);
status_t err = mISurface->registerBuffers(bufferHeap);
- assert(err == OK);
+ CHECK_EQ(err, OK);
}
SoftwareRenderer::~SoftwareRenderer() {
@@ -65,7 +63,7 @@
LOGE("size is %d, expected %d",
size, (mDecodedHeight * mDecodedWidth * 3) / 2);
}
- assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
+ CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
static const signed kClipMin = -278;
static const signed kClipMax = 535;
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
index ba42ef4..ebade4a 100644
--- a/media/libstagefright/omx/TIHardwareRenderer.cpp
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -17,13 +17,15 @@
#define LOG_TAG "TIHardwareRenderer"
#include <utils/Log.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <media/stagefright/TIHardwareRenderer.h>
+#include <media/stagefright/MediaDebug.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
+#include "v4l2_utils.h"
+
+#define CACHEABLE_BUFFERS 0x1
+
namespace android {
////////////////////////////////////////////////////////////////////////////////
@@ -37,10 +39,12 @@
mDisplayHeight(displayHeight),
mDecodedWidth(decodedWidth),
mDecodedHeight(decodedHeight),
- mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
- assert(mISurface.get() != NULL);
- assert(mDecodedWidth > 0);
- assert(mDecodedHeight > 0);
+ mFrameSize(mDecodedWidth * mDecodedHeight * 2),
+ mIsFirstFrame(true),
+ mIndex(0) {
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
sp<OverlayRef> ref = mISurface->createOverlay(
mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
@@ -51,11 +55,14 @@
}
mOverlay = new Overlay(ref);
+ mOverlay->setParameter(CACHEABLE_BUFFERS, 0);
- for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
- mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+ for (size_t i = 0; i < (size_t)mOverlay->getBufferCount(); ++i) {
+ mapping_data_t *data =
+ (mapping_data_t *)mOverlay->getBufferAddress((void *)i);
+
+ mOverlayAddresses.push(data->ptr);
}
- mIndex = mOverlayAddresses.size() - 1;
}
TIHardwareRenderer::~TIHardwareRenderer() {
@@ -70,27 +77,51 @@
void TIHardwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
- // assert(size == mFrameSize);
+ // CHECK_EQ(size, mFrameSize);
if (mOverlay.get() == NULL) {
return;
}
#if 0
- overlay_buffer_t buffer;
- if (mOverlay->dequeueBuffer(&buffer) == OK) {
- void *addr = mOverlay->getBufferAddress(buffer);
+ size_t i = 0;
+ for (; i < mOverlayAddresses.size(); ++i) {
+ if (mOverlayAddresses[i] == data) {
+ break;
+ }
- memcpy(addr, data, size);
+ if (mIsFirstFrame) {
+ LOGI("overlay buffer #%d: %p", i, mOverlayAddresses[i]);
+ }
+ }
- mOverlay->queueBuffer(buffer);
+ if (i == mOverlayAddresses.size()) {
+ LOGE("No suitable overlay buffer found.");
+ return;
+ }
+
+ mOverlay->queueBuffer((void *)i);
+
+ overlay_buffer_t overlay_buffer;
+ if (!mIsFirstFrame) {
+ CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
+ } else {
+ mIsFirstFrame = false;
}
#else
memcpy(mOverlayAddresses[mIndex], data, size);
+
mOverlay->queueBuffer((void *)mIndex);
- if (mIndex-- == 0) {
- mIndex = mOverlayAddresses.size() - 1;
+ if (++mIndex == mOverlayAddresses.size()) {
+ mIndex = 0;
+ }
+
+ overlay_buffer_t overlay_buffer;
+ if (!mIsFirstFrame) {
+ CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
+ } else {
+ mIsFirstFrame = false;
}
#endif
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index e76967d..3f2bc39 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -372,81 +372,81 @@
public static final String META_DATA_MP3 [][] = {
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
- "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
- "ID3V2.3 Title", "1234", "287", "1"},
+ "ID3V2.3 Title", "1234", "287", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", "1", "test ID3V1 Album", "test ID3V1 Artist",
- null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1"},
+ null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null,
- null, null, null, null, null, null, "231330", "1"},
+ null, null, null, null, null, null, "231330", "1", null},
//The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", null, "295", "1"},
+ "Blues", "ID3V2.3 Title", null, "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null,
- null, null, null, null, null, null, "295", "1"}
+ null, null, null, null, null, null, "295", "1", null}
};
public static final String META_DATA_OTHERS [][] = {
{"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null,
null, null, "20080309T002415.000Z", null,
- null, null, "1404928", "2"},
+ null, null, "1404928", "2", null},
{"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
null, null, null, null,
- null, null, "126540", "1"},
+ null, null, "126540", "1", null},
{"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null,
null, null, null, null,
- null, null, "231180", "1"},
- {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation",
+ null, null, "231180", "1", null},
+ {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
+ "13", "Jaws Of Life", "2005", "19815424", "1", "m4a composer"},
{"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null,
null, null, null, "20051220T202015.000Z",
- null, null, null, "3771392", "2"},
+ null, null, null, "3771392", "2", null},
{"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
- {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda",
+ null, null, "2005", "231180", "1", null},
+ {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda",
"mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z",
- "41", "Kung Fu Panda", "2008", "5667840", "2"},
+ "41", "Kung Fu Panda", "2008", "5667840", "2", "mp4 composer"},
{"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
+ null, null, "2005", "231180", "1", null},
{"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg",
null, "Suspended Animation", "John Petrucci",
- null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"},
+ null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null,
null, null, null, null,
- null, null, null, "224000", "1"},
+ null, null, null, "224000", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal",
"Alien Crime Syndicate", "Alien Crime Syndicate",
"wma 9 Composer", "20040521T175729.483Z",
- "Rock", "Run for the Money", "2004", "134479", "1"},
+ "Rock", "Run for the Money", "2004", "134479", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album",
"wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z",
- "Acid Jazz", "wma 10 Title", "2010", "126574", "1"},
+ "Acid Jazz", "wma 10 Title", "2010", "126574", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album",
null, "wmv 9 Artist ", null, "20051122T155247.540Z",
- null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"},
+ null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2", null},
{"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album",
null, "Hallau Shoots & Company", null, "20020226T170045.891Z",
- null, "CODEC Shootout", "1986", "43709", "2"}
+ null, "CODEC Shootout", "1986", "43709", "2", null}
};
//output recorded video
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 3715913..1bf4958 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -36,7 +36,7 @@
FILE_PATH,CD_TRACK, ALBUM,
ARTIST, AUTHOR, COMPOSER,
DATE, GENRE, TITLE,
- YEAR, DURATION, NUM_TRACKS
+ YEAR, DURATION, NUM_TRACKS, WRITER
}
public static enum MP3_TEST_FILE{
@@ -130,8 +130,6 @@
validateMetatData(non_mp3_test_file.AMRWB.ordinal(), MediaNames.META_DATA_OTHERS);
}
- //Bug# 1440173 - skip this test case now
- @Suppress
@MediumTest
public static void testM4A1_Metadata() throws Exception {
validateMetatData(non_mp3_test_file.M4A1.ordinal(), MediaNames.META_DATA_OTHERS);
@@ -254,6 +252,10 @@
Log.v(TAG, "Track : "+ value);
assertEquals(TAG,meta_data_file[fileIndex][meta.NUM_TRACKS.ordinal()], value);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER);
+ Log.v(TAG, "Writer : "+ value);
+ assertEquals(TAG,meta_data_file[fileIndex][meta.WRITER.ordinal()], value);
+
retriever.release();
}
}
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index f569595..1b66662 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -897,6 +897,11 @@
if (lower < 0) {
lower += 256;
}
+ // If upper and lower both equal 0, it should be the end of string.
+ // Ignore left bytes from array to avoid potential issues
+ if (upper == 0 && lower == 0) {
+ return new String(c, 0, i);
+ }
c[i] = (char)((upper << 8) | lower);
}
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index 423d5a7..675272d 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -168,7 +168,7 @@
} else {
response = validateResponseCode(mListener.onPut(op));
}
- if (response != ResponseCodes.OBEX_HTTP_OK) {
+ if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
op.sendReply(response);
} else if (!op.isAborted) {
// wait for the final bit
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 132473a..022da0c 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -655,25 +655,27 @@
EGLConfig closestConfig = null;
int closestDistance = 1000;
for(EGLConfig config : configs) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
int d = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
- int distance = Math.abs(r - mRedSize)
- + Math.abs(g - mGreenSize)
- + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize)
- + Math.abs(d - mDepthSize) + Math.abs(s - mStencilSize);
- if (distance < closestDistance) {
- closestDistance = distance;
- closestConfig = config;
+ if (d >= mDepthSize && s>= mStencilSize) {
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+ int distance = Math.abs(r - mRedSize)
+ + Math.abs(g - mGreenSize)
+ + Math.abs(b - mBlueSize)
+ + Math.abs(a - mAlphaSize);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestConfig = config;
+ }
}
}
return closestConfig;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 0762ebf..9c0f7fd 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -141,7 +141,8 @@
egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
virtual ~egl_surface_t();
- virtual bool isValid() const = 0;
+ bool isValid() const;
+ virtual bool initCheck() const = 0;
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
@@ -175,6 +176,11 @@
magic = 0;
free(depth.data);
}
+bool egl_surface_t::isValid() const {
+ LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
+ return magic == MAGIC;
+}
+
EGLBoolean egl_surface_t::swapBuffers() {
return EGL_FALSE;
}
@@ -208,9 +214,9 @@
int32_t depthFormat,
android_native_window_t* window);
- ~egl_window_surface_v2_t();
+ ~egl_window_surface_v2_t();
- virtual bool isValid() const { return nativeWindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC; }
+ virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails
virtual EGLBoolean swapBuffers();
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
@@ -704,7 +710,7 @@
virtual ~egl_pixmap_surface_t() { }
- virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual bool initCheck() const { return !depth.format || depth.data!=0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return nativePixmap.width; }
@@ -726,7 +732,6 @@
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
}
}
}
@@ -768,7 +773,7 @@
virtual ~egl_pbuffer_surface_t();
- virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual bool initCheck() const { return pbuffer.data != 0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return pbuffer.width; }
@@ -1196,6 +1201,11 @@
if (!(surfaceType & EGL_WINDOW_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<android_native_window_t*>(window)->common.magic !=
+ ANDROID_NATIVE_WINDOW_MAGIC) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -1241,7 +1251,7 @@
surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
static_cast<android_native_window_t*>(window));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -1265,6 +1275,11 @@
if (!(surfaceType & EGL_PIXMAP_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
+ sizeof(egl_native_pixmap_t)) {
+ return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -1307,7 +1322,7 @@
new egl_pixmap_surface_t(dpy, config, depthFormat,
static_cast<egl_native_pixmap_t*>(pixmap));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -1375,7 +1390,7 @@
egl_surface_t* surface =
new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -1590,7 +1605,7 @@
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (eglSurface != EGL_NO_SURFACE) {
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
- if (surface->magic != egl_surface_t::MAGIC)
+ if (!surface->isValid())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1610,6 +1625,8 @@
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (!surface->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1702,9 +1719,19 @@
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (draw) {
egl_surface_t* s = (egl_surface_t*)draw;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (s->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that draw and read are compatible with the context
+ // TODO: check that draw is compatible with the context
+ }
+ if (read && read!=draw) {
+ egl_surface_t* s = (egl_surface_t*)read;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that read is compatible with the context
}
EGLContext current_ctx = EGL_NO_CONTEXT;
@@ -1737,7 +1764,8 @@
egl_surface_t* r = (egl_surface_t*)read;
if (c->draw) {
- reinterpret_cast<egl_surface_t*>(c->draw)->disconnect();
+ egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
+ s->disconnect();
}
if (c->read) {
// FIXME: unlock/disconnect the read surface too
@@ -1860,6 +1888,8 @@
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -2073,6 +2103,8 @@
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -2088,6 +2120,8 @@
return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index 8ae32cc0f..f211bca 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -216,6 +216,8 @@
static inline void validate_light_mvi(ogles_context_t* c)
{
uint32_t en = c->lighting.enabledLights;
+ // Vector from object to viewer, in eye coordinates
+ const vec4_t eyeViewer = { 0, 0, 0x1000, 0 };
while (en) {
const int i = 31 - gglClz(en);
en &= ~(1<<i);
@@ -223,6 +225,9 @@
c->transforms.mvui.point4(&c->transforms.mvui,
&l.objPosition, &l.position);
vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+ c->transforms.mvui.point4(&c->transforms.mvui,
+ &l.objViewer, &eyeViewer);
+ vnorm3(l.objViewer.v, l.objViewer.v);
}
}
@@ -379,9 +384,9 @@
// specular
if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
vec4_t h;
- h.x = d.x;
- h.y = d.y;
- h.z = d.z + 0x10000;
+ h.x = d.x + l.objViewer.x;
+ h.y = d.y + l.objViewer.y;
+ h.z = d.z + l.objViewer.z;
vnorm3(h.v, h.v);
s = dot3(n.v, h.v);
s = (s<0) ? (twoSide?(-s):0) : s;
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index 0b68dc0..21ef50e 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -696,6 +696,8 @@
f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
c->transforms.dirty |= transform_state_t::VIEWPORT;
+ if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)
+ c->transforms.dirty |= transform_state_t::MVP;
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index e1fd48b..9578452 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -28,6 +28,10 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
+LOCAL_CFLAGS += -DADRENO130=1
+endif
+
include $(BUILD_SHARED_LIBRARY)
installed_libEGL := $(LOCAL_INSTALLED_MODULE)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 445e681..d51b333 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -224,12 +224,12 @@
void *Loader::load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask)
{
- //LOGD("%s", driver);
void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
- LOGE_IF(!dso, "%s", dlerror());
if (dso == 0)
return 0;
+ LOGD("loaded %s", driver);
+
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 64b82eb..d1ddcd3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -36,6 +36,8 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
+#include <utils/SortedVector.h>
+
#include "hooks.h"
#include "egl_impl.h"
#include "Loader.h"
@@ -50,7 +52,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
static char const * const gVendorString = "Android";
-static char const * const gVersionString = "1.31 Android META-EGL";
+static char const * const gVersionString = "1.4 Android META-EGL";
static char const * const gClientApiString = "OpenGL ES";
static char const * const gExtensionString =
"EGL_KHR_image "
@@ -63,40 +65,122 @@
// ----------------------------------------------------------------------------
-template <int MAGIC>
-struct egl_object_t
-{
- egl_object_t() : magic(MAGIC) { }
- ~egl_object_t() { magic = 0; }
- bool isValid() const { return magic == MAGIC; }
+class egl_object_t {
+ static SortedVector<egl_object_t*> sObjects;
+ static Mutex sLock;
+
+ volatile int32_t terminated;
+ mutable volatile int32_t count;
+
+public:
+ egl_object_t() : terminated(0), count(1) {
+ Mutex::Autolock _l(sLock);
+ sObjects.add(this);
+ }
+
+ inline bool isAlive() const { return !terminated; }
+
private:
- uint32_t magic;
+ bool get() {
+ Mutex::Autolock _l(sLock);
+ if (egl_object_t::sObjects.indexOf(this) >= 0) {
+ android_atomic_inc(&count);
+ return true;
+ }
+ return false;
+ }
+
+ bool put() {
+ Mutex::Autolock _l(sLock);
+ if (android_atomic_dec(&count) == 1) {
+ sObjects.remove(this);
+ return true;
+ }
+ return false;
+ }
+
+public:
+ template <typename N, typename T>
+ struct LocalRef {
+ N* ref;
+ LocalRef(T o) : ref(0) {
+ N* native = reinterpret_cast<N*>(o);
+ if (o && native->get()) {
+ ref = native;
+ }
+ }
+ ~LocalRef() {
+ if (ref && ref->put()) {
+ delete ref;
+ }
+ }
+ inline N* get() {
+ return ref;
+ }
+ void acquire() const {
+ if (ref) {
+ android_atomic_inc(&ref->count);
+ }
+ }
+ void release() const {
+ if (ref) {
+ int32_t c = android_atomic_dec(&ref->count);
+ // ref->count cannot be 1 prior atomic_dec because we have
+ // a reference, and if we have one, it means there was
+ // already one before us.
+ LOGE_IF(c==1, "refcount is now 0 in release()");
+ }
+ }
+ void terminate() {
+ if (ref) {
+ ref->terminated = 1;
+ release();
+ }
+ }
+ };
};
-struct egl_display_t : public egl_object_t<'_dpy'>
-{
- EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- char const* extensionsString;
- volatile int32_t refs;
+SortedVector<egl_object_t*> egl_object_t::sObjects;
+Mutex egl_object_t::sLock;
+
+struct egl_display_t {
+ enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
+
struct strings_t {
char const * vendor;
char const * version;
char const * clientApi;
char const * extensions;
};
- strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+
+ struct DisplayImpl {
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+ state(NOT_INITIALIZED), numConfigs(0) { }
+ EGLDisplay dpy;
+ EGLConfig* config;
+ EGLint state;
+ EGLint numConfigs;
+ strings_t queryString;
+ };
+
+ uint32_t magic;
+ DisplayImpl disp[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+ EGLint numTotalConfigs;
+ volatile int32_t refs;
+
+ egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
+ ~egl_display_t() { magic = 0; }
+ inline bool isValid() const { return magic == '_dpy'; }
+ inline bool isAlive() const { return isValid(); }
};
-struct egl_surface_t : public egl_object_t<'_srf'>
+struct egl_surface_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
+
egl_surface_t(EGLDisplay dpy, EGLSurface surface,
int impl, egl_connection_t const* cnx)
- : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
- {
- // NOTE: window must be incRef'ed and connected already
+ : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
}
~egl_surface_t() {
}
@@ -106,8 +190,10 @@
egl_connection_t const* cnx;
};
-struct egl_context_t : public egl_object_t<'_ctx'>
+struct egl_context_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
+
egl_context_t(EGLDisplay dpy, EGLContext context,
int impl, egl_connection_t const* cnx)
: dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
@@ -121,8 +207,10 @@
egl_connection_t const* cnx;
};
-struct egl_image_t : public egl_object_t<'_img'>
+struct egl_image_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
+
egl_image_t(EGLDisplay dpy, EGLContext context)
: dpy(dpy), context(context)
{
@@ -133,6 +221,10 @@
EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
};
+typedef egl_surface_t::Ref SurfaceRef;
+typedef egl_context_t::Ref ContextRef;
+typedef egl_image_t::Ref ImageRef;
+
struct tls_t
{
tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
@@ -272,14 +364,14 @@
static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- return (i>0 ? dp->numConfigs[0] : 0) + index;
+ return (i>0 ? dp->disp[0].numConfigs : 0) + index;
}
static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
int& i, int& index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- size_t numConfigs = dp->numConfigs[0];
+ size_t numConfigs = dp->disp[0].numConfigs;
i = configId / numConfigs;
index = configId % numConfigs;
}
@@ -326,32 +418,6 @@
// ----------------------------------------------------------------------------
-/*
- * To "loose" the GPU, use something like
- * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
- *
- */
-
-static int gl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return 0;
-}
-static int egl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
- usleep(100000); // don't use all the CPU
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static GLint egl_context_lost_get_error() {
- return EGL_CONTEXT_LOST;
-}
-static int ext_context_lost() {
- return 0;
-}
-
static void gl_no_context() {
tls_t* tls = getTLS();
if (tls->logCallWithNoContext == EGL_TRUE) {
@@ -417,7 +483,7 @@
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
index = uintptr_t(config) & 0xFFFFFF;
- if (index >= dp->numConfigs[impl]) {
+ if (index >= dp->disp[impl].numConfigs) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
egl_connection_t* const cnx = &gEGLImpl[impl];
@@ -431,11 +497,9 @@
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!ctx) // TODO: make sure context is a valid object
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!get_context(ctx)->isValid())
+ if (!get_context(ctx)->isAlive())
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
return EGL_TRUE;
}
@@ -444,114 +508,106 @@
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!surface) // TODO: make sure surface is a valid object
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (!get_surface(surface)->isValid())
+ if (!get_surface(surface)->isAlive())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
return EGL_TRUE;
}
-
EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
{
+ ImageRef _i(image);
+ if (!_i.get()) return EGL_NO_IMAGE_KHR;
+
EGLContext context = getContext();
if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
return EGL_NO_IMAGE_KHR;
egl_context_t const * const c = get_context(context);
- if (!c->isValid())
+ if (!c->isAlive())
return EGL_NO_IMAGE_KHR;
egl_image_t const * const i = get_image(image);
- if (!i->isValid())
- return EGL_NO_IMAGE_KHR;
-
return i->images[c->impl];
}
+// ----------------------------------------------------------------------------
-EGLDisplay egl_init_displays(NativeDisplayType display)
+// this mutex protects:
+// d->disp[]
+// egl_init_drivers_locked()
+//
+static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
+
+EGLBoolean egl_init_drivers_locked()
{
if (sEarlyInitState) {
- return EGL_NO_DISPLAY;
+ // initialized by static ctor. should be set here.
+ return EGL_FALSE;
}
- uint32_t index = uint32_t(display);
- if (index >= NUM_DISPLAYS) {
- return EGL_NO_DISPLAY;
- }
-
- EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
- egl_display_t* d = &gDisplay[index];
-
// get our driver loader
- Loader& loader(Loader::getInstance());
+ Loader& loader(Loader::getInstance());
- // dynamically load all our EGL implementations for that display
- // and call into the real eglGetGisplay()
- egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+ // dynamically load all our EGL implementations for all displays
+ // and retrieve the corresponding EGLDisplay
+ // if that fails, don't use this driver.
+ // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
+ egl_connection_t* cnx;
+ egl_display_t* d = &gDisplay[0];
+
+ cnx = &gEGLImpl[IMPL_SOFTWARE];
if (cnx->dso == 0) {
cnx->hooks = &gHooks[IMPL_SOFTWARE];
- cnx->dso = loader.open(display, 0, cnx->hooks);
- }
- if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
- d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
- LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
- "No EGLDisplay for software EGL!");
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
+ d->disp[IMPL_SOFTWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
}
cnx = &gEGLImpl[IMPL_HARDWARE];
- if (cnx->dso == 0 && cnx->unavailable == 0) {
+ if (cnx->dso == 0) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.hw", value, "1");
if (atoi(value) != 0) {
cnx->hooks = &gHooks[IMPL_HARDWARE];
- cnx->dso = loader.open(display, 1, cnx->hooks);
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
+ d->disp[IMPL_HARDWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
} else {
LOGD("3D hardware acceleration is disabled");
}
}
- if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
- (uint32_t)((void*)gl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
- (uint32_t)((void*)egl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
- (uint32_t)((void*)ext_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
- gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
- egl_context_lost_swap_buffers;
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
- egl_context_lost_get_error;
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
- gHooks[IMPL_HARDWARE].egl.eglTerminate;
-
- d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
- if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
- LOGE("h/w accelerated eglGetDisplay() failed (%s)",
- egl_strerror(cnx->hooks->egl.eglGetError()));
-
- loader.close(cnx->dso);
- cnx->dso = 0;
- // in case of failure, we want to make sure we don't try again
- // as it's expensive.
- cnx->unavailable = 1;
- }
+ if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
+ return EGL_FALSE;
}
- return dpy;
+ return EGL_TRUE;
}
+EGLBoolean egl_init_drivers()
+{
+ EGLBoolean res;
+ pthread_mutex_lock(&gInitDriverMutex);
+ res = egl_init_drivers_locked();
+ pthread_mutex_unlock(&gInitDriverMutex);
+ return res;
+}
// ----------------------------------------------------------------------------
}; // namespace android
@@ -561,7 +617,17 @@
EGLDisplay eglGetDisplay(NativeDisplayType display)
{
- return egl_init_displays(display);
+ uint32_t index = uint32_t(display);
+ if (index >= NUM_DISPLAYS) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+ return dpy;
}
// ----------------------------------------------------------------------------
@@ -584,7 +650,6 @@
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- dp->extensionsString = strdup(gExtensionString);
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
cnx->major = -1;
@@ -592,25 +657,43 @@
if (!cnx->dso)
continue;
- if (cnx->hooks->egl.eglInitialize(
- dp->dpys[i], &cnx->major, &cnx->minor)) {
+#if defined(ADRENO130)
+#warning "Adreno-130 eglInitialize() workaround"
+ /*
+ * The ADRENO 130 driver returns a different EGLDisplay each time
+ * eglGetDisplay() is called, but also makes the EGLDisplay invalid
+ * after eglTerminate() has been called, so that eglInitialize()
+ * cannot be called again. Therefore, we need to make sure to call
+ * eglGetDisplay() before calling eglInitialize();
+ */
+ if (i == IMPL_HARDWARE) {
+ dp->disp[i].dpy =
+ cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+#endif
+
+ EGLDisplay idpy = dp->disp[i].dpy;
+ if (cnx->hooks->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
//LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+ // i, idpy, cnx->major, cnx->minor, cnx);
+
+ // display is now initialized
+ dp->disp[i].state = egl_display_t::INITIALIZED;
// get the query-strings for this display for each implementation
- dp->queryString[i].vendor =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
- dp->queryString[i].version =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
- dp->queryString[i].extensions = strdup(
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
- dp->queryString[i].clientApi =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+ dp->disp[i].queryString.vendor =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_VENDOR);
+ dp->disp[i].queryString.version =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_VERSION);
+ dp->disp[i].queryString.extensions =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_EXTENSIONS);
+ dp->disp[i].queryString.clientApi =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
} else {
- LOGD("%d: eglInitialize() failed (%s)",
- i, egl_strerror(cnx->hooks->egl.eglGetError()));
+ LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ egl_strerror(cnx->hooks->egl.eglGetError()));
}
}
@@ -619,15 +702,16 @@
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
EGLint n;
- if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
- dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
- if (dp->configs[i]) {
+ if (cnx->hooks->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
+ dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+ if (dp->disp[i].config) {
if (cnx->hooks->egl.eglGetConfigs(
- dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+ dp->disp[i].dpy, dp->disp[i].config, n,
+ &dp->disp[i].numConfigs))
{
// sort the configurations so we can do binary searches
- qsort( dp->configs[i],
- dp->numConfigs[i],
+ qsort( dp->disp[i].config,
+ dp->disp[i].numConfigs,
sizeof(EGLConfig), cmp_configs);
dp->numTotalConfigs += n;
@@ -648,36 +732,36 @@
EGLBoolean eglTerminate(EGLDisplay dpy)
{
+ // NOTE: don't unload the drivers b/c some APIs can be called
+ // after eglTerminate() has been called. eglTerminate() only
+ // terminates an EGLDisplay, not a EGL itself.
+
egl_display_t* const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (android_atomic_dec(&dp->refs) != 1)
return EGL_TRUE;
-
- Loader& loader(Loader::getInstance());
EGLBoolean res = EGL_FALSE;
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- cnx->hooks->egl.eglTerminate(dp->dpys[i]);
-
- /* REVISIT: it's unclear what to do if eglTerminate() fails,
- * on one end we shouldn't care, on the other end if it fails
- * it might not be safe to call dlclose() (there could be some
- * threads around). */
-
- free(dp->configs[i]);
- free((void*)dp->queryString[i].extensions);
- dp->numConfigs[i] = 0;
- dp->dpys[i] = EGL_NO_DISPLAY;
+ if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
+ if (cnx->hooks->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
+ LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
+ egl_strerror(cnx->hooks->egl.eglGetError()));
+ }
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ free(dp->disp[i].config);
- loader.close(cnx->dso);
- cnx->dso = 0;
+ dp->disp[i].numConfigs = 0;
+ dp->disp[i].config = 0;
+ dp->disp[i].state = egl_display_t::TERMINATED;
+
res = EGL_TRUE;
}
}
- free((void*)dp->extensionsString);
- dp->extensionsString = 0;
+
+ // TODO: all egl_object_t should be marked for termination
+
dp->numTotalConfigs = 0;
clearTLS();
return res;
@@ -701,7 +785,7 @@
}
GLint n = 0;
for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
- for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+ for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
*configs++ = MAKE_CONFIG(j, i);
config_size--;
n++;
@@ -758,7 +842,7 @@
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index],
+ dp->disp[i].dpy, dp->disp[i].config[index],
EGL_CONFIG_ID, &configId);
// and switch to the new list
@@ -773,7 +857,7 @@
// which one.
res = cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n);
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n);
if (res && n>0) {
// n has to be 0 or 1, by construction, and we already know
// which config it will return (since there can be only one).
@@ -792,13 +876,14 @@
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
if (cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n)) {
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
if (configs) {
// now we need to convert these client EGLConfig to our
// internal EGLConfig format. This is done in O(n log n).
for (int j=0 ; j<n ; j++) {
int index = binarySearch<EGLConfig>(
- dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+ dp->disp[i].config, 0,
+ dp->disp[i].numConfigs-1, configs[j]);
if (index >= 0) {
if (configs) {
configs[j] = MAKE_CONFIG(i, index);
@@ -833,7 +918,7 @@
return EGL_TRUE;
}
return cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index], attribute, value);
+ dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
}
// ----------------------------------------------------------------------------
@@ -849,7 +934,7 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
- dp->dpys[i], dp->configs[i][index], window, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
@@ -867,7 +952,7 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
- dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
@@ -884,7 +969,7 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
- dp->dpys[i], dp->configs[i][index], attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
@@ -895,28 +980,35 @@
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
- egl_surface_t const * const s = get_surface(surface);
+ egl_surface_t * const s = get_surface(surface);
EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
- dp->dpys[s->impl], s->surface);
-
- delete s;
+ dp->disp[s->impl].dpy, s->surface);
+ if (result == EGL_TRUE) {
+ _s.terminate();
+ }
return result;
}
EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
EGLint attribute, EGLint *value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->hooks->egl.eglQuerySurface(
- dp->dpys[s->impl], s->surface, attribute, value);
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -931,7 +1023,8 @@
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLContext context = cnx->hooks->egl.eglCreateContext(
- dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index],
+ share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
return c;
@@ -942,66 +1035,125 @@
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
- dp->dpys[c->impl], c->context);
- delete c;
+ dp->disp[c->impl].dpy, c->context);
+ if (result == EGL_TRUE) {
+ _c.terminate();
+ }
return result;
}
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
+ // get a reference to the object passed in
+ ContextRef _c(ctx);
+ SurfaceRef _d(draw);
+ SurfaceRef _r(read);
+
+ // validate the display and the context (if not EGL_NO_CONTEXT)
egl_display_t const * const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
- ctx == EGL_NO_CONTEXT)
- {
- EGLBoolean result = EGL_TRUE;
- ctx = getContext();
- if (ctx) {
- egl_context_t * const c = get_context(ctx);
- result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
- if (result == EGL_TRUE) {
- setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
- setContext(EGL_NO_CONTEXT);
- }
- }
- return result;
+ if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
+ // EGL_NO_CONTEXT is valid
+ return EGL_FALSE;
}
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
+ // these are the underlying implementation's object
+ EGLContext impl_ctx = EGL_NO_CONTEXT;
EGLSurface impl_draw = EGL_NO_SURFACE;
EGLSurface impl_read = EGL_NO_SURFACE;
- egl_context_t * const c = get_context(ctx);
+
+ // these are our objects structs passed in
+ egl_context_t * c = NULL;
+ egl_surface_t const * d = NULL;
+ egl_surface_t const * r = NULL;
+
+ // these are the current objects structs
+ egl_context_t * cur_c = get_context(getContext());
+ egl_surface_t * cur_r = NULL;
+ egl_surface_t * cur_d = NULL;
+
+ if (ctx != EGL_NO_CONTEXT) {
+ c = get_context(ctx);
+ cur_r = get_surface(c->read);
+ cur_d = get_surface(c->draw);
+ impl_ctx = c->context;
+ } else {
+ // no context given, use the implementation of the current context
+ if (cur_c == NULL) {
+ // no current context
+ if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+ // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+ // not an error, there is just not current context.
+ return EGL_TRUE;
+ }
+ }
+
+ // retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
- egl_surface_t const * d = get_surface(draw);
- if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->impl != c->impl)
+ d = get_surface(draw);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && d->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_draw = d->surface;
}
+
+ // retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
- egl_surface_t const * r = get_surface(read);
- if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (r->impl != c->impl)
+ r = get_surface(read);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && r->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_read = r->surface;
}
- EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
- dp->dpys[c->impl], impl_draw, impl_read, c->context);
+
+ EGLBoolean result;
+
+ if (c) {
+ result = c->cnx->hooks->egl.eglMakeCurrent(
+ dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ } else {
+ result = cur_c->cnx->hooks->egl.eglMakeCurrent(
+ dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ }
if (result == EGL_TRUE) {
- setGlThreadSpecific(c->cnx->hooks);
- setContext(ctx);
- c->read = read;
- c->draw = draw;
+ // by construction, these are either 0 or valid (possibly terminated)
+ // it should be impossible for these to be invalid
+ ContextRef _cur_c(cur_c);
+ SurfaceRef _cur_r(cur_r);
+ SurfaceRef _cur_d(cur_d);
+
+ // cur_c has to be valid here (but could be terminated)
+ if (ctx != EGL_NO_CONTEXT) {
+ setGlThreadSpecific(c->cnx->hooks);
+ setContext(ctx);
+ _c.acquire();
+ } else {
+ setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+ setContext(EGL_NO_CONTEXT);
+ }
+ _cur_c.release();
+
+ _r.acquire();
+ _cur_r.release();
+ if (c) c->read = read;
+
+ _d.acquire();
+ _cur_d.release();
+ if (c) c->draw = draw;
}
return result;
}
@@ -1010,6 +1162,9 @@
EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
EGLint attribute, EGLint *value)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
@@ -1017,17 +1172,23 @@
egl_context_t * const c = get_context(ctx);
return c->cnx->hooks->egl.eglQueryContext(
- dp->dpys[c->impl], c->context, attribute, value);
+ dp->disp[c->impl].dpy, c->context, attribute, value);
}
EGLContext eglGetCurrentContext(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_CONTEXT.
+
EGLContext ctx = getContext();
return ctx;
}
EGLSurface eglGetCurrentSurface(EGLint readdraw)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_SURFACE.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1043,6 +1204,9 @@
EGLDisplay eglGetCurrentDisplay(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_DISPLAY.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1054,6 +1218,9 @@
EGLBoolean eglWaitGL(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1071,6 +1238,9 @@
EGLBoolean eglWaitNative(EGLint engine)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1107,9 +1277,11 @@
// eglGetProcAddress() could be the very first function called
// in which case we must make sure we've initialized ourselves, this
// happens the first time egl_get_display() is called.
-
- if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
- return NULL;
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ setError(EGL_BAD_PARAMETER, NULL);
+ return NULL;
+ }
__eglMustCastToProperFunctionPointerType addr;
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
@@ -1168,22 +1340,28 @@
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
- return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+ return s->cnx->hooks->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
NativePixmapType target)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->hooks->egl.eglCopyBuffers(
- dp->dpys[s->impl], s->surface, target);
+ dp->disp[s->impl].dpy, s->surface, target);
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -1210,13 +1388,16 @@
EGLBoolean eglSurfaceAttrib(
EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglSurfaceAttrib) {
return s->cnx->hooks->egl.eglSurfaceAttrib(
- dp->dpys[s->impl], s->surface, attribute, value);
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1224,13 +1405,16 @@
EGLBoolean eglBindTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglBindTexImage) {
return s->cnx->hooks->egl.eglBindTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1238,13 +1422,16 @@
EGLBoolean eglReleaseTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglReleaseTexImage) {
return s->cnx->hooks->egl.eglReleaseTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1259,7 +1446,8 @@
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
if (cnx->hooks->egl.eglSwapInterval) {
- if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+ if (cnx->hooks->egl.eglSwapInterval(
+ dp->disp[i].dpy, interval) == EGL_FALSE) {
res = EGL_FALSE;
}
}
@@ -1275,6 +1463,8 @@
EGLBoolean eglWaitClient(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1296,6 +1486,10 @@
EGLBoolean eglBindAPI(EGLenum api)
{
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
// bind this API on all EGLs
EGLBoolean res = EGL_TRUE;
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
@@ -1313,6 +1507,10 @@
EGLenum eglQueryAPI(void)
{
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
@@ -1351,7 +1549,8 @@
if (!cnx) return EGL_FALSE;
if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
- dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+ dp->disp[i].dpy, buftype, buffer,
+ dp->disp[i].config[index], attrib_list);
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
@@ -1363,6 +1562,9 @@
EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
const EGLint *attrib_list)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
@@ -1371,13 +1573,16 @@
if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
return s->cnx->hooks->egl.eglLockSurfaceKHR(
- dp->dpys[s->impl], s->surface, attrib_list);
+ dp->disp[s->impl].dpy, s->surface, attrib_list);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
@@ -1386,7 +1591,7 @@
if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
- dp->dpys[s->impl], s->surface);
+ dp->disp[s->impl].dpy, s->surface);
}
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
@@ -1395,13 +1600,15 @@
EGLClientBuffer buffer, const EGLint *attrib_list)
{
if (ctx != EGL_NO_CONTEXT) {
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
if (!validate_display_context(dpy, ctx))
return EGL_NO_IMAGE_KHR;
egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
// since we have an EGLContext, we know which implementation to use
EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
- dp->dpys[c->impl], c->context, target, buffer, attrib_list);
+ dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
if (image == EGL_NO_IMAGE_KHR)
return image;
@@ -1425,7 +1632,7 @@
if (cnx->dso) {
if (cnx->hooks->egl.eglCreateImageKHR) {
implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
- dp->dpys[i], ctx, target, buffer, attrib_list);
+ dp->disp[i].dpy, ctx, target, buffer, attrib_list);
if (implImages[i] != EGL_NO_IMAGE_KHR) {
success = true;
}
@@ -1443,16 +1650,15 @@
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
{
- egl_display_t const * const dp = get_display(dpy);
+ egl_display_t const * const dp = get_display(dpy);
if (dp == 0) {
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
- egl_image_t* image = get_image(img);
- if (!image->isValid()) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
+ ImageRef _i(img);
+ if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_image_t* image = get_image(img);
bool success = false;
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
@@ -1460,7 +1666,7 @@
if (cnx->dso) {
if (cnx->hooks->egl.eglCreateImageKHR) {
if (cnx->hooks->egl.eglDestroyImageKHR(
- dp->dpys[i], image->images[i])) {
+ dp->disp[i].dpy, image->images[i])) {
success = true;
}
}
@@ -1470,7 +1676,7 @@
if (!success)
return EGL_FALSE;
- delete image;
+ _i.terminate();
return EGL_TRUE;
}
@@ -1483,26 +1689,32 @@
EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
EGLint left, EGLint top, EGLint width, EGLint height)
{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
- return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
- s->surface, left, top, width, height);
+ return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(
+ dp->disp[s->impl].dpy, s->surface, left, top, width, height);
}
return setError(EGL_BAD_DISPLAY, NULL);
}
EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
+
if (!validate_display_surface(dpy, draw))
return 0;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) {
- return s->cnx->hooks->egl.eglGetRenderBufferANDROID(dp->dpys[s->impl],
- s->surface);
+ return s->cnx->hooks->egl.eglGetRenderBufferANDROID(
+ dp->disp[s->impl].dpy, s->surface);
}
return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
}
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index c5f753d..ac286cb 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -35,7 +35,6 @@
gl_hooks_t * hooks;
EGLint major;
EGLint minor;
- int unavailable;
};
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 37292ee..8c0357e 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -60,12 +60,8 @@
enum {
IMPL_HARDWARE = 0,
IMPL_SOFTWARE,
-
IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
-
- IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
- IMPL_NO_CONTEXT,
-
+ IMPL_NO_CONTEXT = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
IMPL_NUM_IMPLEMENTATIONS
};
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6a1f6f8..8f4061e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -64,7 +64,7 @@
private static final String TAG = "SettingsProvider";
private static final String DATABASE_NAME = "settings.db";
- private static final int DATABASE_VERSION = 38;
+ private static final int DATABASE_VERSION = 39;
private Context mContext;
@@ -389,21 +389,6 @@
if (upgradeVersion == 34) {
db.beginTransaction();
try {
- String value =
- mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0";
- db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
- Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');");
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
-
- upgradeVersion = 35;
- }
-
- if (upgradeVersion == 35) {
- db.beginTransaction();
- try {
SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
loadSecure35Settings(stmt);
@@ -412,8 +397,15 @@
} finally {
db.endTransaction();
}
+ }
+ // due to a botched merge from donut to eclair, the initialization of ASSISTED_GPS_ENABLED
+ // was accidentally done out of order here.
+ // to fix this, ASSISTED_GPS_ENABLED is now initialized while upgrading from 38 to 39,
+ // and we intentionally do nothing from 35 to 36 now.
+ if (upgradeVersion == 35) {
upgradeVersion = 36;
}
+
if (upgradeVersion == 36) {
// This upgrade adds the STREAM_SYSTEM_ENFORCED type to the list of
// types affected by ringer modes (silent, vibrate, etc.)
@@ -450,6 +442,21 @@
upgradeVersion = 38;
}
+ if (upgradeVersion == 38) {
+ db.beginTransaction();
+ try {
+ String value =
+ mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0";
+ db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
+ Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ upgradeVersion = 39;
+ }
+
if (upgradeVersion != currentVersion) {
Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+ ", must wipe the settings provider");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index a5bd254..56a279a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -30,7 +30,7 @@
import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.BackupHelperAgent;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -393,7 +393,7 @@
}
private void enableBluetooth(boolean enable) {
- BluetoothDevice bt = (BluetoothDevice) getSystemService(Context.BLUETOOTH_SERVICE);
+ BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE);
if (bt != null) {
if (!enable) {
bt.disable();
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index d839c4e..a3938bd 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -13,7 +13,8 @@
android:label="@string/app_label">
<uses-library android:name="com.google.android.gtalkservice" />
<provider android:name="SubscribedFeedsProvider"
- android:authorities="subscribedfeeds" android:syncable="false"
+ android:authorities="subscribedfeeds"
+ android:label="@string/provider_label"
android:multiprocess="false"
android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ"
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
diff --git a/packages/SubscribedFeedsProvider/res/values/strings.xml b/packages/SubscribedFeedsProvider/res/values/strings.xml
index 072571d..c4c2484 100644
--- a/packages/SubscribedFeedsProvider/res/values/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values/strings.xml
@@ -17,5 +17,9 @@
<resources>
<!-- Title of the feed synchronization activity. -->
<string name="app_label">Sync Feeds</string>
+
+ <!-- What to show in messaging that refers to this provider, e.g. AccountSyncSettings -->
+ <string name="provider_label">Push Subscriptions</string>
+
</resources>
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 3cd2cc4..b854f86 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -113,7 +113,7 @@
// TODO(fredq) fix the hardcoded type
final Account account = new Account(accountName, "com.google.GAIA");
c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
- null, where, new String[]{account.mName, account.mType, feed}, null);
+ null, where, new String[]{account.name, account.type, feed}, null);
if (c.getCount() == 0) {
Log.w(TAG, "received tickle for non-existent feed: "
+ "account " + accountName + ", feed " + feed);
@@ -171,12 +171,12 @@
try {
ContentValues values = new ContentValues();
for (Account account : accounts) {
- values.put(SyncConstValue._SYNC_ACCOUNT, account.mName);
- values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.mType);
+ values.put(SyncConstValue._SYNC_ACCOUNT, account.name);
+ values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type);
contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND "
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
- new String[] {account.mName, account.mType});
+ new String[] {account.name, account.type});
}
} catch (SQLiteFullException e) {
Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
index d87f5e7..2647752 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -16,6 +16,7 @@
package com.android.providers.subscribedfeeds;
+import android.accounts.Account;
import android.content.UriMatcher;
import android.content.*;
import android.database.Cursor;
@@ -123,6 +124,16 @@
}
@Override
+ protected void onAccountsChanged(Account[] accountsArray) {
+ super.onAccountsChanged(accountsArray);
+ for (Account account : accountsArray) {
+ if (account.type.equals("com.google.GAIA")) {
+ ContentResolver.setSyncAutomatically(account, "subscribedfeeds", true);
+ }
+ }
+ }
+
+ @Override
protected void onDatabaseOpened(SQLiteDatabase db) {
db.markTableSyncable("feeds", "_deleted_feeds");
}
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index a4090cf..1793587 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -26,16 +26,25 @@
#include <android_runtime/AndroidRuntime.h>
#include <tts/TtsEngine.h>
#include <media/AudioTrack.h>
+#include <math.h>
#include <dlfcn.h>
#define DEFAULT_TTS_RATE 16000
#define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT
#define DEFAULT_TTS_NB_CHANNELS 1
-#define DEFAULT_TTS_BUFFERSIZE 1024
+#define DEFAULT_TTS_BUFFERSIZE 2048
// TODO use the TTS stream type when available
#define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC
+// EQ + BOOST parameters
+#define FILTER_LOWSHELF_ATTENUATION -18.0f // in dB
+#define FILTER_TRANSITION_FREQ 1100.0f // in Hz
+#define FILTER_SHELF_SLOPE 1.0f // Q
+#define FILTER_GAIN 6.0f // linear gain
+// such a huge gain is justified by how much energy in the low frequencies is "wasted" at the output
+// of the synthesis. The low shelving filter removes it, leaving room for amplification.
+
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE 1
@@ -57,6 +66,79 @@
};
// ----------------------------------------------------------------------------
+// EQ data
+double amp;
+double w;
+double sinw;
+double cosw;
+double beta;
+double a0, a1, a2, b0, b1, b2;
+double m_fa, m_fb, m_fc, m_fd, m_fe;
+double x0; // x[n]
+double x1; // x[n-1]
+double x2; // x[n-2]
+double out0;// y[n]
+double out1;// y[n-1]
+double out2;// y[n-2]
+
+void initializeEQ() {
+
+ amp = float(pow(10.0, FILTER_LOWSHELF_ATTENUATION / 40.0));
+ w = 2.0 * M_PI * (FILTER_TRANSITION_FREQ / DEFAULT_TTS_RATE);
+ sinw = float(sin(w));
+ cosw = float(cos(w));
+ beta = float(sqrt(amp)/FILTER_SHELF_SLOPE);
+
+ // initialize low-shelf parameters
+ b0 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) + (beta*sinw));
+ b1 = 2.0F * amp * ((amp-1.0F) - ((amp+1.0F)*cosw));
+ b2 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) - (beta*sinw));
+ a0 = (amp+1.0F) + ((amp-1.0F)*cosw) + (beta*sinw);
+ a1 = 2.0F * ((amp-1.0F) + ((amp+1.0F)*cosw));
+ a2 = -((amp+1.0F) + ((amp-1.0F)*cosw) - (beta*sinw));
+
+ m_fa = FILTER_GAIN * b0/a0;
+ m_fb = FILTER_GAIN * b1/a0;
+ m_fc = FILTER_GAIN * b2/a0;
+ m_fd = a1/a0;
+ m_fe = a2/a0;
+}
+
+void initializeFilter() {
+ x0 = 0.0f;
+ x1 = 0.0f;
+ x2 = 0.0f;
+ out0 = 0.0f;
+ out1 = 0.0f;
+ out2 = 0.0f;
+}
+
+void applyFilter(int16_t* buffer, size_t sampleCount) {
+
+ for (size_t i=0 ; i<sampleCount ; i++) {
+
+ x0 = (double) buffer[i];
+
+ out0 = (m_fa*x0) + (m_fb*x1) + (m_fc*x2) + (m_fd*out1) + (m_fe*out2);
+
+ x2 = x1;
+ x1 = x0;
+
+ out2 = out1;
+ out1 = out0;
+
+ if (out0 > 32767.0f) {
+ buffer[i] = 32767;
+ } else if (out0 < -32768.0f) {
+ buffer[i] = -32768;
+ } else {
+ buffer[i] = (int16_t) out0;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
static fields_t javaTTSFields;
// TODO move to synth member once we have multiple simultaneous engines running
@@ -198,12 +280,13 @@
if (wav == NULL) {
delete pForAfter;
- LOGI("Null: speech has completed");
+ LOGV("Null: speech has completed");
}
if (bufferSize > 0) {
prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
+ applyFilter((int16_t*)wav, bufferSize/2);
pJniData->mAudioOut->write(wav, bufferSize);
memset(wav, 0, bufferSize);
//LOGV("AudioTrack wrote: %d bytes", bufferSize);
@@ -212,13 +295,14 @@
}
}
} else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
- LOGV("Save to file");
+ //LOGV("Save to file");
if (wav == NULL) {
delete pForAfter;
LOGV("Null: speech has completed");
return TTS_CALLBACK_HALT;
}
if (bufferSize > 0){
+ applyFilter((int16_t*)wav, bufferSize/2);
fwrite(wav, 1, bufferSize, pForAfter->outputFile);
memset(wav, 0, bufferSize);
}
@@ -289,6 +373,8 @@
env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData,
(int)pJniStorage);
+ initializeEQ();
+
env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
}
@@ -479,6 +565,8 @@
return result;
}
+ initializeFilter();
+
Mutex::Autolock l(engineMutex);
// Retrieve audio parameters before writing the file header
@@ -583,6 +671,8 @@
return result;
}
+ initializeFilter();
+
Mutex::Autolock l(engineMutex);
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index cd24727..5a72fcd 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -34,6 +34,8 @@
import android.speech.tts.ITtsCallback;
import android.speech.tts.TextToSpeech;
import android.util.Log;
+
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -138,6 +140,7 @@
private ContentResolver mResolver;
+ // lock for the speech queue (mSpeechQueue) and the current speech item (mCurrentSpeechItem)
private final ReentrantLock speechQueueLock = new ReentrantLock();
private final ReentrantLock synthesizerLock = new ReentrantLock();
@@ -173,10 +176,7 @@
public void onDestroy() {
super.onDestroy();
- // TODO replace the call to stopAll() with a method to clear absolutely all upcoming
- // uses of the native synth, including synthesis to a file, and delete files for which
- // synthesis was not complete.
- stopAll("");
+ killAllUtterances();
// Don't hog the media player
cleanUpPlayer();
@@ -477,6 +477,64 @@
}
+ /**
+ * Stops all speech output, both rendered to a file and directly spoken, and removes any
+ * utterances still in the queue globally. Files that were being written are deleted.
+ */
+ @SuppressWarnings("finally")
+ private int killAllUtterances() {
+ int result = TextToSpeech.ERROR;
+ boolean speechQueueAvailable = false;
+
+ try {
+ speechQueueAvailable = speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT,
+ TimeUnit.MILLISECONDS);
+ if (speechQueueAvailable) {
+ // remove every single entry in the speech queue
+ mSpeechQueue.clear();
+
+ // clear the current speech item
+ if (mCurrentSpeechItem != null) {
+ result = sNativeSynth.stop();
+ mKillList.put(mCurrentSpeechItem, true);
+ mIsSpeaking = false;
+
+ // was the engine writing to a file?
+ if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
+ // delete the file that was being written
+ // TODO make sure the synth is not writing to the file anymore
+ if (mCurrentSpeechItem.mFilename != null) {
+ File tempFile = new File(mCurrentSpeechItem.mFilename);
+ Log.v("TtsService", "Leaving behind " + mCurrentSpeechItem.mFilename);
+ if (tempFile.exists()) {
+ Log.v("TtsService", "About to delete "
+ + mCurrentSpeechItem.mFilename);
+ if (tempFile.delete()) {
+ Log.v("TtsService", "file successfully deleted");
+ }
+ }
+ }
+ }
+
+ mCurrentSpeechItem = null;
+ }
+ } else {
+ Log.e("TtsService", "TTS killAllUtterances(): queue locked longer than expected");
+ result = TextToSpeech.ERROR;
+ }
+ } catch (InterruptedException e) {
+ Log.e("TtsService", "TTS killAllUtterances(): tryLock interrupted");
+ result = TextToSpeech.ERROR;
+ } finally {
+ // This check is needed because finally will always run, even if the
+ // method returns somewhere in the try block.
+ if (speechQueueAvailable) {
+ speechQueueLock.unlock();
+ }
+ return result;
+ }
+ }
+
/**
* Stops all speech output and removes any utterances still in the queue globally, except
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 1c60058..e26dd13 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -100,6 +100,9 @@
// a process dies
private List mFeatureUsers;
+ private boolean mSystemReady;
+ private ArrayList<Intent> mDeferredBroadcasts;
+
private class NetworkAttributes {
/**
* Class for holding settings read from resources.
@@ -354,6 +357,11 @@
for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
if (t != mNetworkPreference &&
mNetTrackers[t].getNetworkInfo().isConnected()) {
+ if (DBG) {
+ Log.d(TAG, "tearing down " +
+ mNetTrackers[t].getNetworkInfo() +
+ " in enforcePreference");
+ }
teardown(mNetTrackers[t]);
}
}
@@ -510,7 +518,8 @@
mNetRequestersPids[usedNetworkType].add(currentPid);
}
- if (ni.isConnectedOrConnecting() == true) {
+ if ((ni.isConnectedOrConnecting() == true) &&
+ !network.isTeardownRequested()) {
if (ni.isConnected() == true) {
// add the pid-specific dns
handleDnsConfigurationChange();
@@ -683,6 +692,7 @@
++numConnectedNets;
}
}
+ if (DBG) Log.d(TAG, "numConnectedNets returning "+numConnectedNets);
return numConnectedNets;
}
@@ -789,7 +799,8 @@
if (newNet.isAvailable()) {
NetworkInfo switchTo = newNet.getNetworkInfo();
switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting()) {
+ if (!switchTo.isConnectedOrConnecting() ||
+ newNet.isTeardownRequested()) {
newNet.reconnect();
}
if (DBG) {
@@ -820,7 +831,7 @@
(newNet == null || !newNet.isAvailable() ? "" : " other=" +
newNet.getNetworkInfo().getTypeName()));
- mContext.sendStickyBroadcast(intent);
+ sendStickyBroadcast(intent);
/*
* If the failover network is already connected, then immediately send
* out a followup broadcast indicating successful failover
@@ -843,7 +854,7 @@
intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
info.getExtraInfo());
}
- mContext.sendStickyBroadcast(intent);
+ sendStickyBroadcast(intent);
}
/**
@@ -882,7 +893,33 @@
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
info.setFailover(false);
}
- mContext.sendStickyBroadcast(intent);
+ sendStickyBroadcast(intent);
+ }
+
+ private void sendStickyBroadcast(Intent intent) {
+ synchronized(this) {
+ if (mSystemReady) {
+ mContext.sendStickyBroadcast(intent);
+ } else {
+ if (mDeferredBroadcasts == null) {
+ mDeferredBroadcasts = new ArrayList<Intent>();
+ }
+ mDeferredBroadcasts.add(intent);
+ }
+ }
+ }
+
+ void systemReady() {
+ synchronized(this) {
+ mSystemReady = true;
+ if (mDeferredBroadcasts != null) {
+ int count = mDeferredBroadcasts.size();
+ for (int i = 0; i < count; i++) {
+ mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i));
+ }
+ mDeferredBroadcasts = null;
+ }
+ }
}
private void handleConnect(NetworkInfo info) {
@@ -1074,11 +1111,13 @@
int j = 1;
for (String dns : dnsList) {
if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ if (DBG) Log.d(TAG, " adding "+dns);
SystemProperties.set("net.dns" + j++, dns);
}
}
for (int k=j ; k<mNumDnsEntries; k++) {
- SystemProperties.set("net.dns" + j, "");
+ if (DBG) Log.d(TAG, "erasing net.dns" + k);
+ SystemProperties.set("net.dns" + k, "");
}
mNumDnsEntries = j;
} else {
@@ -1200,6 +1239,10 @@
NetworkInfo i = net.getNetworkInfo();
if (i.isConnected() &&
!mNetAttributes[i.getType()].isDefault()) {
+ if (DBG) {
+ Log.d(TAG, "tearing down " + i +
+ " to restore the default network");
+ }
teardown(net);
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
new file mode 100644
index 0000000..2bd039f
--- /dev/null
+++ b/services/java/com/android/server/DockObserver.java
@@ -0,0 +1,110 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UEventObserver;
+import android.util.Log;
+
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+
+/**
+ * <p>DockObserver monitors for a docking station.
+ */
+class DockObserver extends UEventObserver {
+ private static final String TAG = DockObserver.class.getSimpleName();
+ private static final boolean LOG = false;
+
+ private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
+ private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
+
+ private int mDockState;
+ private boolean mPendingIntent;
+
+ private final Context mContext;
+
+ public DockObserver(Context context) {
+ mContext = context;
+
+ startObserving(DOCK_UEVENT_MATCH);
+
+ init(); // set initial status
+ }
+
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Dock UEVENT: " + event.toString());
+ }
+
+ try {
+ update(Integer.parseInt(event.get("SWITCH_STATE")));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Could not parse switch state from event " + event);
+ }
+ }
+
+ private synchronized final void init() {
+ char[] buffer = new char[1024];
+
+ int newState = mDockState;
+ try {
+ FileReader file = new FileReader(DOCK_STATE_PATH);
+ int len = file.read(buffer, 0, 1024);
+ newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "This kernel does not have dock station support");
+ } catch (Exception e) {
+ Log.e(TAG, "" , e);
+ }
+
+ update(newState);
+ }
+
+ private synchronized final void update(int newState) {
+ if (newState != mDockState) {
+ mDockState = newState;
+
+ mPendingIntent = true;
+ mHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private synchronized final void sendIntent() {
+ Log.d(TAG, "Broadcasting dock state " + mDockState);
+
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (mPendingIntent) {
+ sendIntent();
+ mPendingIntent = false;
+ }
+ }
+ };
+}
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 7597f85..6ac72e0 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -141,8 +141,11 @@
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
- if (mCurrentVibration != null
- && mCurrentVibration.hasLongerTimeout(milliseconds)) {
+ // We're running in the system server so we cannot crash. Check for a
+ // timeout of 0 or negative. This will ensure that a vibration has
+ // either a timeout of > 0 or a non-null pattern.
+ if (milliseconds <= 0 || (mCurrentVibration != null
+ && mCurrentVibration.hasLongerTimeout(milliseconds))) {
// Ignore this vibration since the current vibration will play for
// longer than milliseconds.
return;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index fab97b1..2201b55 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1100,6 +1100,11 @@
}
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
+ if (provider == null) {
+ // throw NullPointerException to remain compatible with previous implementation
+ throw new NullPointerException();
+ }
+
// first check for permission to the provider
checkPermissionsSafe(provider);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
@@ -1110,7 +1115,7 @@
synchronized (mLock) {
LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (provider == null) {
+ if (proxy == null) {
return false;
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index f81c519..3d4bcc5 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -231,6 +231,7 @@
if (getMassStorageConnected() && !suppressIfConnected) {
Intent intent = new Intent();
intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
com.android.internal.R.string.usb_storage_notification_title,
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 5dad8d0..d0f6eee 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -35,6 +35,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
@@ -48,6 +49,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.Power;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Vibrator;
@@ -257,7 +259,8 @@
}
public void onNotificationClick(String pkg, int id) {
- cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL);
+ cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL,
+ Notification.FLAG_FOREGROUND_SERVICE);
}
public void onPanelRevealed() {
@@ -326,7 +329,7 @@
if (pkgName == null) {
return;
}
- cancelAllNotifications(pkgName);
+ cancelAllNotificationsInt(pkgName, 0, 0);
}
}
};
@@ -580,6 +583,8 @@
// ============================================================================
public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
{
+ checkIncomingCall(pkg);
+
// This conditional is a dirty hack to limit the logging done on
// behalf of the download manager without affecting other apps.
if (!pkg.equals("com.android.providers.downloads")
@@ -612,7 +617,20 @@
} else {
old = mNotificationList.remove(index);
mNotificationList.add(index, r);
+ // Make sure we don't lose the foreground service state.
+ if (old != null) {
+ notification.flags |=
+ old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
+ }
}
+
+ // Ensure if this is a foreground service that the proper additional
+ // flags are set.
+ if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ notification.flags |= Notification.FLAG_ONGOING_EVENT
+ | Notification.FLAG_NO_CLEAR;
+ }
+
if (notification.icon != 0) {
IconData icon = IconData.makeIcon(null, pkg, notification.icon,
notification.iconLevel,
@@ -807,9 +825,11 @@
}
/**
- * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}.
+ * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
+ * and none of the {@code mustNotHaveFlags}.
*/
- private void cancelNotification(String pkg, int id, int mustHaveFlags) {
+ private void cancelNotification(String pkg, int id, int mustHaveFlags,
+ int mustNotHaveFlags) {
EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
synchronized (mNotificationList) {
@@ -822,6 +842,9 @@
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
return;
}
+ if ((r.notification.flags & mustNotHaveFlags) != 0) {
+ return;
+ }
mNotificationList.remove(index);
@@ -835,7 +858,8 @@
* Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
- private void cancelAllNotificationsInt(String pkg, int mustHaveFlags) {
+ void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
+ int mustNotHaveFlags) {
EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
synchronized (mNotificationList) {
@@ -846,6 +870,9 @@
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
continue;
}
+ if ((r.notification.flags & mustNotHaveFlags) != 0) {
+ continue;
+ }
if (!r.pkg.equals(pkg)) {
continue;
}
@@ -860,17 +887,40 @@
}
- public void cancelNotification(String pkg, int id)
- {
- cancelNotification(pkg, id, 0);
+ public void cancelNotification(String pkg, int id) {
+ checkIncomingCall(pkg);
+ // Don't allow client applications to cancel foreground service notis.
+ cancelNotification(pkg, id, 0,
+ Binder.getCallingUid() == Process.SYSTEM_UID
+ ? 0 : Notification.FLAG_FOREGROUND_SERVICE);
}
- public void cancelAllNotifications(String pkg)
- {
- cancelAllNotificationsInt(pkg, 0);
+ public void cancelAllNotifications(String pkg) {
+ checkIncomingCall(pkg);
+
+ // Calling from user space, don't allow the canceling of actively
+ // running foreground services.
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
}
- public void cancelAll() {
+ void checkIncomingCall(String pkg) {
+ int uid = Binder.getCallingUid();
+ if (uid == Process.SYSTEM_UID || uid == 0) {
+ return;
+ }
+ try {
+ ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
+ pkg, 0);
+ if (ai.uid != uid) {
+ throw new SecurityException("Calling uid " + uid + " gave package"
+ + pkg + " which is owned by uid " + ai.uid);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException("Unknown package " + pkg);
+ }
+ }
+
+ void cancelAll() {
synchronized (mNotificationList) {
final int N = mNotificationList.size();
for (int i=N-1; i>=0; i--) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index aac13b6..2f4d716 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5065,6 +5065,15 @@
pw.println("Settings parse messages:");
pw.println(mSettings.mReadMessages.toString());
}
+
+ synchronized (mProviders) {
+ pw.println(" ");
+ pw.println("Registered ContentProviders:");
+ for (PackageParser.Provider p : mProviders.values()) {
+ pw.println(" ["); pw.println(p.info.authority); pw.println("]: ");
+ pw.println(p.toString());
+ }
+ }
}
static final class BasePermission {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 447e9fa..1249289 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2054,7 +2054,15 @@
if (event.values[0] == 0.0) {
goToSleep(milliseconds);
} else {
- userActivity(milliseconds, false);
+ // proximity sensor negative events user activity.
+ // temporarily set mUserActivityAllowed to true so this will work
+ // even when the keyguard is on.
+ synchronized (mLocks) {
+ boolean savedActivityAllowed = mUserActivityAllowed;
+ mUserActivityAllowed = true;
+ userActivity(milliseconds, false);
+ mUserActivityAllowed = savedActivityAllowed;
+ }
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ad8e8921..98f35f4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,7 +36,7 @@
import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
-import android.server.BluetoothDeviceService;
+import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
@@ -85,12 +85,14 @@
HardwareService hardware = null;
PowerManagerService power = null;
BatteryService battery = null;
+ ConnectivityService connectivity = null;
IPackageManager pm = null;
Context context = null;
WindowManagerService wm = null;
- BluetoothDeviceService bluetooth = null;
+ BluetoothService bluetooth = null;
BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
+ DockObserver dock = null;
// Critical services...
try {
@@ -174,9 +176,9 @@
ServiceManager.addService(Context.BLUETOOTH_SERVICE, null);
} else {
Log.i(TAG, "Starting Bluetooth Service.");
- bluetooth = new BluetoothDeviceService(context);
- bluetooth.init();
+ bluetooth = new BluetoothService(context);
ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth);
+ bluetooth.initAfterRegistration();
bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
@@ -231,8 +233,8 @@
try {
Log.i(TAG, "Starting Connectivity Service.");
- ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
- ConnectivityService.getInstance(context));
+ connectivity = ConnectivityService.getInstance(context);
+ ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Connectivity Service", e);
}
@@ -325,6 +327,14 @@
}
try {
+ Log.i(TAG, "Starting DockObserver");
+ // Listen for dock station changes
+ dock = new DockObserver(context);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting DockObserver", e);
+ }
+
+ try {
Log.i(TAG, "Starting Backup Service");
ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
} catch (Throwable e) {
@@ -384,7 +394,8 @@
}
if (wallpaper != null) wallpaper.systemReady();
- battery.systemReady();
+ if (battery != null) battery.systemReady();
+ if (connectivity != null) connectivity.systemReady();
Watchdog.getInstance().start();
Looper.loop();
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 7379b5d..170a9f8 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -535,9 +535,12 @@
intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
}
intent.putExtra(Phone.DATA_APN_KEY, apn);
- String types = apnTypes[0];
- for (int i = 1; i < apnTypes.length; i++) {
- types = types+","+apnTypes[i];
+ String types = new String("");
+ if (apnTypes.length > 0) {
+ types = apnTypes[0];
+ for (int i = 1; i < apnTypes.length; i++) {
+ types = types+","+apnTypes[i];
+ }
}
intent.putExtra(Phone.DATA_APN_TYPES_KEY, types);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 0a31396..3c62aa0 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -65,7 +65,7 @@
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
Object mLock = new Object();
@@ -327,6 +327,8 @@
// The default component is our static image wallpaper.
realName = new ComponentName("android",
ImageWallpaper.class.getName());
+ //clearWallpaperComponentLocked();
+ //return;
}
ServiceInfo si = mContext.getPackageManager().getServiceInfo(realName,
PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
@@ -390,13 +392,21 @@
}
}
mContext.unbindService(mWallpaperConnection);
+ try {
+ if (DEBUG) Log.v(TAG, "Removing window token: "
+ + mWallpaperConnection.mToken);
+ mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+ } catch (RemoteException e) {
+ }
mWallpaperConnection = null;
}
}
void attachServiceLocked(WallpaperConnection conn) {
try {
- conn.mService.attach(conn, conn.mToken, mWidth, mHeight);
+ conn.mService.attach(conn, conn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER, false,
+ mWidth, mHeight);
} catch (RemoteException e) {
Log.w(TAG, "Failed attaching wallpaper; clearing", e);
bindWallpaperComponentLocked(null);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index fae987a..2dc747e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1209,8 +1209,9 @@
ssid = "";
}
- // bssid is the hash key
- scanResult = mScanResultCache.get(bssid);
+ // bssid + ssid is the hash key
+ String key = bssid + ssid;
+ scanResult = mScanResultCache.get(key);
if (scanResult != null) {
scanResult.level = level;
scanResult.SSID = ssid;
@@ -1222,7 +1223,7 @@
scanResult =
new ScanResult(
ssid, bssid, flags, level, frequency);
- mScanResultCache.put(bssid, scanResult);
+ mScanResultCache.put(key, scanResult);
}
}
} else {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ac80071..1384ede 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -139,6 +139,7 @@
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
+ static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean MEASURE_LATENCY = false;
static private LatencyTimer lt;
@@ -404,6 +405,12 @@
// If non-null, this is the currently visible window that is associated
// with the wallpaper.
WindowState mWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the lower one in Z-order.
+ WindowState mLowerWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the higher one in Z-order.
+ WindowState mUpperWallpaperTarget = null;
int mWallpaperAnimLayerAdjustment;
AppWindowToken mFocusedApp = null;
@@ -1177,55 +1184,191 @@
boolean adjustWallpaperWindowsLocked() {
boolean changed = false;
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
// First find top-most window that has asked to be on top of the
// wallpaper; all wallpapers go behind it.
final ArrayList localmWindows = mWindows;
int N = localmWindows.size();
WindowState w = null;
+ WindowState foundW = null;
+ int foundI = 0;
int i = N;
- boolean visible = false;
while (i > 0) {
i--;
w = (WindowState)localmWindows.get(i);
- if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()) {
- visible = true;
+ if (w.mAppToken != null) {
+ // If this window's app token is hidden and not animating,
+ // it is of no interest to us.
+ if (w.mAppToken.hidden && w.mAppToken.animation == null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Skipping hidden or animating token: " + w);
+ continue;
+ }
+ // If this window's app token is ot fullscreen, also irrelevant.
+ if (!w.mAppToken.appFullscreen) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Skipping non-fullscreen token: " + w);
+ continue;
+ }
+ }
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay="
+ + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending
+ + " commitdrawpending=" + w.mCommitDrawPending);
+ if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
+ && !w.mDrawPending && !w.mCommitDrawPending) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Found wallpaper activity: #" + i + "=" + w);
+ foundW = w;
+ foundI = i;
+ if (w == mWallpaperTarget && w.mAppToken != null
+ && w.mAppToken.animation != null) {
+ // The current wallpaper target is animating, so we'll
+ // look behind it for another possible target and figure
+ // out what is going on below.
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w
+ + ": token animating, looking behind.");
+ continue;
+ }
break;
}
}
- if (!visible) w = null;
- //if (mWallpaperTarget != w) {
- // Log.v(TAG, "New wallpaper target: " + w);
- //}
- mWallpaperTarget = w;
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ // If we are currently waiting for an app transition, and either
+ // the current target or the next target are involved with it,
+ // then hold off on doing anything with the wallpaper.
+ // Note that we are checking here for just whether the target
+ // is part of an app token... which is potentially overly aggressive
+ // (the app token may not be involved in the transition), but good
+ // enough (we'll just wait until whatever transition is pending
+ // executes).
+ if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Wallpaper not changing: waiting for app anim in current target");
+ return false;
+ }
+ if (foundW != null && foundW.mAppToken != null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Wallpaper not changing: waiting for app anim in found target");
+ return false;
+ }
+ }
+ if (mWallpaperTarget != foundW) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New wallpaper target: " + foundW
+ + " oldTarget: " + mWallpaperTarget);
+ }
+
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+
+ WindowState oldW = mWallpaperTarget;
+ mWallpaperTarget = foundW;
+
+ // Now what is happening... if the current and new targets are
+ // animating, then we are in our super special mode!
+ if (foundW != null && foundW.mAppToken != null && oldW != null
+ && oldW.mAppToken != null) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New animation: " + foundW.mAppToken.animation
+ + " old animation: " + oldW.mAppToken.animation);
+ }
+ if (foundW.mAppToken.animation != null
+ && oldW.mAppToken.animation != null) {
+ int oldI = localmWindows.indexOf(oldW);
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New i: " + foundI + " old i: " + oldI);
+ }
+ if (oldI >= 0) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Animating wallpapers: old#" + oldI
+ + "=" + oldW + "; new#" + foundI
+ + "=" + foundW);
+ }
+
+ // Set the new target correctly.
+ if (foundW.mAppToken.hiddenRequested) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Old wallpaper still the target.");
+ }
+ mWallpaperTarget = oldW;
+ }
+
+ // Now set the upper and lower wallpaper targets
+ // correctly, and make sure that we are positioning
+ // the wallpaper below the lower.
+ if (foundI > oldI) {
+ // The new target is on top of the old one.
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Found target above old target.");
+ }
+ mUpperWallpaperTarget = foundW;
+ mLowerWallpaperTarget = oldW;
+ foundW = oldW;
+ foundI = oldI;
+ } else {
+ // The new target is below the old one.
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Found target below old target.");
+ }
+ mUpperWallpaperTarget = oldW;
+ mLowerWallpaperTarget = foundW;
+ }
+ }
+ }
+ }
+
+ } else {
+ // Is it time to stop animating?
+ if (mLowerWallpaperTarget == null
+ || mLowerWallpaperTarget.mAppToken.animation == null
+ || mUpperWallpaperTarget == null
+ || mUpperWallpaperTarget.mAppToken.animation == null) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "No longer animating wallpaper targets!");
+ }
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+ }
+ }
+
+ boolean visible = foundW != null;
if (visible) {
- mWallpaperAnimLayerAdjustment = w.mAppToken != null
- ? w.mAppToken.animLayerAdjustment : 0;
+ // The window is visible to the compositor... but is it visible
+ // to the user? That is what the wallpaper cares about.
+ visible = !foundW.mObscured;
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper visibility: " + visible);
+
+ // If the wallpaper target is animating, we may need to copy
+ // its layer adjustment. Only do this if we are not transfering
+ // between two wallpaper targets.
+ mWallpaperAnimLayerAdjustment =
+ (mLowerWallpaperTarget == null && foundW.mAppToken != null)
+ ? foundW.mAppToken.animLayerAdjustment : 0;
// Now w is the window we are supposed to be behind... but we
// need to be sure to also be behind any of its attached windows,
// AND any starting window associated with it.
- while (i > 0) {
- WindowState wb = (WindowState)localmWindows.get(i-1);
- if (wb.mAttachedWindow != w &&
+ while (foundI > 0) {
+ WindowState wb = (WindowState)localmWindows.get(foundI-1);
+ if (wb.mAttachedWindow != foundW &&
(wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
- wb.mToken != w.mToken)) {
+ wb.mToken != foundW.mToken)) {
// This window is not related to the previous one in any
// interesting way, so stop here.
break;
}
- w = wb;
- i--;
+ foundW = wb;
+ foundI--;
}
}
// Okay i is the position immediately above the wallpaper. Look at
// what is below it for later.
- w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
-
- final int dw = mDisplay.getWidth();
- final int dh = mDisplay.getHeight();
+ foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
// Start stepping backwards from here, ensuring that our wallpaper windows
// are correctly placed.
@@ -1239,7 +1382,8 @@
WindowState wallpaper = token.windows.get(curWallpaperIndex);
if (visible) {
- updateWallpaperOffsetLocked(mWallpaperTarget, wallpaper, dw, dh);
+ updateWallpaperOffsetLocked(mWallpaperTarget,
+ wallpaper, dw, dh);
}
// First, make sure the client has the current visibility
@@ -1247,7 +1391,7 @@
if (wallpaper.mWallpaperVisible != visible) {
wallpaper.mWallpaperVisible = visible;
try {
- if (DEBUG_VISIBILITY) Log.v(TAG,
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
"Setting visibility of wallpaper " + wallpaper
+ ": " + visible);
wallpaper.mClient.dispatchAppVisibility(visible);
@@ -1256,14 +1400,15 @@
}
wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
- if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
- + " anim layer: " + wallpaper.mAnimLayer);
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
// First, if this window is at the current index, then all
// is well.
- if (wallpaper == w) {
- i--;
- w = i > 0 ? (WindowState)localmWindows.get(i-1) : null;
+ if (wallpaper == foundW) {
+ foundI--;
+ foundW = foundI > 0
+ ? (WindowState)localmWindows.get(foundI-1) : null;
continue;
}
@@ -1273,13 +1418,16 @@
int oldIndex = localmWindows.indexOf(wallpaper);
if (oldIndex >= 0) {
localmWindows.remove(oldIndex);
- if (oldIndex < i) {
- i--;
+ if (oldIndex < foundI) {
+ foundI--;
}
}
// Now stick it in.
- localmWindows.add(i, wallpaper);
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+ + " from " + oldIndex + " to " + foundI);
+
+ localmWindows.add(foundI, wallpaper);
changed = true;
}
}
@@ -1288,7 +1436,8 @@
}
void setWallpaperAnimLayerAdjustmentLocked(int adj) {
- if (DEBUG_LAYERS) Log.v(TAG, "Setting wallpaper layer adj to " + adj);
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting wallpaper layer adj to " + adj);
mWallpaperAnimLayerAdjustment = adj;
int curTokenIndex = mWallpaperTokens.size();
while (curTokenIndex > 0) {
@@ -1299,8 +1448,8 @@
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
wallpaper.mAnimLayer = wallpaper.mLayer + adj;
- if (DEBUG_LAYERS) Log.v(TAG, "Wallpaper win " + wallpaper
- + " anim layer: " + wallpaper.mAnimLayer);
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
}
}
}
@@ -1308,28 +1457,42 @@
boolean updateWallpaperOffsetLocked(WindowState target,
WindowState wallpaperWin, int dw, int dh) {
boolean changed = false;
+ boolean rawChanged = false;
if (target.mWallpaperX >= 0) {
int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
int offset = availw > 0 ? -(int)(availw*target.mWallpaperX+.5f) : 0;
changed = wallpaperWin.mXOffset != offset;
if (changed) {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ + wallpaperWin + " x: " + offset);
wallpaperWin.mXOffset = offset;
}
+ if (wallpaperWin.mWallpaperX != target.mWallpaperX) {
+ wallpaperWin.mWallpaperX = target.mWallpaperX;
+ rawChanged = true;
+ }
}
+
if (target.mWallpaperY >= 0) {
int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
int offset = availh > 0 ? -(int)(availh*target.mWallpaperY+.5f) : 0;
if (wallpaperWin.mYOffset != offset) {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ + wallpaperWin + " y: " + offset);
changed = true;
wallpaperWin.mYOffset = offset;
}
+ if (wallpaperWin.mWallpaperY != target.mWallpaperY) {
+ wallpaperWin.mWallpaperY = target.mWallpaperY;
+ rawChanged = true;
+ }
}
- if (wallpaperWin.mWallpaperX != target.mWallpaperX
- || wallpaperWin.mWallpaperY != target.mWallpaperY) {
- wallpaperWin.mWallpaperX = target.mWallpaperX;
- wallpaperWin.mWallpaperY = target.mWallpaperY;
+ if (rawChanged) {
try {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
+ + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ + " y=" + wallpaperWin.mWallpaperY);
wallpaperWin.mClient.dispatchWallpaperOffsets(
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
} catch (RemoteException e) {
@@ -1366,6 +1529,65 @@
return changed;
}
+ void updateWallpaperVisibilityLocked() {
+ final boolean visible = mWallpaperTarget != null
+ && !mWallpaperTarget.mObscured;
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if (visible) {
+ updateWallpaperOffsetLocked(mWallpaperTarget,
+ wallpaper, dw, dh);
+ }
+
+ if (wallpaper.mWallpaperVisible != visible) {
+ wallpaper.mWallpaperVisible = visible;
+ try {
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting visibility of wallpaper " + wallpaper
+ + ": " + visible);
+ wallpaper.mClient.dispatchAppVisibility(visible);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
+ void sendPointerToWallpaperLocked(WindowState srcWin,
+ MotionEvent pointer, long eventTime) {
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if ((wallpaper.mAttrs.flags &
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ continue;
+ }
+ try {
+ MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
+ ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
+ srcWin.mFrame.top-wallpaper.mFrame.top);
+ wallpaper.mClient.dispatchPointer(ev, eventTime, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure sending pointer to wallpaper", e);
+ }
+ }
+ }
+ }
+
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets) {
@@ -1654,6 +1876,8 @@
}
private void removeWindowInnerLocked(Session session, WindowState win) {
+ mKeyWaiter.finishedKey(session, win.mClient, true,
+ KeyWaiter.RETURN_NOTHING);
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
@@ -1675,11 +1899,6 @@
mInputMethodDialogs.remove(win);
}
- if (win.mAttrs.type == TYPE_WALLPAPER ||
- (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
- adjustWallpaperWindowsLocked();
- }
-
final WindowToken token = win.mToken;
final AppWindowToken atoken = win.mAppToken;
token.windows.remove(win);
@@ -1717,6 +1936,11 @@
}
}
+ if (win.mAttrs.type == TYPE_WALLPAPER ||
+ (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
+
if (!mInLayout) {
assignLayersLocked();
mLayoutNeeded = true;
@@ -2157,6 +2381,16 @@
? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
: com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
break;
+ case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseExitAnimation;
+ break;
}
a = loadAnimation(lp, animAttr);
if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
@@ -4320,7 +4554,7 @@
final Rect frame = out.mFrame;
oev.offsetLocation(-(float)frame.left, -(float)frame.top);
try {
- out.mClient.dispatchPointer(oev, eventTime);
+ out.mClient.dispatchPointer(oev, eventTime, false);
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
}
@@ -4333,6 +4567,12 @@
final Rect frame = target.mFrame;
ev.offsetLocation(-(float)frame.left, -(float)frame.top);
mKeyWaiter.bindTargetWindowLocked(target);
+
+ // If we are on top of the wallpaper, then the wallpaper also
+ // gets to see this movement.
+ if (mWallpaperTarget == target) {
+ sendPointerToWallpaperLocked(target, ev, eventTime);
+ }
}
}
@@ -4347,7 +4587,7 @@
lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
}
- target.mClient.dispatchPointer(ev, eventTime);
+ target.mClient.dispatchPointer(ev, eventTime, true);
if (MEASURE_LATENCY) {
lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
@@ -4423,7 +4663,7 @@
}
try {
- focus.mClient.dispatchTrackball(ev, eventTime);
+ focus.mClient.dispatchTrackball(ev, eventTime, true);
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
@@ -5198,14 +5438,16 @@
return null;
}
+ MotionEvent res = null;
+ QueuedEvent qev = null;
+ WindowState win = null;
+
synchronized (this) {
if (DEBUG_INPUT) Log.v(
TAG, "finishedKey: client=" + client.asBinder()
+ ", force=" + force + ", last=" + mLastBinder
+ " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
- QueuedEvent qev = null;
- WindowState win = null;
if (returnWhat == RETURN_PENDING_POINTER) {
qev = session.mPendingPointerMove;
win = session.mPendingPointerWindow;
@@ -5235,17 +5477,25 @@
}
if (qev != null) {
- MotionEvent res = (MotionEvent)qev.event;
+ res = (MotionEvent)qev.event;
if (DEBUG_INPUT) Log.v(TAG,
"Returning pending motion: " + res);
mQueue.recycleEvent(qev);
if (win != null && returnWhat == RETURN_PENDING_POINTER) {
res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
}
- return res;
}
- return null;
}
+
+ if (res != null && returnWhat == RETURN_PENDING_POINTER) {
+ synchronized (mWindowMap) {
+ if (mWallpaperTarget == win) {
+ sendPointerToWallpaperLocked(win, res, res.getEventTime());
+ }
+ }
+ }
+
+ return res;
}
void tickle() {
@@ -5997,6 +6247,7 @@
int mAnimLayer;
int mLastLayer;
boolean mHaveFrame;
+ boolean mObscured;
WindowState mNextOutsideTouch;
@@ -6254,6 +6505,8 @@
visible.set(vf);
final Rect frame = mFrame;
+ final int fw = frame.width();
+ final int fh = frame.height();
//System.out.println("In: w=" + w + " h=" + h + " container=" +
// container + " x=" + mAttrs.x + " y=" + mAttrs.y);
@@ -6290,6 +6543,12 @@
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
+ if (mIsWallpaper && (fw != frame.width() || fh != frame.height())
+ && mWallpaperTarget != null) {
+ updateWallpaperOffsetLocked(mWallpaperTarget, this,
+ mDisplay.getWidth(), mDisplay.getHeight());
+ }
+
if (localLOGV) {
//if ("com.google.android.youtube".equals(mAttrs.packageName)
// && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
@@ -6438,7 +6697,8 @@
Surface.openTransaction();
try {
try {
- mSurface.setPosition(mFrame.left, mFrame.top);
+ mSurface.setPosition(mFrame.left + mXOffset,
+ mFrame.top + mYOffset);
mSurface.setLayer(mAnimLayer);
mSurface.hide();
if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
@@ -6473,11 +6733,14 @@
mAppToken.startingDisplayed = false;
}
- if (localLOGV) Log.v(
- TAG, "Window " + this
- + " destroying surface " + mSurface + ", session " + mSession);
if (mSurface != null) {
try {
+ if (DEBUG_VISIBILITY) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ Log.w(TAG, "Window " + this + " destroying surface "
+ + mSurface + ", session " + mSession, e);
+ }
if (SHOW_TRANSACTIONS) {
RuntimeException ex = new RuntimeException();
ex.fillInStackTrace();
@@ -6626,7 +6889,7 @@
}
mHasLocalTransformation = false;
if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
- && mAppToken.hasTransformation) {
+ && mAppToken.animation != null) {
// When our app token is animating, we kind-of pretend like
// we are as well. Note the mLocalAnimating mAnimationIsEntrance
// part of this check means that we will only do this if
@@ -6759,7 +7022,8 @@
// Wallpapers are animated based on the "real" window they
// are currently targeting.
- if (mAttrs.type == TYPE_WALLPAPER && mWallpaperTarget != null) {
+ if (mAttrs.type == TYPE_WALLPAPER && mLowerWallpaperTarget == null
+ && mWallpaperTarget != null) {
if (mWallpaperTarget.mHasLocalTransformation) {
attachedTransformation = mWallpaperTarget.mTransformation;
}
@@ -6767,6 +7031,12 @@
mWallpaperTarget.mAppToken.hasTransformation) {
appTransformation = mWallpaperTarget.mAppToken.transformation;
}
+ if (DEBUG_WALLPAPER && attachedTransformation != null) {
+ Log.v(TAG, "WP target attached xform: " + attachedTransformation);
+ }
+ if (DEBUG_WALLPAPER && appTransformation != null) {
+ Log.v(TAG, "WP target app xform: " + appTransformation);
+ }
}
if (selfTransformation || attachedTransformation != null
@@ -6919,7 +7189,8 @@
final boolean animating = atoken != null
? (atoken.animation != null) : false;
return mSurface != null && mPolicyVisibility && !mDestroying
- && ((!mAttachedHidden && !mRootToken.hidden)
+ && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
+ && !mRootToken.hidden)
|| mAnimation != null || animating);
}
@@ -7119,7 +7390,8 @@
pw.print(prefix); pw.print("mViewVisibility=0x");
pw.print(Integer.toHexString(mViewVisibility));
pw.print(" mLastHidden="); pw.print(mLastHidden);
- pw.print(" mHaveFrame="); pw.println(mHaveFrame);
+ pw.print(" mHaveFrame="); pw.print(mHaveFrame);
+ pw.print(" mObscured="); pw.println(mObscured);
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
pw.print(prefix); pw.print("mPolicyVisibility=");
pw.print(mPolicyVisibility);
@@ -7388,7 +7660,7 @@
if (w == mInputMethodTarget) {
setInputMethodAnimLayerAdjustment(adj);
}
- if (w == mWallpaperTarget) {
+ if (w == mWallpaperTarget && mLowerWallpaperTarget == null) {
setWallpaperAnimLayerAdjustmentLocked(adj);
}
}
@@ -7428,7 +7700,7 @@
if (animation == sDummyAnimation) {
// This guy is going to animate, but not yet. For now count
- // it is not animating for purposes of scheduling transactions;
+ // it as not animating for purposes of scheduling transactions;
// when it is really time to animate, this will be set to
// a real animation and the next call will execute normally.
return false;
@@ -7568,6 +7840,7 @@
pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
}
pw.print(prefix); pw.print("groupId="); pw.print(groupId);
+ pw.print(" appFullscreen="); pw.println(appFullscreen);
pw.print(" requestedOrientation="); pw.println(requestedOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
pw.print(" clientHidden="); pw.print(clientHidden);
@@ -8141,7 +8414,8 @@
for (i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.mBaseLayer == curBaseLayer || w.mIsFloatingLayer) {
+ if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
+ || (i > 0 && w.mIsWallpaper)) {
curLayer += WINDOW_LAYER_MULTIPLIER;
w.mLayer = curLayer;
} else {
@@ -8512,6 +8786,59 @@
mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+ adjustWallpaperWindowsLocked();
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "New wallpaper target=" + mWallpaperTarget
+ + ", lower target=" + mLowerWallpaperTarget
+ + ", upper target=" + mUpperWallpaperTarget);
+ if (mLowerWallpaperTarget != null) {
+ // Need to determine if both the closing and
+ // opening app token sets are wallpaper targets,
+ // in which case special animations are needed
+ // (since the wallpaper needs to stay static
+ // behind them).
+ int found = 0;
+ NN = mOpeningApps.size();
+ for (i=0; i<NN; i++) {
+ AppWindowToken wtoken = mOpeningApps.get(i);
+ if (mLowerWallpaperTarget.mAppToken == wtoken) {
+ found |= 1;
+ }
+ if (mUpperWallpaperTarget.mAppToken == wtoken) {
+ found |= 1;
+ }
+ }
+ NN = mClosingApps.size();
+ for (i=0; i<NN; i++) {
+ AppWindowToken wtoken = mClosingApps.get(i);
+ if (mLowerWallpaperTarget.mAppToken == wtoken) {
+ found |= 2;
+ }
+ if (mUpperWallpaperTarget.mAppToken == wtoken) {
+ found |= 2;
+ }
+ }
+
+ if (found == 3) {
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "Wallpaper animation!");
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+ case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+ case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+ transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN;
+ break;
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+ case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
+ case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
+ transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE;
+ break;
+ }
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "New transit: " + transit);
+ }
+ }
+
// We need to figure out which animation to use...
WindowManager.LayoutParams lp = findAnimations(mAppTokens,
mOpeningApps, mClosingApps);
@@ -8523,6 +8850,7 @@
"Now opening app" + wtoken);
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
+ wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, true, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.showAllWindowsLocked();
@@ -8533,6 +8861,7 @@
if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
"Now closing app" + wtoken);
wtoken.inPendingTransaction = false;
+ wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, false, transit, false);
wtoken.updateReportedVisibilityLocked();
// Force the allDrawn flag, because we want to start
@@ -8547,7 +8876,6 @@
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
mLayoutNeeded = true;
- adjustWallpaperWindowsLocked();
if (!moveInputMethodWindowsIfNeededLocked(true)) {
assignLayersLocked();
}
@@ -8822,8 +9150,10 @@
focusDisplayed = true;
}
+ final boolean obscuredChanged = w.mObscured != obscured;
+
// Update effect.
- if (!obscured) {
+ if (!(w.mObscured=obscured)) {
if (w.mSurface != null) {
if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
holdScreen = w.mSession;
@@ -8923,6 +9253,13 @@
}
}
}
+
+ if (obscuredChanged && mWallpaperTarget == w) {
+ // This is the wallpaper target and its obscured state
+ // changed... make sure the current wallaper's visibility
+ // has been updated accordingly.
+ updateWallpaperVisibilityLocked();
+ }
}
if (backgroundFillerShown == false && mBackgroundFillerShown) {
@@ -8989,6 +9326,7 @@
}
// Destroy the surface of any windows that are no longer visible.
+ boolean wallpaperDestroyed = false;
i = mDestroySurface.size();
if (i > 0) {
do {
@@ -8998,6 +9336,9 @@
if (mInputMethodWindow == win) {
mInputMethodWindow = null;
}
+ if (win == mWallpaperTarget) {
+ wallpaperDestroyed = true;
+ }
win.destroySurfaceLocked();
} while (i > 0);
mDestroySurface.clear();
@@ -9026,7 +9367,12 @@
if (focusDisplayed) {
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
- if (animating) {
+ if (wallpaperDestroyed) {
+ wallpaperDestroyed = adjustWallpaperWindowsLocked();
+ }
+ if (wallpaperDestroyed) {
+ requestAnimationLocked(0);
+ } else if (animating) {
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
}
mQueue.setHoldScreenLocked(holdScreen != null);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c59c9cc3..23eb7c1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -39,8 +39,10 @@
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
import android.app.Instrumentation;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.ResultInfo;
+import android.app.Service;
import android.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -753,6 +755,8 @@
String mTopData;
boolean mSystemReady = false;
boolean mBooting = false;
+ boolean mWaitingUpdate = false;
+ boolean mDidUpdate = false;
Context mContext;
@@ -930,6 +934,7 @@
static final int RESUME_TOP_ACTIVITY_MSG = 19;
static final int PROC_START_TIMEOUT_MSG = 20;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
+ static final int KILL_APPLICATION_MSG = 22;
AlertDialog mUidAlert;
@@ -969,6 +974,8 @@
res.set(0);
}
}
+
+ ensureBootCompleted();
} break;
case SHOW_NOT_RESPONDING_MSG: {
synchronized (ActivityManagerService.this) {
@@ -989,13 +996,13 @@
proc.anrDialog = d;
}
- ensureScreenEnabled();
+ ensureBootCompleted();
} break;
case SHOW_FACTORY_ERROR_MSG: {
Dialog d = new FactoryErrorDialog(
mContext, msg.getData().getCharSequence("msg"));
d.show();
- enableScreenAfterBoot();
+ ensureBootCompleted();
} break;
case UPDATE_CONFIGURATION_MSG: {
final ContentResolver resolver = mContext.getContentResolver();
@@ -1159,6 +1166,14 @@
doPendingActivityLaunchesLocked(true);
}
}
+ case KILL_APPLICATION_MSG: {
+ synchronized (ActivityManagerService.this) {
+ int uid = msg.arg1;
+ boolean restart = (msg.arg2 == 1);
+ String pkg = (String) msg.obj;
+ uninstallPackageLocked(pkg, uid, restart);
+ }
+ } break;
}
}
};
@@ -1832,12 +1847,12 @@
}
startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent());
+ "activity", r.intent.getComponent(), false);
}
private final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
- String hostingType, ComponentName hostingName) {
+ String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
ProcessRecord app = getProcessRecordLocked(processName, info.uid);
// We don't have to do anything more if:
// (1) There is an existing application record; and
@@ -1890,7 +1905,8 @@
// If the system is not ready yet, then hold off on starting this
// process until it is.
if (!mSystemReady
- && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ && !isAllowedWhileBooting(info)
+ && !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
@@ -1901,6 +1917,10 @@
return (app.pid != 0) ? app : null;
}
+ boolean isAllowedWhileBooting(ApplicationInfo ai) {
+ return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
if (app.pid > 0 && app.pid != MY_PID) {
@@ -4810,7 +4830,12 @@
int callerUid = Binder.getCallingUid();
// Only the system server can kill an application
if (callerUid == Process.SYSTEM_UID) {
- uninstallPackageLocked(pkg, uid, false);
+ // Post an aysnc message to kill the application
+ Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
+ msg.arg1 = uid;
+ msg.arg2 = 0;
+ msg.obj = pkg;
+ mHandler.sendMessage(msg);
} else {
throw new SecurityException(callerUid + " cannot kill pkg: " +
pkg);
@@ -5069,8 +5094,13 @@
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- List providers = generateApplicationProvidersLocked(app);
+ boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
+ List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
+ if (!normalMode) {
+ Log.i(TAG, "Launching preboot mode app: " + app);
+ }
+
if (localLOGV) Log.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
@@ -5086,12 +5116,14 @@
mWaitForDebugger = mOrigWaitForDebugger;
}
}
+
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
}
+
ensurePackageDexOpt(app.instrumentationInfo != null
? app.instrumentationInfo.packageName
: app.info.packageName);
@@ -5102,7 +5134,8 @@
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
- isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
+ isRestrictedBackupMode || !normalMode,
+ mConfiguration, getCommonServicesLocked());
updateLRUListLocked(app, false);
app.lastRequestedGc = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -5268,6 +5301,8 @@
}
void enableScreenAfterBoot() {
+ EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
+ SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
}
@@ -5378,26 +5413,7 @@
}
if (booting) {
- // Ensure that any processes we had put on hold are now started
- // up.
- final int NP = mProcessesOnHold.size();
- if (NP > 0) {
- ArrayList<ProcessRecord> procs =
- new ArrayList<ProcessRecord>(mProcessesOnHold);
- for (int ip=0; ip<NP; ip++) {
- this.startProcessLocked(procs.get(ip), "on-hold", null);
- }
- }
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- // Tell anyone interested that we are done booting!
- synchronized (this) {
- broadcastIntentLocked(null, null,
- new Intent(Intent.ACTION_BOOT_COMPLETED, null),
- null, null, 0, null, null,
- android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
- false, false, MY_PID, Process.SYSTEM_UID);
- }
- }
+ finishBooting();
}
trimApplications();
@@ -5405,22 +5421,48 @@
//mWindowManager.dump();
if (enableScreen) {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
enableScreenAfterBoot();
}
}
- final void ensureScreenEnabled() {
+ final void finishBooting() {
+ // Ensure that any processes we had put on hold are now started
+ // up.
+ final int NP = mProcessesOnHold.size();
+ if (NP > 0) {
+ ArrayList<ProcessRecord> procs =
+ new ArrayList<ProcessRecord>(mProcessesOnHold);
+ for (int ip=0; ip<NP; ip++) {
+ this.startProcessLocked(procs.get(ip), "on-hold", null);
+ }
+ }
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ // Tell anyone interested that we are done booting!
+ synchronized (this) {
+ broadcastIntentLocked(null, null,
+ new Intent(Intent.ACTION_BOOT_COMPLETED, null),
+ null, null, 0, null, null,
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
+ false, false, MY_PID, Process.SYSTEM_UID);
+ }
+ }
+ }
+
+ final void ensureBootCompleted() {
+ boolean booting;
boolean enableScreen;
synchronized (this) {
+ booting = mBooting;
+ mBooting = false;
enableScreen = !mBooted;
mBooted = true;
}
+
+ if (booting) {
+ finishBooting();
+ }
if (enableScreen) {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
enableScreenAfterBoot();
}
}
@@ -5572,6 +5614,13 @@
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ if (type == INTENT_SENDER_BROADCAST) {
+ if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+ throw new IllegalArgumentException(
+ "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ }
+ }
+
synchronized(this) {
int callingUid = Binder.getCallingUid();
try {
@@ -7382,7 +7431,7 @@
ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
- cpi.name));
+ cpi.name), false);
if (proc == null) {
Log.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
@@ -8109,17 +8158,93 @@
if (mSystemReady) {
return;
}
+
+ // Check to see if there are any update receivers to run.
+ if (!mDidUpdate) {
+ if (mWaitingUpdate) {
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+ List<ResolveInfo> ris = null;
+ try {
+ ris = ActivityThread.getPackageManager().queryIntentReceivers(
+ intent, null, 0);
+ } catch (RemoteException e) {
+ }
+ if (ris != null) {
+ for (int i=ris.size()-1; i>=0; i--) {
+ if ((ris.get(i).activityInfo.applicationInfo.flags
+ &ApplicationInfo.FLAG_SYSTEM) == 0) {
+ ris.remove(i);
+ }
+ }
+ intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+ for (int i=0; i<ris.size(); i++) {
+ ActivityInfo ai = ris.get(i).activityInfo;
+ intent.setComponent(new ComponentName(ai.packageName, ai.name));
+ IIntentReceiver finisher = null;
+ if (i == 0) {
+ finisher = new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered)
+ throws RemoteException {
+ synchronized (ActivityManagerService.this) {
+ mDidUpdate = true;
+ }
+ systemReady();
+ }
+ };
+ }
+ Log.i(TAG, "Sending system update to: " + intent.getComponent());
+ broadcastIntentLocked(null, null, intent, null, finisher,
+ 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
+ if (i == 0) {
+ mWaitingUpdate = true;
+ }
+ }
+ }
+ if (mWaitingUpdate) {
+ return;
+ }
+ mDidUpdate = true;
+ }
+
mSystemReady = true;
if (!mStartRunning) {
return;
}
}
+ ArrayList<ProcessRecord> procsToKill = null;
+ synchronized(mPidsSelfLocked) {
+ for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
+ ProcessRecord proc = mPidsSelfLocked.valueAt(i);
+ if (!isAllowedWhileBooting(proc.info)){
+ if (procsToKill == null) {
+ procsToKill = new ArrayList<ProcessRecord>();
+ }
+ procsToKill.add(proc);
+ }
+ }
+ }
+
+ if (procsToKill != null) {
+ synchronized(this) {
+ for (int i=procsToKill.size()-1; i>=0; i--) {
+ ProcessRecord proc = procsToKill.get(i);
+ Log.i(TAG, "Removing system update proc: " + proc);
+ removeProcessLocked(proc, true);
+ }
+ }
+ }
+
if (Config.LOGD) Log.d(TAG, "Start running!");
EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis());
synchronized(this) {
+ // Make sure we have no pre-ready processes sitting around.
+
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -8177,6 +8302,9 @@
}
}
+ // Start up initial activity.
+ mBooting = true;
+
try {
if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
Message msg = Message.obtain();
@@ -8186,8 +8314,6 @@
} catch (RemoteException e) {
}
- // Start up initial activity.
- mBooting = true;
resumeTopActivityLocked(null);
}
}
@@ -9370,7 +9496,9 @@
sr.app = null;
sr.executeNesting = 0;
mStoppingServices.remove(sr);
- if (sr.bindings.size() > 0) {
+
+ boolean hasClients = sr.bindings.size() > 0;
+ if (hasClients) {
Iterator<IntentBindRecord> bindings
= sr.bindings.values().iterator();
while (bindings.hasNext()) {
@@ -9391,7 +9519,20 @@
} else if (!allowRestart) {
bringDownServiceLocked(sr, true);
} else {
- scheduleServiceRestartLocked(sr);
+ boolean canceled = scheduleServiceRestartLocked(sr, true);
+
+ // Should the service remain running? Note that in the
+ // extreme case of so many attempts to deliver a command
+ // that it failed, that we also will stop it here.
+ if (sr.startRequested && (sr.stopIfKilled || canceled)) {
+ if (sr.pendingStarts.size() == 0) {
+ sr.startRequested = false;
+ if (!hasClients) {
+ // Whoops, no reason to restart!
+ bringDownServiceLocked(sr, true);
+ }
+ }
+ }
}
}
@@ -9830,35 +9971,55 @@
private final void sendServiceArgsLocked(ServiceRecord r,
boolean oomAdjusted) {
- final int N = r.startArgs.size();
+ final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
- final int BASEID = r.lastStartId - N + 1;
int i = 0;
while (i < N) {
try {
- Intent args = r.startArgs.get(i);
+ ServiceRecord.StartItem si = r.pendingStarts.get(i);
if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
- + r.name + " " + r.intent + " args=" + args);
+ + r.name + " " + r.intent + " args=" + si.intent);
+ if (si.intent == null && N > 0) {
+ // If somehow we got a dummy start at the front, then
+ // just drop it here.
+ i++;
+ continue;
+ }
bumpServiceExecutingLocked(r);
if (!oomAdjusted) {
oomAdjusted = true;
updateOomAdjLocked(r.app);
}
- r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
+ int flags = 0;
+ if (si.deliveryCount > 0) {
+ flags |= Service.START_FLAG_RETRY;
+ }
+ if (si.doneExecutingCount > 0) {
+ flags |= Service.START_FLAG_REDELIVERY;
+ }
+ r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
+ si.deliveredTime = SystemClock.uptimeMillis();
+ r.deliveredStarts.add(si);
+ si.deliveryCount++;
i++;
+ } catch (RemoteException e) {
+ // Remote process gone... we'll let the normal cleanup take
+ // care of this.
+ break;
} catch (Exception e) {
+ Log.w(TAG, "Unexpected exception", e);
break;
}
}
if (i == N) {
- r.startArgs.clear();
+ r.pendingStarts.clear();
} else {
while (i > 0) {
- r.startArgs.remove(0);
i--;
+ r.pendingStarts.remove(i);
}
}
}
@@ -9922,23 +10083,66 @@
}
ensurePackageDexOpt(r.serviceInfo.packageName);
app.thread.scheduleCreateService(r, r.serviceInfo);
+ r.postNotification();
created = true;
} finally {
if (!created) {
app.services.remove(r);
- scheduleServiceRestartLocked(r);
+ scheduleServiceRestartLocked(r, false);
}
}
requestServiceBindingsLocked(r);
+
+ // If the service is in the started state, and there are no
+ // pending arguments, then fake up one so its onStartCommand() will
+ // be called.
+ if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
+ r.lastStartId++;
+ if (r.lastStartId < 1) {
+ r.lastStartId = 1;
+ }
+ r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
+ }
+
sendServiceArgsLocked(r, true);
}
- private final void scheduleServiceRestartLocked(ServiceRecord r) {
+ private final boolean scheduleServiceRestartLocked(ServiceRecord r,
+ boolean allowCancel) {
+ boolean canceled = false;
+
+ long minDuration = SERVICE_RESTART_DURATION;
+ long resetTime = minDuration*2*2*2;
+
+ // Any delivered but not yet finished starts should be put back
+ // on the pending list.
+ final int N = r.deliveredStarts.size();
+ if (N > 0) {
+ for (int i=N-1; i>=0; i--) {
+ ServiceRecord.StartItem si = r.deliveredStarts.get(i);
+ if (si.intent == null) {
+ // We'll generate this again if needed.
+ } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
+ && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
+ r.pendingStarts.add(0, si);
+ long dur = SystemClock.uptimeMillis() - si.deliveredTime;
+ dur *= 2;
+ if (minDuration < dur) minDuration = dur;
+ if (resetTime < dur) resetTime = dur;
+ } else {
+ Log.w(TAG, "Canceling start item " + si.intent + " in service "
+ + r.name);
+ canceled = true;
+ }
+ }
+ r.deliveredStarts.clear();
+ }
+
r.totalRestartCount++;
if (r.restartDelay == 0) {
r.restartCount++;
- r.restartDelay = SERVICE_RESTART_DURATION;
+ r.restartDelay = minDuration;
} else {
// If it has been a "reasonably long time" since the service
// was started, then reset our restart duration back to
@@ -9946,16 +10150,21 @@
// on a service that just occasionally gets killed (which is
// a normal case, due to process being killed to reclaim memory).
long now = SystemClock.uptimeMillis();
- if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
+ if (now > (r.restartTime+resetTime)) {
r.restartCount = 1;
- r.restartDelay = SERVICE_RESTART_DURATION;
+ r.restartDelay = minDuration;
} else {
- r.restartDelay *= 2;
+ r.restartDelay *= 4;
+ if (r.restartDelay < minDuration) {
+ r.restartDelay = minDuration;
+ }
}
}
if (!mRestartingServices.contains(r)) {
mRestartingServices.add(r);
}
+ r.cancelNotification();
+
mHandler.removeCallbacks(r.restarter);
mHandler.postDelayed(r.restarter, r.restartDelay);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
@@ -9968,6 +10177,8 @@
msg.what = SERVICE_ERROR_MSG;
msg.obj = r;
mHandler.sendMessage(msg);
+
+ return canceled;
}
final void performServiceRestartLocked(ServiceRecord r) {
@@ -10027,7 +10238,7 @@
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (startProcessLocked(appName, r.appInfo, true, intentFlags,
- "service", r.name) == null) {
+ "service", r.name, false) == null) {
Log.w(TAG, "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
@@ -10124,13 +10335,21 @@
}
}
+ r.cancelNotification();
+ r.isForeground = false;
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+
+ // Clear start entries.
+ r.deliveredStarts.clear();
+ r.pendingStarts.clear();
+
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.app.thread != null) {
- updateServiceForegroundLocked(r.app, false);
try {
Log.i(TAG, "Stopping service: " + r.shortName);
bumpServiceExecutingLocked(r);
@@ -10142,6 +10361,7 @@
+ r.shortName, e);
serviceDoneExecutingLocked(r, true);
}
+ updateServiceForegroundLocked(r.app, false);
} else {
if (DEBUG_SERVICE) Log.v(
TAG, "Removed service that has no process: " + r.shortName);
@@ -10185,11 +10405,12 @@
+ r.shortName);
}
r.startRequested = true;
- r.startArgs.add(service);
+ r.callStart = false;
r.lastStartId++;
if (r.lastStartId < 1) {
r.lastStartId = 1;
}
+ r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
@@ -10257,6 +10478,7 @@
r.record.stats.stopRunningLocked();
}
r.record.startRequested = false;
+ r.record.callStart = false;
final long origId = Binder.clearCallingIdentity();
bringDownServiceLocked(r.record, false);
Binder.restoreCallingIdentity(origId);
@@ -10305,10 +10527,35 @@
if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token);
- if (r != null && (startId < 0 || r.lastStartId == startId)) {
+ if (r != null) {
+ if (startId >= 0) {
+ // Asked to only stop if done with all work. Note that
+ // to avoid leaks, we will take this as dropping all
+ // start items up to and including this one.
+ ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
+ if (si != null) {
+ while (r.deliveredStarts.size() > 0) {
+ if (r.deliveredStarts.remove(0) == si) {
+ break;
+ }
+ }
+ }
+
+ if (r.lastStartId != startId) {
+ return false;
+ }
+
+ if (r.deliveredStarts.size() > 0) {
+ Log.w(TAG, "stopServiceToken startId " + startId
+ + " is last, but have " + r.deliveredStarts.size()
+ + " remaining args");
+ }
+ }
+
synchronized (r.stats.getBatteryStats()) {
r.stats.stopRunningLocked();
r.startRequested = false;
+ r.callStart = false;
}
final long origId = Binder.clearCallingIdentity();
bringDownServiceLocked(r, false);
@@ -10320,20 +10567,45 @@
}
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) {
+ int id, Notification notification, boolean removeNotification) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
synchronized(this) {
ServiceRecord r = findServiceLocked(className, token);
if (r != null) {
- if (r.isForeground != isForeground) {
- final long origId = Binder.clearCallingIdentity();
- r.isForeground = isForeground;
+ if (id != 0) {
+ if (notification == null) {
+ throw new IllegalArgumentException("null notification");
+ }
+ if (r.foregroundId != id) {
+ r.cancelNotification();
+ r.foregroundId = id;
+ }
+ notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ r.foregroundNoti = notification;
+ r.isForeground = true;
+ r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
- Binder.restoreCallingIdentity(origId);
+ } else {
+ if (r.isForeground) {
+ r.isForeground = false;
+ if (r.app != null) {
+ updateServiceForegroundLocked(r.app, true);
+ }
+ }
+ if (removeNotification) {
+ r.cancelNotification();
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+ }
}
}
}
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
@@ -10627,7 +10899,7 @@
}
}
- public void serviceDoneExecuting(IBinder token) {
+ public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
@@ -10645,6 +10917,51 @@
return;
}
+ if (type == 1) {
+ // This is a call from a service start... take care of
+ // book-keeping.
+ r.callStart = true;
+ switch (res) {
+ case Service.START_STICKY_COMPATIBILITY:
+ case Service.START_STICKY: {
+ // We are done with the associated start arguments.
+ r.findDeliveredStart(startId, true);
+ // Don't stop if killed.
+ r.stopIfKilled = false;
+ break;
+ }
+ case Service.START_NOT_STICKY: {
+ // We are done with the associated start arguments.
+ r.findDeliveredStart(startId, true);
+ if (r.lastStartId == startId) {
+ // There is no more work, and this service
+ // doesn't want to hang around if killed.
+ r.stopIfKilled = true;
+ }
+ break;
+ }
+ case Service.START_REDELIVER_INTENT: {
+ // We'll keep this item until they explicitly
+ // call stop for it, but keep track of the fact
+ // that it was delivered.
+ ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
+ if (si != null) {
+ si.deliveryCount = 0;
+ si.doneExecutingCount++;
+ // Don't stop if killed.
+ r.stopIfKilled = true;
+ }
+ break;
+ }
+ default:
+ throw new IllegalArgumentException(
+ "Unknown service start result: " + res);
+ }
+ if (res == Service.START_STICKY_COMPATIBILITY) {
+ r.callStart = false;
+ }
+ }
+
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
@@ -10723,7 +11040,7 @@
ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
// startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0, "backup", hostingName);
+ false, 0, "backup", hostingName, false);
if (proc == null) {
Log.e(TAG, "Unable to start backup agent process " + r);
return false;
@@ -11260,10 +11577,11 @@
}
synchronized(this) {
+ int flags = intent.getFlags();
+
if (!mSystemReady) {
// if the caller really truly claims to know what they're doing, go
// ahead and allow the broadcast without launching any receivers
- int flags = intent.getFlags();
if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
intent = new Intent(intent);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -11274,6 +11592,11 @@
}
}
+ if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+ throw new IllegalArgumentException(
+ "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ }
+
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -11868,12 +12191,13 @@
// restart the application.
}
- // Not running -- get it started, and enqueue this history record
- // to be executed when the app comes up.
+ // Not running -- get it started, to be executed when the app comes up.
if ((r.curApp=startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
- "broadcast", r.curComponent)) == null) {
+ "broadcast", r.curComponent,
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
+ == null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Log.w(TAG, "Unable to launch app "
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index c834b34..ed0d534 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -260,6 +260,7 @@
enforceCallingPermission();
synchronized (mStats) {
mStats.noteBluetoothOnLocked();
+ mStats.setBtHeadset(new android.bluetooth.BluetoothHeadset(mContext, null));
}
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index fc93b69..afbf9c7 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -18,12 +18,16 @@
import com.android.internal.os.BatteryStatsImpl;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.SystemClock;
import java.io.PrintWriter;
@@ -60,13 +64,38 @@
final HashMap<IBinder, ConnectionRecord> connections
= new HashMap<IBinder, ConnectionRecord>();
// IBinder -> ConnectionRecord of all bound clients
- final List<Intent> startArgs = new ArrayList<Intent>();
+
+ // Maximum number of delivery attempts before giving up.
+ static final int MAX_DELIVERY_COUNT = 3;
+
+ // Maximum number of times it can fail during execution before giving up.
+ static final int MAX_DONE_EXECUTING_COUNT = 6;
+
+ static class StartItem {
+ final int id;
+ final Intent intent;
+ long deliveredTime;
+ int deliveryCount;
+ int doneExecutingCount;
+
+ StartItem(int _id, Intent _intent) {
+ id = _id;
+ intent = _intent;
+ }
+ }
+ final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
+ // start() arguments which been delivered.
+ final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
// start() arguments that haven't yet been delivered.
- ProcessRecord app; // where this service is running or null.
- boolean isForeground; // asked to run as a foreground service?
+ ProcessRecord app; // where this service is running or null.
+ boolean isForeground; // is service currently in foreground mode?
+ int foregroundId; // Notification ID of last foreground req.
+ Notification foregroundNoti; // Notification record of foreground state.
long lastActivity; // last time there was some activity on the service.
boolean startRequested; // someone explicitly called start?
+ boolean stopIfKilled; // last onStart() said to stop if service killed?
+ boolean callStart; // last onStart() has asked to alway be called on restart.
int lastStartId; // identifier of most recent start request.
int executeNesting; // number of outstanding operations keeping foreground.
long executingStart; // start time of last execute request.
@@ -79,6 +108,25 @@
String stringName; // caching of toString
+ void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
+ final int N = list.size();
+ for (int i=0; i<N; i++) {
+ StartItem si = list.get(i);
+ pw.print(prefix); pw.print("#"); pw.print(i);
+ pw.print(" id="); pw.print(si.id);
+ if (now != 0) pw.print(" dur="); pw.print(now-si.deliveredTime);
+ if (si.deliveryCount != 0) {
+ pw.print(" dc="); pw.print(si.deliveryCount);
+ }
+ if (si.doneExecutingCount != 0) {
+ pw.print(" dxc="); pw.print(si.doneExecutingCount);
+ }
+ pw.print(" ");
+ if (si.intent != null) pw.println(si.intent.toString());
+ else pw.println("null");
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(true, false));
@@ -92,20 +140,39 @@
if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir);
pw.print(" dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
- pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
- pw.print(" lastActivity="); pw.println(lastActivity);
- pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
- pw.print(" startId="); pw.print(lastStartId);
- pw.print(" executeNesting="); pw.print(executeNesting);
+ if (isForeground || foregroundId != 0) {
+ pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
+ pw.print(" foregroundId="); pw.print(foregroundId);
+ pw.print(" foregroundNoti="); pw.println(foregroundNoti);
+ }
+ pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity);
pw.print(" executingStart="); pw.print(executingStart);
- pw.print(" crashCount="); pw.println(crashCount);
- pw.print(prefix); pw.print("totalRestartCount="); pw.print(totalRestartCount);
- pw.print(" restartCount="); pw.print(restartCount);
- pw.print(" restartDelay="); pw.print(restartDelay);
- pw.print(" restartTime="); pw.print(restartTime);
- pw.print(" nextRestartTime="); pw.println(nextRestartTime);
+ pw.print(" restartTime="); pw.println(restartTime);
+ if (startRequested || lastStartId != 0) {
+ pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
+ pw.print(" stopIfKilled="); pw.print(stopIfKilled);
+ pw.print(" callStart="); pw.print(callStart);
+ pw.print(" lastStartId="); pw.println(lastStartId);
+ }
+ if (executeNesting != 0 || crashCount != 0 || restartCount != 0
+ || restartDelay != 0 || nextRestartTime != 0) {
+ pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
+ pw.print(" restartCount="); pw.print(restartCount);
+ pw.print(" restartDelay="); pw.print(restartDelay);
+ pw.print(" nextRestartTime="); pw.print(nextRestartTime);
+ pw.print(" crashCount="); pw.println(crashCount);
+ }
+ if (deliveredStarts.size() > 0) {
+ pw.print(prefix); pw.println("Delivered Starts:");
+ dumpStartList(pw, prefix, deliveredStarts, SystemClock.uptimeMillis());
+ }
+ if (pendingStarts.size() > 0) {
+ pw.print(prefix); pw.println("Pending Starts:");
+ dumpStartList(pw, prefix, pendingStarts, 0);
+ }
if (bindings.size() > 0) {
Iterator<IntentBindRecord> it = bindings.values().iterator();
+ pw.print(prefix); pw.println("Bindings:");
while (it.hasNext()) {
IntentBindRecord b = it.next();
pw.print(prefix); pw.print("* IntentBindRecord{");
@@ -166,6 +233,45 @@
restartTime = 0;
}
+ public StartItem findDeliveredStart(int id, boolean remove) {
+ final int N = deliveredStarts.size();
+ for (int i=0; i<N; i++) {
+ StartItem si = deliveredStarts.get(i);
+ if (si.id == id) {
+ if (remove) deliveredStarts.remove(i);
+ return si;
+ }
+ }
+
+ return null;
+ }
+
+ public void postNotification() {
+ if (foregroundId != 0 && foregroundNoti != null) {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm != null) {
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotification(packageName, foregroundId,
+ foregroundNoti, outId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ public void cancelNotification() {
+ if (foregroundId != 0) {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm != null) {
+ try {
+ inm.cancelNotification(packageName, foregroundId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
public String toString() {
if (stringName != null) {
return stringName;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index e71d3291..10680dd 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -18,7 +18,7 @@
import android.app.AlertDialog;
import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
@@ -105,11 +105,9 @@
// phone
private TelephonyManager mPhone;
private IBinder mPhoneIcon;
- private IBinder mPhoneEvdoIcon;
//***** Signal strength icons
private IconData mPhoneData;
- private IconData mPhoneEvdoData;
//GSM/UMTS
private static final int[] sSignalImages = new int[] {
com.android.internal.R.drawable.stat_sys_signal_0,
@@ -125,14 +123,6 @@
com.android.internal.R.drawable.stat_sys_r_signal_3,
com.android.internal.R.drawable.stat_sys_r_signal_4
};
- //CDMA
- private static final int[] sSignalImages_cdma = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_cdma_0,
- com.android.internal.R.drawable.stat_sys_signal_cdma_1,
- com.android.internal.R.drawable.stat_sys_signal_cdma_2,
- com.android.internal.R.drawable.stat_sys_signal_cdma_3,
- com.android.internal.R.drawable.stat_sys_signal_cdma_4
- };
private static final int[] sRoamingIndicatorImages_cdma = new int[] {
com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
// 1 is Standard Roaming Indicator OFF
@@ -232,14 +222,6 @@
// 128-255 Reserved
};
- // EVDO
- private static final int[] sSignalImages_evdo = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_evdo_0,
- com.android.internal.R.drawable.stat_sys_signal_evdo_1,
- com.android.internal.R.drawable.stat_sys_signal_evdo_2,
- com.android.internal.R.drawable.stat_sys_signal_evdo_3,
- com.android.internal.R.drawable.stat_sys_signal_evdo_4
- };
//***** Data connection icons
private int[] mDataIconList = sDataNetType_g;
@@ -262,20 +244,21 @@
com.android.internal.R.drawable.stat_sys_data_out_e,
com.android.internal.R.drawable.stat_sys_data_inandout_e,
};
- //CDMA
- private static final int[] sDataNetType_evdo = new int[] {
- com.android.internal.R.drawable.stat_sys_data_connected_evdo,
- com.android.internal.R.drawable.stat_sys_data_in_evdo,
- com.android.internal.R.drawable.stat_sys_data_out_evdo,
- com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
- com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
+ //3.5G
+ private static final int[] sDataNetType_h = new int[] {
+ com.android.internal.R.drawable.stat_sys_data_connected_h,
+ com.android.internal.R.drawable.stat_sys_data_in_h,
+ com.android.internal.R.drawable.stat_sys_data_out_h,
+ com.android.internal.R.drawable.stat_sys_data_inandout_h,
};
- private static final int[] sDataNetType_1xrtt = new int[] {
- com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
+
+ //CDMA
+ // Use 3G icons for EVDO data and 1x icons for 1XRTT data
+ private static final int[] sDataNetType_1x = new int[] {
+ com.android.internal.R.drawable.stat_sys_data_connected_1x,
+ com.android.internal.R.drawable.stat_sys_data_in_1x,
+ com.android.internal.R.drawable.stat_sys_data_out_1x,
+ com.android.internal.R.drawable.stat_sys_data_inandout_1x,
};
// Assume it's all good unless we hear otherwise. We don't always seem
@@ -430,12 +413,6 @@
null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
mPhoneIcon = service.addIcon(mPhoneData, null);
- // phone_evdo_signal
- mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal",
- null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0);
- mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null);
- service.setIconVisibility(mPhoneEvdoIcon, false);
-
// register for phone state notifications.
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
@@ -473,10 +450,10 @@
mBluetoothData = IconData.makeIcon("bluetooth",
null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
mBluetoothIcon = service.addIcon(mBluetoothData, null);
- BluetoothDevice bluetooth =
- (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (bluetooth != null) {
- mBluetoothEnabled = bluetooth.isEnabled();
+ BluetoothAdapter adapter =
+ (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (adapter != null) {
+ mBluetoothEnabled = adapter.isEnabled();
} else {
mBluetoothEnabled = false;
}
@@ -491,7 +468,7 @@
mGpsFixIconData = IconData.makeIcon("gps",
null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
- service.setIconVisibility(mGpsIcon, false);
+ service.setIconVisibility(mGpsIcon, false);
// Alarm clock
mAlarmClockIconData = IconData.makeIcon(
@@ -514,7 +491,7 @@
mVolumeIcon = service.addIcon(mVolumeData, null);
service.setIconVisibility(mVolumeIcon, false);
updateVolume();
-
+
IntentFilter filter = new IntentFilter();
// Register for Intent broadcasts for...
@@ -634,7 +611,7 @@
}
}
- private void showBatteryView() {
+ private void showBatteryView() {
closeLastBatteryView();
if (mLowBatteryDialog != null) {
mLowBatteryDialog.dismiss();
@@ -715,7 +692,7 @@
b.setView(v);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setPositiveButton(android.R.string.ok, null);
-
+
final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK
@@ -803,6 +780,10 @@
@Override
public void onCallStateChanged(int state, String incomingNumber) {
updateCallState(state);
+ // In cdma, if a voice call is made, RSSI should switch to 1x.
+ if (isCdma()) {
+ updateSignalStrength();
+ }
}
@Override
@@ -831,7 +812,7 @@
final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
mSimState = IccCard.State.PIN_REQUIRED;
- }
+ }
else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
mSimState = IccCard.State.PUK_REQUIRED;
}
@@ -848,6 +829,14 @@
return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
}
+ private boolean isEvdo() {
+ return ( (mServiceState != null)
+ && ((mServiceState.getRadioTechnology()
+ == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+ || (mServiceState.getRadioTechnology()
+ == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
+ }
+
private boolean hasService() {
if (mServiceState != null) {
switch (mServiceState.getState()) {
@@ -864,9 +853,7 @@
private final void updateSignalStrength() {
int iconLevel = -1;
- int evdoIconLevel = -1;
int[] iconList;
- int[] evdoIconList;
if (!hasService()) {
//Log.d(TAG, "updateSignalStrength: no service");
@@ -877,7 +864,6 @@
mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
}
mService.updateIcon(mPhoneIcon, mPhoneData, null);
- mService.setIconVisibility(mPhoneEvdoIcon,false);
return;
}
@@ -900,64 +886,67 @@
iconList = sSignalImages;
}
} else {
- iconList = this.sSignalImages_cdma;
+ iconList = this.sSignalImages;
- int cdmaDbm = mSignalStrength.getCdmaDbm();
- int cdmaEcio = mSignalStrength.getCdmaEcio();
- int levelDbm = 0;
- int levelEcio = 0;
-
- if (cdmaDbm >= -75) levelDbm = 4;
- else if (cdmaDbm >= -85) levelDbm = 3;
- else if (cdmaDbm >= -95) levelDbm = 2;
- else if (cdmaDbm >= -100) levelDbm = 1;
- else levelDbm = 0;
-
- // Ec/Io are in dB*10
- if (cdmaEcio >= -90) levelEcio = 4;
- else if (cdmaEcio >= -110) levelEcio = 3;
- else if (cdmaEcio >= -130) levelEcio = 2;
- else if (cdmaEcio >= -150) levelEcio = 1;
- else levelEcio = 0;
-
- iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
+ // If 3G(EV) and 1x network are available than 3G should be
+ // displayed, displayed RSSI should be from the EV side.
+ // If a voice call is made then RSSI should switch to 1x.
+ if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
+ iconLevel = getEvdoLevel();
+ if (false) {
+ Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+ }
+ } else {
+ iconLevel = getCdmaLevel();
+ }
}
-
- if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
- || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
- // Use Evdo icon
- evdoIconList = this.sSignalImages_evdo;
-
- int evdoDbm = mSignalStrength.getEvdoDbm();
- int evdoSnr = mSignalStrength.getEvdoSnr();
- int levelEvdoDbm = 0;
- int levelEvdoSnr = 0;
-
- if (evdoDbm >= -65) levelEvdoDbm = 4;
- else if (evdoDbm >= -75) levelEvdoDbm = 3;
- else if (evdoDbm >= -90) levelEvdoDbm = 2;
- else if (evdoDbm >= -105) levelEvdoDbm = 1;
- else levelEvdoDbm = 0;
-
- if (evdoSnr > 7) levelEvdoSnr = 4;
- else if (evdoSnr > 5) levelEvdoSnr = 3;
- else if (evdoSnr > 3) levelEvdoSnr = 2;
- else if (evdoSnr > 1) levelEvdoSnr = 1;
- else levelEvdoSnr = 0;
-
- evdoIconLevel = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-
- mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
- mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
- mService.setIconVisibility(mPhoneEvdoIcon,true);
- } else {
- mService.setIconVisibility(mPhoneEvdoIcon,false);
- }
-
mPhoneData.iconId = iconList[iconLevel];
mService.updateIcon(mPhoneIcon, mPhoneData, null);
}
+ private int getCdmaLevel() {
+ final int cdmaDbm = mSignalStrength.getCdmaDbm();
+ final int cdmaEcio = mSignalStrength.getCdmaEcio();
+ int levelDbm = 0;
+ int levelEcio = 0;
+
+ if (cdmaDbm >= -75) levelDbm = 4;
+ else if (cdmaDbm >= -85) levelDbm = 3;
+ else if (cdmaDbm >= -95) levelDbm = 2;
+ else if (cdmaDbm >= -100) levelDbm = 1;
+ else levelDbm = 0;
+
+ // Ec/Io are in dB*10
+ if (cdmaEcio >= -90) levelEcio = 4;
+ else if (cdmaEcio >= -110) levelEcio = 3;
+ else if (cdmaEcio >= -130) levelEcio = 2;
+ else if (cdmaEcio >= -150) levelEcio = 1;
+ else levelEcio = 0;
+
+ return (levelDbm < levelEcio) ? levelDbm : levelEcio;
+ }
+
+ private int getEvdoLevel() {
+ int evdoDbm = mSignalStrength.getEvdoDbm();
+ int evdoSnr = mSignalStrength.getEvdoSnr();
+ int levelEvdoDbm = 0;
+ int levelEvdoSnr = 0;
+
+ if (evdoDbm >= -65) levelEvdoDbm = 4;
+ else if (evdoDbm >= -75) levelEvdoDbm = 3;
+ else if (evdoDbm >= -90) levelEvdoDbm = 2;
+ else if (evdoDbm >= -105) levelEvdoDbm = 1;
+ else levelEvdoDbm = 0;
+
+ if (evdoSnr > 7) levelEvdoSnr = 4;
+ else if (evdoSnr > 5) levelEvdoSnr = 3;
+ else if (evdoSnr > 3) levelEvdoSnr = 2;
+ else if (evdoSnr > 1) levelEvdoSnr = 1;
+ else levelEvdoSnr = 0;
+
+ return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+ }
+
private final void updateDataNetType() {
int net = mPhone.getNetworkType();
@@ -968,16 +957,21 @@
case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = sDataNetType_3g;
break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ mDataIconList = sDataNetType_h;
+ break;
case TelephonyManager.NETWORK_TYPE_CDMA:
// display 1xRTT for IS95A/B
- mDataIconList = this.sDataNetType_1xrtt;
+ mDataIconList = this.sDataNetType_1x;
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
- mDataIconList = this.sDataNetType_1xrtt;
+ mDataIconList = this.sDataNetType_1x;
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
case TelephonyManager.NETWORK_TYPE_EVDO_A:
- mDataIconList = sDataNetType_evdo;
+ mDataIconList = sDataNetType_3g;
break;
default:
mDataIconList = sDataNetType_g;
@@ -1030,8 +1024,6 @@
iconId = mDataIconList[3];
break;
case TelephonyManager.DATA_ACTIVITY_DORMANT:
- iconId = mDataIconList[4];
- break;
default:
iconId = mDataIconList[0];
break;
@@ -1083,7 +1075,7 @@
if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
BluetoothError.ERROR);
- mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON;
+ mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
BluetoothHeadset.STATE_ERROR);
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index e4f001f..8e7cadc 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <dirent.h>
#if HAVE_ANDROID_OS
#include <linux/ioctl.h>
@@ -38,15 +39,7 @@
namespace android {
-#define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"
-#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"
-#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"
-#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"
-#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"
-#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
-#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"
-#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"
-#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"
+#define POWER_SUPPLY_PATH "/sys/class/power_supply"
struct FieldIds {
// members
@@ -77,6 +70,21 @@
};
static BatteryManagerConstants gConstants;
+struct PowerSupplyPaths {
+ char* acOnlinePath;
+ char* usbOnlinePath;
+ char* batteryStatusPath;
+ char* batteryHealthPath;
+ char* batteryPresentPath;
+ char* batteryCapacityPath;
+ char* batteryVoltagePath;
+ char* batteryTemperaturePath;
+ char* batteryTechnologyPath;
+};
+static PowerSupplyPaths gPaths;
+
+static int gVoltageDivisor = 1;
+
static jint getBatteryStatus(const char* status)
{
switch (status[0]) {
@@ -126,6 +134,8 @@
static int readFromFile(const char* path, char* buf, size_t size)
{
+ if (!path)
+ return -1;
int fd = open(path, O_RDONLY, 0);
if (fd == -1) {
LOGE("Could not open '%s'", path);
@@ -171,29 +181,43 @@
env->SetIntField(obj, fieldID, value);
}
+static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+{
+ const int SIZE = 128;
+ char buf[SIZE];
+
+ jint value = 0;
+ if (readFromFile(path, buf, SIZE) > 0) {
+ value = atoi(buf);
+ value /= gVoltageDivisor;
+ }
+ env->SetIntField(obj, fieldID, value);
+}
+
+
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
- setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
- setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
- setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
+ setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
+ setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
+ setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
- setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
- setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
- setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
+ setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
+ setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
+ setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
const int SIZE = 128;
char buf[SIZE];
- if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
else
env->SetIntField(obj, gFieldIds.mBatteryStatus,
gConstants.statusUnknown);
- if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
- if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
}
@@ -204,6 +228,101 @@
int register_android_server_BatteryService(JNIEnv* env)
{
+ char path[PATH_MAX];
+ struct dirent* entry;
+
+ DIR* dir = opendir(POWER_SUPPLY_PATH);
+ if (dir == NULL) {
+ LOGE("Could not open %s\n", POWER_SUPPLY_PATH);
+ return -1;
+ }
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+
+ char buf[20];
+ // Look for "type" file in each subdirectory
+ snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
+ int length = readFromFile(path, buf, sizeof(buf));
+ if (length > 0) {
+ if (buf[length - 1] == '\n')
+ buf[length - 1] = 0;
+
+ if (strcmp(buf, "Mains") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.acOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "USB") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.usbOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "Battery") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryStatusPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryHealthPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryPresentPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryCapacityPath = strdup(path);
+
+ snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
+ gPaths.batteryVoltagePath = strdup(path);
+ // voltage_now is in microvolts, not millivolts
+ gVoltageDivisor = 1000;
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryVoltagePath = strdup(path);
+ }
+
+ snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
+ gPaths.batteryTemperaturePath = strdup(path);
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTemperaturePath = strdup(path);
+ }
+
+ snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTechnologyPath = strdup(path);
+ }
+ }
+ }
+ closedir(dir);
+
+ if (!gPaths.acOnlinePath)
+ LOGE("acOnlinePath not found");
+ if (!gPaths.usbOnlinePath)
+ LOGE("usbOnlinePath not found");
+ if (!gPaths.batteryStatusPath)
+ LOGE("batteryStatusPath not found");
+ if (!gPaths.batteryHealthPath)
+ LOGE("batteryHealthPath not found");
+ if (!gPaths.batteryPresentPath)
+ LOGE("batteryPresentPath not found");
+ if (!gPaths.batteryCapacityPath)
+ LOGE("batteryCapacityPath not found");
+ if (!gPaths.batteryVoltagePath)
+ LOGE("batteryVoltagePath not found");
+ if (!gPaths.batteryTemperaturePath)
+ LOGE("batteryTemperaturePath not found");
+ if (!gPaths.batteryTechnologyPath)
+ LOGE("batteryTechnologyPath not found");
+
jclass clazz = env->FindClass("com/android/server/BatteryService");
if (clazz == NULL) {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 13713e5..4368464 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -29,7 +29,9 @@
import android.util.Log;
import android.util.SparseIntArray;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
import java.util.Locale;
import java.util.regex.Matcher;
@@ -929,7 +931,7 @@
"JM", // Jamaica
"PR", // Puerto Rico
"MS", // Montserrat
- "NP", // Northern Mariana Islands
+ "MP", // Northern Mariana Islands
"KN", // Saint Kitts and Nevis
"LC", // Saint Lucia
"VC", // Saint Vincent and the Grenadines
@@ -962,17 +964,7 @@
public static int getFormatTypeForLocale(Locale locale) {
String country = locale.getCountry();
- // Check for the NANP countries
- int length = NANP_COUNTRIES.length;
- for (int i = 0; i < length; i++) {
- if (NANP_COUNTRIES[i].equals(country)) {
- return FORMAT_NANP;
- }
- }
- if (locale.equals(Locale.JAPAN)) {
- return FORMAT_JAPAN;
- }
- return FORMAT_UNKNOWN;
+ return getFormatTypeFromCountryCode(country);
}
/**
@@ -1272,6 +1264,11 @@
*
* Otherwise, this function returns the dial string passed in
*
+ * @param dialStr the original dial string
+ * @return the converted dial string if the current/default countries belong to NANP,
+ * and if there is the "+" in the original dial string. Otherwise, the original dial
+ * string returns.
+ *
* This API is for CDMA only
*
* @hide TODO: pending API Council approval
@@ -1280,8 +1277,13 @@
if (!TextUtils.isEmpty(dialStr)) {
if (isReallyDialable(dialStr.charAt(0)) &&
isNonSeparator(dialStr)) {
- return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
- getFormatTypeForLocale(Locale.getDefault()));
+ String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, "");
+ String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+ if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
+ return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
+ getFormatTypeFromCountryCode(currIso),
+ getFormatTypeFromCountryCode(defaultIso));
+ }
}
}
return dialStr;
@@ -1296,89 +1298,92 @@
* plus sign, then process the plus sign.
* Currently, this function supports the plus sign conversion within NANP only.
* Specifically, it handles the plus sign in the following ways:
- * 1)+NANP or +1NANP,remove +, e.g.
- * +8475797000 is converted to 8475797000,
+ * 1)+1NANP,remove +, e.g.
* +18475797000 is converted to 18475797000,
- * 2)+non-NANP Numbers,replace + with the current NANP IDP, e.g,
+ * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g,
+ * +8475797000 is converted to 0118475797000,
* +11875767800 is converted to 01111875767800
- * 3)+NANP in post dial string(s), e.g.
- * 8475797000;+8475231753 is converted to 8475797000;8475231753
+ * 3)+1NANP in post dial string(s), e.g.
+ * 8475797000;+18475231753 is converted to 8475797000;18475231753
*
- * This function returns the original dial string if locale/numbering plan
- * aren't supported.
+ *
+ * @param dialStr the original dial string
+ * @param currFormat the numbering system of the current country that the phone is camped on
+ * @param defaultFormat the numbering system of the country that the phone is activated on
+ * @return the converted dial string if the current/default countries belong to NANP,
+ * and if there is the "+" in the original dial string. Otherwise, the original dial
+ * string returns.
*
* @hide
*/
- public static String cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int numFormat) {
+ public static String
+ cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) {
String retStr = dialStr;
// Checks if the plus sign character is in the passed-in dial string
if (dialStr != null &&
dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
+ // Format the string based on the rules for the country the number is from,
+ // and the current country the phone is camped on.
+ if ((currFormat == defaultFormt) && (currFormat == FORMAT_NANP)) {
+ // Handle case where default and current telephone numbering plans are NANP.
+ String postDialStr = null;
+ String tempDialStr = dialStr;
- String postDialStr = null;
- String tempDialStr = dialStr;
-
- // Sets the retStr to null since the conversion will be performed below.
- retStr = null;
- if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
- // This routine is to process the plus sign in the dial string by loop through
- // the network portion, post dial portion 1, post dial portion 2... etc. if
- // applied
- do {
- String networkDialStr;
-
- // Format the string based on the rules for the country the number is from
- if (numFormat != FORMAT_NANP) {
- // TODO: to support NANP international conversion and
- // other telephone numbering plan
- // Currently the phone is ever used in non-NANP system
- // return the original dial string
- Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
- return dialStr;
- } else {
- // For the case that the default and current telephone
- // numbering plans are NANP
+ // Sets the retStr to null since the conversion will be performed below.
+ retStr = null;
+ if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
+ // This routine is to process the plus sign in the dial string by loop through
+ // the network portion, post dial portion 1, post dial portion 2... etc. if
+ // applied
+ do {
+ String networkDialStr;
networkDialStr = extractNetworkPortion(tempDialStr);
// Handles the conversion within NANP
networkDialStr = processPlusCodeWithinNanp(networkDialStr);
- }
- // Concatenates the string that is converted from network portion
- if (!TextUtils.isEmpty(networkDialStr)) {
- if (retStr == null) {
- retStr = networkDialStr;
- } else {
- retStr = retStr.concat(networkDialStr);
- }
- } else {
- // This should never happen since we checked the if dialStr is null
- // and if it contains the plus sign in the begining of this function.
- // The plus sign is part of the network portion.
- Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
- return dialStr;
- }
- postDialStr = extractPostDialPortion(tempDialStr);
- if (!TextUtils.isEmpty(postDialStr)) {
- int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
- // dialableIndex should always be greater than 0
- if (dialableIndex >= 1) {
- retStr = appendPwCharBackToOrigDialStr(dialableIndex,
- retStr,postDialStr);
- // Skips the P/W character, extracts the dialable portion
- tempDialStr = postDialStr.substring(dialableIndex);
- } else {
- // Non-dialable character such as P/W should not be at the end of
- // the dial string after P/W processing in CdmaConnection.java
- // Set the postDialStr to "" to break out of the loop
- if (dialableIndex < 0) {
- postDialStr = "";
+ // Concatenates the string that is converted from network portion
+ if (!TextUtils.isEmpty(networkDialStr)) {
+ if (retStr == null) {
+ retStr = networkDialStr;
+ } else {
+ retStr = retStr.concat(networkDialStr);
}
- Log.e("wrong postDialStr=", postDialStr);
+ } else {
+ // This should never happen since we checked the if dialStr is null
+ // and if it contains the plus sign in the beginning of this function.
+ // The plus sign is part of the network portion.
+ Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
+ return dialStr;
}
- }
- if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
- } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
+ postDialStr = extractPostDialPortion(tempDialStr);
+ if (!TextUtils.isEmpty(postDialStr)) {
+ int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
+
+ // dialableIndex should always be greater than 0
+ if (dialableIndex >= 1) {
+ retStr = appendPwCharBackToOrigDialStr(dialableIndex,
+ retStr,postDialStr);
+ // Skips the P/W character, extracts the dialable portion
+ tempDialStr = postDialStr.substring(dialableIndex);
+ } else {
+ // Non-dialable character such as P/W should not be at the end of
+ // the dial string after P/W processing in CdmaConnection.java
+ // Set the postDialStr to "" to break out of the loop
+ if (dialableIndex < 0) {
+ postDialStr = "";
+ }
+ Log.e("wrong postDialStr=", postDialStr);
+ }
+ }
+ if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
+ } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
+ } else {
+ // TODO: Support NANP international conversion and other telephone numbering plans.
+ // Currently the phone is never used in non-NANP system, so return the original
+ // dial string.
+ Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
+ }
}
return retStr;
}
@@ -1401,6 +1406,20 @@
}
}
+ private static int getFormatTypeFromCountryCode (String country) {
+ // Check for the NANP countries
+ int length = NANP_COUNTRIES.length;
+ for (int i = 0; i < length; i++) {
+ if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) {
+ return FORMAT_NANP;
+ }
+ }
+ if ("jp".compareToIgnoreCase(country) == 0) {
+ return FORMAT_JAPAN;
+ }
+ return FORMAT_UNKNOWN;
+ }
+
/**
* This function checks if the passed in string conforms to the NANP format
* i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9
@@ -1446,8 +1465,8 @@
/**
* This function handles the plus code conversion within NANP CDMA network
* If the number format is
- * 1)+NANP or +1NANP,remove +,
- * 2)+non-NANP Numbers,replace + with the current IDP
+ * 1)+1NANP,remove +,
+ * 2)other than +1NANP, any + numbers,replace + with the current IDP
*/
private static String processPlusCodeWithinNanp(String networkDialStr) {
String retStr = networkDialStr;
@@ -1459,7 +1478,7 @@
networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
networkDialStr.length() > 1) {
String newStr = networkDialStr.substring(1);
- if (isNanp(newStr) || isOneNanp(newStr)) {
+ if (isOneNanp(newStr)) {
// Remove the leading plus sign
retStr = newStr;
} else {
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index e113680..73e7baa5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -154,8 +154,9 @@
* @see ServiceState#STATE_IN_SERVICE
* @see ServiceState#STATE_OUT_OF_SERVICE
* @see ServiceState#STATE_POWER_OFF
- * @deprecated, @see #onSignalStrengthsChanged
+ * @deprecated see #onSignalStrengthsChanged
*/
+ @Deprecated
public void onSignalStrengthChanged(int asu) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 50c4d41..06b5c26 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -83,6 +83,12 @@
public static final int RADIO_TECHNOLOGY_EVDO_0 = 7;
/** @hide */
public static final int RADIO_TECHNOLOGY_EVDO_A = 8;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSDPA = 9;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSUPA = 10;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSPA = 11;
/**
* Available registration states for GSM, UMTS and CDMA.
@@ -366,6 +372,15 @@
case 8:
radioTechnology = "EvDo rev. A";
break;
+ case 9:
+ radioTechnology = "HSDPA";
+ break;
+ case 10:
+ radioTechnology = "HSUPA";
+ break;
+ case 11:
+ radioTechnology = "HSPA";
+ break;
default:
Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
break;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ed9af66..f3304a3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -382,6 +382,15 @@
/** Current network is 1xRTT*/
/** @hide */
public static final int NETWORK_TYPE_1xRTT = 7;
+ /** Current network is HSDPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSDPA = 8;
+ /** Current network is HSUPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSUPA = 9;
+ /** Current network is HSPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSPA = 10;
/**
* Returns a constant indicating the radio technology (network type)
@@ -392,35 +401,25 @@
* @see #NETWORK_TYPE_GPRS
* @see #NETWORK_TYPE_EDGE
* @see #NETWORK_TYPE_UMTS
+ * @see #NETWORK_TYPE_HSDPA
+ * @see #NETWORK_TYPE_HSUPA
+ * @see #NETWORK_TYPE_HSPA
* @see #NETWORK_TYPE_CDMA
* @see #NETWORK_TYPE_EVDO_0
* @see #NETWORK_TYPE_EVDO_A
* @see #NETWORK_TYPE_1xRTT
*/
public int getNetworkType() {
- String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE);
- if ("GPRS".equals(prop)) {
- return NETWORK_TYPE_GPRS;
- }
- else if ("EDGE".equals(prop)) {
- return NETWORK_TYPE_EDGE;
- }
- else if ("UMTS".equals(prop)) {
- return NETWORK_TYPE_UMTS;
- }
- else if ("CDMA".equals(prop)) {
- return NETWORK_TYPE_CDMA;
- }
- else if ("CDMA - EvDo rev. 0".equals(prop)) {
- return NETWORK_TYPE_EVDO_0;
+ try{
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkType();
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
}
- else if ("CDMA - EvDo rev. A".equals(prop)) {
- return NETWORK_TYPE_EVDO_A;
- }
- else if ("CDMA - 1xRTT".equals(prop)) {
- return NETWORK_TYPE_1xRTT;
- }
- else {
+ } catch(RemoteException ex){
+ // This shouldn't happen in the normal case
return NETWORK_TYPE_UNKNOWN;
}
}
@@ -440,6 +439,12 @@
return "EDGE";
case NETWORK_TYPE_UMTS:
return "UMTS";
+ case NETWORK_TYPE_HSDPA:
+ return "HSDPA";
+ case NETWORK_TYPE_HSUPA:
+ return "HSUPA";
+ case NETWORK_TYPE_HSPA:
+ return "HSPA";
case NETWORK_TYPE_CDMA:
return "CDMA";
case NETWORK_TYPE_EVDO_0:
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index 84dfca0..37ef912 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -345,6 +345,7 @@
* the number of code units used, and int[2] is the number of code
* units remaining until the next message. int[3] is the encoding
* type that should be used for the message.
+ * @deprecated Use android.telephony.SmsMessage.
*/
@Deprecated
public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index afc8b62..bda2d22 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,9 +20,8 @@
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.text.TextUtils;
import android.telephony.TelephonyManager;
import android.telephony.PhoneNumberUtils;
@@ -134,44 +133,39 @@
int columnIndex;
// Look for the name
- columnIndex = cursor.getColumnIndex(People.NAME);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
if (columnIndex != -1) {
info.name = cursor.getString(columnIndex);
}
// Look for the number
- columnIndex = cursor.getColumnIndex(Phones.NUMBER);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
if (columnIndex != -1) {
info.phoneNumber = cursor.getString(columnIndex);
}
// Look for the label/type combo
- columnIndex = cursor.getColumnIndex(Phones.LABEL);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
if (columnIndex != -1) {
- int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE);
+ int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
if (typeColumnIndex != -1) {
info.numberType = cursor.getInt(typeColumnIndex);
info.numberLabel = cursor.getString(columnIndex);
- info.phoneLabel = Contacts.Phones.getDisplayLabel(context,
+ info.phoneLabel = Phone.getDisplayLabel(context,
info.numberType, info.numberLabel)
.toString();
}
}
// Look for the person ID
- columnIndex = cursor.getColumnIndex(Phones.PERSON_ID);
+ columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
- } else {
- columnIndex = cursor.getColumnIndex(People._ID);
- if (columnIndex != -1) {
- info.person_id = cursor.getLong(columnIndex);
- }
}
// look for the custom ringtone, create from the string stored
// in the database.
- columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
} else {
@@ -180,7 +174,7 @@
// look for the send to voicemail flag, set it to true only
// under certain circumstances.
- columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
info.shouldSendToVoicemail = (columnIndex != -1) &&
((cursor.getInt(columnIndex)) == 1);
info.contactExists = true;
@@ -256,8 +250,7 @@
}
}
- Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL,
- Uri.encode(number));
+ Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
CallerInfo info = getCallerInfo(context, contactUri);
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index f81f42a..ef456f0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,7 +24,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.provider.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -303,7 +303,7 @@
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
//contruct the URI object and start Query.
- Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number);
+ Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
c.allocate(context, contactRef);
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 6ebd8d6..ed8bc1e 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -607,8 +607,9 @@
* ar.exception carries exception on failure
* ar.userObject contains the orignal value of result.obj
* ar.result contains a List of DataCallState
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
void getPDPContextList(Message result);
/**
@@ -779,8 +780,9 @@
* cause code returned as int[0] in Message.obj.response
* returns an integer cause code defined in TS 24.008
* section 6.1.3.1.3 or close approximation
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
void getLastPdpFailCause (Message result);
/**
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index a3f1ad8..cfb465e 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -24,14 +24,18 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
import android.util.Log;
+import java.util.ArrayList;
+
/**
* {@hide}
*
*/
public abstract class DataConnectionTracker extends Handler {
- private static final boolean DBG = true;
+ protected static final boolean DBG = true;
+ protected final String LOG_TAG = "DataConnectionTracker";
/**
* IDLE: ready to start data connection setup, default state
@@ -94,9 +98,25 @@
protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
public static final int EVENT_CLEAN_UP_CONNECTION = 34;
+ protected static final int EVENT_CDMA_OTA_PROVISION = 35;
+ protected static final int EVENT_RESTART_RADIO = 36;
//***** Constants
+ protected static final int APN_INVALID_ID = -1;
+ protected static final int APN_DEFAULT_ID = 0;
+ protected static final int APN_MMS_ID = 1;
+ protected static final int APN_SUPL_ID = 2;
+ protected static final int APN_DUN_ID = 3;
+ protected static final int APN_HIPRI_ID = 4;
+ protected static final int APN_NUM_TYPES = 5;
+
+ protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+ protected int enabledCount = 0;
+
+ /* Currently requested APN type */
+ protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+
/** Retry configuration: A doubling of retry times from 5secs to 30minutes */
protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
+ "5000,10000,20000,40000,80000:5000,160000:5000,"
@@ -146,6 +166,9 @@
protected int mNoRecvPollCount = 0;
protected boolean netStatPollEnabled = false;
+ /** Manage the behavior of data retry after failure */
+ protected final RetryManager mRetryMgr = new RetryManager();
+
// wifi connection status will be updated by sticky intent
protected boolean mIsWifiConnected = false;
@@ -163,6 +186,8 @@
this.phone = phone;
}
+ public abstract void dispose();
+
public Activity getActivity() {
return activity;
}
@@ -202,10 +227,13 @@
if (getDataOnRoamingEnabled() != enabled) {
Settings.Secure.putInt(phone.getContext().getContentResolver(),
Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
+ if (phone.getServiceState().getRoaming()) {
+ if (enabled) {
+ mRetryMgr.resetRetryCount();
+ }
+ sendMessage(obtainMessage(EVENT_ROAMING_ON));
+ }
}
- Message roamingMsg = phone.getServiceState().getRoaming() ?
- obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF);
- sendMessage(roamingMsg);
}
//Retrieve the data roaming setting from the shared preferences.
@@ -243,6 +271,9 @@
break;
case EVENT_ROAMING_OFF:
+ if (getDataOnRoamingEnabled() == false) {
+ mRetryMgr.resetRetryCount();
+ }
onRoamingOff();
break;
@@ -291,24 +322,18 @@
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
- public abstract boolean getDataEnabled();
+ public boolean getDataEnabled() {
+ return dataEnabled[APN_DEFAULT_ID];
+ }
/**
* Report on whether data connectivity is enabled
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
- public abstract boolean getAnyDataEnabled();
-
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
- * @return {@code true} if the operation succeeded
- */
- public abstract boolean setDataEnabled(boolean enable);
+ public boolean getAnyDataEnabled() {
+ return (enabledCount != 0);
+ }
protected abstract void startNetStatPoll();
@@ -317,4 +342,166 @@
protected abstract void restartRadio();
protected abstract void log(String s);
+
+ protected int apnTypeToId(String type) {
+ if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
+ return APN_DEFAULT_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
+ return APN_MMS_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
+ return APN_SUPL_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
+ return APN_DUN_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
+ return APN_HIPRI_ID;
+ } else {
+ return APN_INVALID_ID;
+ }
+ }
+
+ protected abstract boolean isApnTypeActive(String type);
+
+ protected abstract boolean isApnTypeAvailable(String type);
+
+ protected abstract String[] getActiveApnTypes();
+
+ protected abstract String getActiveApnString();
+
+ public abstract ArrayList<DataConnection> getAllDataConnections();
+
+ protected abstract String getInterfaceName(String apnType);
+
+ protected abstract String getIpAddress(String apnType);
+
+ protected abstract String getGateway(String apnType);
+
+ protected abstract String[] getDnsServers(String apnType);
+
+ protected abstract void setState(State s);
+
+ protected boolean isEnabled(int id) {
+ if (id != APN_INVALID_ID) {
+ return dataEnabled[id];
+ }
+ return false;
+ }
+
+ /**
+ * Ensure that we are connected to an APN of the specified type.
+ * @param type the APN type (currently the only valid values
+ * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
+ * @return the result of the operation. Success is indicated by
+ * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
+ * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
+ * will be sent by the ConnectivityManager when a connection to
+ * the APN has been established.
+ */
+ public int enableApnType(String type) {
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+
+ // If already active, return
+ if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
+ + isApnTypeActive(type) + " and state = " + state);
+
+ if (isApnTypeActive(type)) {
+ if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
+ else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
+ }
+
+ if (!isApnTypeAvailable(type)) {
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ setEnabled(id, true);
+ mRequestedApnType = type;
+ sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ /**
+ * The APN of the specified type is no longer needed. Ensure that if
+ * use of the default APN has not been explicitly disabled, we are connected
+ * to the default APN.
+ * @param type the APN type. The only valid values are currently
+ * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
+ * @return
+ */
+ public int disableApnType(String type) {
+ if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ if (isEnabled(id)) {
+ setEnabled(id, false);
+ if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+ mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ return Phone.APN_ALREADY_ACTIVE;
+ } else {
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ }
+
+ protected synchronized void setEnabled(int id, boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
+ dataEnabled[id] + " and enabledCount = " + enabledCount);
+ if (dataEnabled[id] != enable) {
+ dataEnabled[id] = enable;
+
+ // count the total number of enabled APN's
+ // if we just enabled the first APN, start our Data connection,
+ // if we disabled the last, stop our data connection
+ if (enable) {
+ enabledCount++;
+ if (enabledCount == 1) {
+ setPrivateDataEnabled(true);
+ }
+ } else {
+ enabledCount--;
+ if (enabledCount == 0) {
+ setPrivateDataEnabled(false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Prevent mobile data connections from being established,
+ * or once again allow mobile data connections. If the state
+ * toggles, then either tear down or set up data, as
+ * appropriate to match the new state.
+ * <p>This operation only affects the default APN, and if the same APN is
+ * currently being used for MMS traffic, the teardown will not happen
+ * even when {@code enable} is {@code false}.</p>
+ * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
+ * @return {@code true} if the operation succeeded
+ */
+ public boolean setDataEnabled(boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")");
+ setEnabled(APN_DEFAULT_ID, enable);
+ return true;
+ }
+
+ private void setPrivateDataEnabled(boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")");
+ if (enable) {
+ sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+ } else {
+ Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
+ msg.arg1 = 1; // tearDown is true
+ msg.obj = Phone.REASON_DATA_DISABLED;
+ sendMessage(msg);
+ }
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d83b135..cac4de9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -243,5 +243,9 @@
*/
int getVoiceMessageCount();
+ /**
+ * Returns the network type
+ */
+ int getNetworkType();
}
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index c2bed88..6657060 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -595,7 +595,7 @@
// this is common for all radio technologies
if (!mIccCardStatus.getCardState().isCardPresent()) {
- return IccCard.State.NOT_READY;
+ return IccCard.State.ABSENT;
}
RadioState currentRadioState = mPhone.mCM.getRadioState();
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 622b47d..3f9744f 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -434,6 +434,20 @@
void unregisterForMmiComplete(Handler h);
/**
+ * Registration point for Ecm timer reset
+ * @param h handler to notify
+ * @param what user-defined message code
+ * @param obj placed in Message.obj
+ */
+ public void registerForEcmTimerReset(Handler h, int what, Object obj);
+
+ /**
+ * Unregister for notification for Ecm timer reset
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForEcmTimerReset(Handler h);
+
+ /**
* Returns a list of MMI codes that are pending. (They have initiated
* but have not yet completed).
* Presently there is only ever one.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index b279527..9edb4c2 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -109,6 +109,7 @@
public CommandsInterface mCM;
protected IccFileHandler mIccFileHandler;
boolean mDnsCheckDisabled = false;
+ public DataConnectionTracker mDataConnection;
/**
* Set a system property, unless we're in unit test mode
@@ -617,7 +618,7 @@
* This should only be called in GSM mode.
* Only here for some backward compatibility
* issues concerning the GSMPhone class.
- * @deprecated
+ * @deprecated Always returns null.
*/
public List<PdpConnection> getCurrentPdpList() {
return null;
@@ -759,6 +760,16 @@
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ // 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.");
+ }
+
+ public void unregisterForEcmTimerReset(Handler h) {
+ // 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.");
+ }
+
public void registerForSignalInfo(Handler h, int what, Object obj) {
mCM.registerForSignalInfo(h, what, obj);
}
@@ -824,4 +835,71 @@
// 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.");
}
+
+ public String getInterfaceName(String apnType) {
+ return mDataConnection.getInterfaceName(apnType);
+ }
+
+ public String getIpAddress(String apnType) {
+ return mDataConnection.getIpAddress(apnType);
+ }
+
+ public boolean isDataConnectivityEnabled() {
+ return mDataConnection.getDataEnabled();
+ }
+
+ public String getGateway(String apnType) {
+ return mDataConnection.getGateway(apnType);
+ }
+
+ public String[] getDnsServers(String apnType) {
+ return mDataConnection.getDnsServers(apnType);
+ }
+
+ public String[] getActiveApnTypes() {
+ return mDataConnection.getActiveApnTypes();
+ }
+
+ public String getActiveApn() {
+ return mDataConnection.getActiveApnString();
+ }
+
+ public int enableApnType(String type) {
+ return mDataConnection.enableApnType(type);
+ }
+
+ public int disableApnType(String type) {
+ return mDataConnection.disableApnType(type);
+ }
+
+ /**
+ * simulateDataConnection
+ *
+ * simulates various data connection states. This messes with
+ * DataConnectionTracker's internal states, but doesn't actually change
+ * the underlying radio connection states.
+ *
+ * @param state Phone.DataState enum.
+ */
+ public void simulateDataConnection(Phone.DataState state) {
+ DataConnectionTracker.State dcState;
+
+ switch (state) {
+ case CONNECTED:
+ dcState = DataConnectionTracker.State.CONNECTED;
+ break;
+ case SUSPENDED:
+ dcState = DataConnectionTracker.State.CONNECTED;
+ break;
+ case DISCONNECTED:
+ dcState = DataConnectionTracker.State.FAILED;
+ break;
+ default:
+ dcState = DataConnectionTracker.State.CONNECTING;
+ break;
+ }
+
+ mDataConnection.setState(dcState);
+ notifyDataConnection(null);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index f2568c1..8683278 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -323,6 +323,14 @@
mActivePhone.unregisterForSubscriptionInfoReady(h);
}
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ mActivePhone.registerForEcmTimerReset(h,what,obj);
+ }
+
+ public void unregisterForEcmTimerReset(Handler h) {
+ mActivePhone.unregisterForEcmTimerReset(h);
+ }
+
public boolean getIccRecordsLoaded() {
return mActivePhone.getIccRecordsLoaded();
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 50bf218..cd6340e 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -2511,6 +2511,7 @@
mRestrictedStateRegistrant.notifyRegistrant(
new AsyncResult (null, ret, null));
}
+ break;
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
if (RILJ_LOGD) unsljLog(response);
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 46b39a5..c74bb8d 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -34,6 +34,14 @@
* 1 = GPRS only
* 2 = EDGE
* 3 = UMTS
+ * 4 = IS95A
+ * 5 = IS95B
+ * 6 = 1xRTT
+ * 7 = EvDo_0
+ * 8 = EvDo_A
+ * 9 = HSDPA
+ * 10 = HSUPA
+ * 11 = HSPA
*/
protected static final int DATA_ACCESS_UNKNOWN = 0;
protected static final int DATA_ACCESS_GPRS = 1;
@@ -44,6 +52,9 @@
protected static final int DATA_ACCESS_CDMA_1xRTT = 6;
protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7;
protected static final int DATA_ACCESS_CDMA_EvDo_A = 8;
+ protected static final int DATA_ACCESS_HSDPA = 9;
+ protected static final int DATA_ACCESS_HSUPA = 10;
+ protected static final int DATA_ACCESS_HSPA = 11;
//***** Instance Variables
protected CommandsInterface cm;
@@ -116,6 +127,7 @@
protected static final int EVENT_NV_READY = 35;
protected static final int EVENT_ERI_FILE_LOADED = 36;
protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37;
+ protected static final int EVENT_SET_RADIO_POWER_OFF = 38;
//***** Time Zones
protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 522fa1d..66eb789 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -28,6 +28,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
@@ -72,8 +74,7 @@
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
+
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -87,15 +88,18 @@
// Default Emergency Callback Mode exit timer
private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+
static final String VM_COUNT_CDMA = "vm_count_key_cdma";
private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
private String mVmNumber = null;
+ static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
+ static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
+
//***** Instance Variables
CdmaCallTracker mCT;
CdmaSMSDispatcher mSMS;
CdmaServiceStateTracker mSST;
- CdmaDataConnectionTracker mDataConnection;
RuimFileHandler mRuimFileHandler;
RuimRecords mRuimRecords;
RuimCard mRuimCard;
@@ -104,6 +108,7 @@
RuimSmsInterfaceManager mRuimSmsInterfaceManager;
PhoneSubInfo mSubInfo;
EriManager mEriManager;
+ WakeLock mWakeLock;
// mNvLoadedRegistrants are informed after the EVENT_NV_READY
private RegistrantList mNvLoadedRegistrants = new RegistrantList();
@@ -111,17 +116,20 @@
// mEriFileLoadedRegistrants are informed after the ERI text has been loaded
private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
- // mECMExitRespRegistrant is informed after the phone has been exited
+ // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
+ private RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
+
+ // mEcmExitRespRegistrant is informed after the phone has been exited
//the emergency callback mode
//keep track of if phone is in emergency callback mode
- private boolean mIsPhoneInECMState;
- private Registrant mECMExitRespRegistrant;
+ private boolean mIsPhoneInEcmState;
+ private Registrant mEcmExitRespRegistrant;
private String mEsn;
private String mMeid;
// string to define how the carrier specifies its own ota sp number
private String mCarrierOtaSpNumSchema;
- // A runnable which is used to automatically exit from ECM after a period of time.
+ // A runnable which is used to automatically exit from Ecm after a period of time.
private Runnable mExitEcmRunnable = new Runnable() {
public void run() {
exitEmergencyCallbackMode();
@@ -166,6 +174,9 @@
mCM.registerForNVReady(h, EVENT_NV_READY, null);
mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
+ PowerManager pm
+ = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG);
//Change the system setting
SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
@@ -173,7 +184,7 @@
// This is needed to handle phone process crashes
String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- mIsPhoneInECMState = inEcm.equals("true");
+ mIsPhoneInEcmState = inEcm.equals("true");
// get the string that specifies the carrier OTA Sp number
mCarrierOtaSpNumSchema = SystemProperties.get(
@@ -245,6 +256,10 @@
protected void finalize() {
if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
+ if (mWakeLock.isHeld()) {
+ Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
+ mWakeLock.release();
+ }
}
@@ -369,42 +384,11 @@
return mCT.backgroundCall;
}
- public String getGateway(String apnType) {
- return mDataConnection.getGateway();
- }
-
public boolean handleInCallMmiCommands(String dialString) {
Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
return false;
}
- public int enableApnType(String type) {
- // This request is mainly used to enable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to enableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- public int disableApnType(String type) {
- // This request is mainly used to disable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to disableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_REQUEST_STARTED;
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- public String getActiveApn() {
- Log.d(LOG_TAG, "Request to getActiveApn()");
- return null;
- }
-
public void
setNetworkSelectionModeAutomatic(Message response) {
Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
@@ -481,10 +465,6 @@
return false;
}
- public String getInterfaceName(String apnType) {
- return mDataConnection.getInterfaceName();
- }
-
public CellLocation getCellLocation() {
return mSST.cellLoc;
}
@@ -512,10 +492,6 @@
return false;
}
- public boolean isDataConnectivityEnabled() {
- return mDataConnection.getDataEnabled();
- }
-
public boolean isDataConnectivityPossible() {
boolean noData = mDataConnection.getDataEnabled() &&
getDataConnectionState() == DataState.DISCONNECTED;
@@ -528,10 +504,6 @@
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
}
- public String[] getDnsServers(String apnType) {
- return mDataConnection.getDnsServers();
- }
-
public IccCard getIccCard() {
return mRuimCard;
}
@@ -569,11 +541,11 @@
}
public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
- mECMExitRespRegistrant = new Registrant (h, what, obj);
+ mEcmExitRespRegistrant = new Registrant (h, what, obj);
}
public void unsetOnEcbModeExitResponse(Handler h) {
- mECMExitRespRegistrant.clear();
+ mEcmExitRespRegistrant.clear();
}
public void registerForCallWaiting(Handler h, int what, Object obj) {
@@ -584,10 +556,6 @@
mCT.unregisterForCallWaiting(h);
}
- public String getIpAddress(String apnType) {
- return mDataConnection.getIpAddress();
- }
-
public void
getNeighboringCids(Message response) {
/*
@@ -701,14 +669,6 @@
Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
}
- public String[] getActiveApnTypes() {
- String[] result;
- Log.d(LOG_TAG, "Request to getActiveApn()");
- result = new String[1];
- result[0] = Phone.APN_TYPE_DEFAULT;
- return result;
- }
-
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
}
@@ -785,10 +745,13 @@
public boolean enableDataConnectivity() {
// block data activities when phone is in emergency callback mode
- if (mIsPhoneInECMState) {
+ if (mIsPhoneInEcmState) {
Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
ActivityManagerNative.broadcastStickyIntent(intent, null);
return false;
+ } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) {
+ // Do not allow data call to be enabled when emergency call is going on
+ return false;
} else {
return mDataConnection.setDataEnabled(true);
}
@@ -882,8 +845,9 @@
void sendEmergencyCallbackModeChange(){
//Send an Intent
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
- intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState);
+ intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
ActivityManagerNative.broadcastStickyIntent(intent,null);
+ if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
}
/*package*/ void
@@ -915,15 +879,21 @@
@Override
public void exitEmergencyCallbackMode() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
// Send a message which will invoke handleExitEmergencyCallbackMode
mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
}
private void handleEnterEmergencyCallbackMode(Message msg) {
- Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received");
- // if phone is not in ECM mode, and it's changed to ECM mode
- if (mIsPhoneInECMState == false) {
- mIsPhoneInECMState = true;
+ if (DBG) {
+ Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
+ + mIsPhoneInEcmState);
+ }
+ // if phone is not in Ecm mode, and it's changed to Ecm mode
+ if (mIsPhoneInEcmState == false) {
+ mIsPhoneInEcmState = true;
// notify change
sendEmergencyCallbackModeChange();
setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
@@ -933,23 +903,27 @@
long delayInMillis = SystemProperties.getLong(
TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
h.postDelayed(mExitEcmRunnable, delayInMillis);
+ // We don't want to go to sleep while in Ecm
+ mWakeLock.acquire();
}
}
private void handleExitEmergencyCallbackMode(Message msg) {
- Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received");
AsyncResult ar = (AsyncResult)msg.obj;
-
- // Remove pending exit ECM runnable, if any
+ if (DBG) {
+ Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
+ + ar.exception + mIsPhoneInEcmState);
+ }
+ // Remove pending exit Ecm runnable, if any
h.removeCallbacks(mExitEcmRunnable);
- if (mECMExitRespRegistrant != null) {
- mECMExitRespRegistrant.notifyRegistrant(ar);
+ if (mEcmExitRespRegistrant != null) {
+ mEcmExitRespRegistrant.notifyRegistrant(ar);
}
// if exiting ecm success
if (ar.exception == null) {
- if (mIsPhoneInECMState) {
- mIsPhoneInECMState = false;
+ if (mIsPhoneInEcmState) {
+ mIsPhoneInEcmState = false;
setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
}
// send an Intent
@@ -959,6 +933,42 @@
}
}
+ /**
+ * Handle to cancel or restart Ecm timer in emergency call back mode
+ * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
+ * otherwise, restart Ecm timer and notify apps the timer is restarted.
+ */
+ void handleTimerInEmergencyCallbackMode(int action) {
+ switch(action) {
+ case CANCEL_ECM_TIMER:
+ h.removeCallbacks(mExitEcmRunnable);
+ mEcmTimerResetRegistrants.notifyResult(new Boolean(true));
+ break;
+ case RESTART_ECM_TIMER:
+ long delayInMillis = SystemProperties.getLong(
+ TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+ h.postDelayed(mExitEcmRunnable, delayInMillis);
+ mEcmTimerResetRegistrants.notifyResult(new Boolean(false));
+ break;
+ default:
+ Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
+ }
+ }
+
+ /**
+ * Registration point for Ecm timer reset
+ * @param h handler to notify
+ * @param what User-defined message code
+ * @param obj placed in Message.obj
+ */
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ mEcmTimerResetRegistrants.addUnique(h, what, obj);
+ }
+
+ public void unregisterForEcmTimerReset(Handler h) {
+ mEcmTimerResetRegistrants.remove(h);
+ }
+
//***** Inner Classes
class MyHandler extends Handler {
MyHandler() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index be4763c..806c31d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -72,7 +72,8 @@
CdmaConnection pendingMO;
boolean hangupPendingMO;
- boolean pendingCallInECM=false;
+ boolean pendingCallInEcm=false;
+ boolean mIsInEmergencyCall = false;
CDMAPhone phone;
boolean desiredMute = false; // false = mute off
@@ -80,6 +81,7 @@
int pendingCallClirMode;
Phone.State state = Phone.State.IDLE;
+ private boolean mIsEcmTimerCanceled = false;
// boolean needsPoll;
@@ -182,6 +184,14 @@
throw new CallStateException("cannot dial in current state");
}
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ boolean isPhoneInEcmMode = inEcm.equals("true");
+ boolean isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(dialString);
+
+ // Cancel Ecm timer if a second emergency call is originating in Ecm mode
+ if (isPhoneInEcmMode && isEmergencyCall) {
+ handleEcmTimer(phone.CANCEL_ECM_TIMER);
+ }
// We are initiating a call therefore even if we previously
// didn't know the state (i.e. Generic was true) we now know
@@ -210,14 +220,17 @@
// Always unmute when initiating a new call
setMute(false);
- String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- if(inEcm.equals("false")) {
+ // Check data call
+ disableDataCallInEmergencyCall(dialString);
+
+ // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit.
+ if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
} else {
phone.exitEmergencyCallbackMode();
phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);
pendingCallClirMode=clirMode;
- pendingCallInECM=true;
+ pendingCallInEcm=true;
}
}
@@ -236,6 +249,9 @@
private Connection
dialThreeWay (String dialString) {
if (!foregroundCall.isIdle()) {
+ // Check data call
+ disableDataCallInEmergencyCall(dialString);
+
// Attach the new connection to foregroundCall
pendingMO = new CdmaConnection(phone.getContext(),
dialString, this, foregroundCall);
@@ -285,8 +301,14 @@
// Should we bother with this check?
if (ringingCall.getState() == CdmaCall.State.INCOMING) {
throw new CallStateException("cannot be in the incoming state");
- } else {
+ } else if (foregroundCall.getConnections().size() > 1) {
flashAndSetGenericTrue();
+ } else {
+ // Send a flash command to CDMA network for putting the other party on hold.
+ // For CDMA networks which do not support this the user would just hear a beep
+ // from the network. For CDMA networks which do support it will put the other
+ // party on hold.
+ cm.sendCDMAFeatureCode("", obtainMessage(EVENT_SWITCH_RESULT));
}
}
@@ -479,6 +501,11 @@
// Someone has already asked to hangup this call
if (hangupPendingMO) {
hangupPendingMO = false;
+ // Re-start Ecm timer when an uncompleted emergency call ends
+ if (mIsEcmTimerCanceled) {
+ handleEcmTimer(phone.RESTART_ECM_TIMER);
+ }
+
try {
if (Phone.DEBUG_PHONE) log(
"poll: hangupPendingMO, hangup conn " + i);
@@ -532,6 +559,14 @@
}
}
foregroundCall.setGeneric(false);
+
+ // Re-start Ecm timer when the connected emergency call ends
+ if (mIsEcmTimerCanceled) {
+ handleEcmTimer(phone.RESTART_ECM_TIMER);
+ } else {
+ mIsInEmergencyCall = false;
+ }
+
// Dropped connections are removed from the CallTracker
// list but kept in the Call list
connections[i] = null;
@@ -571,8 +606,8 @@
droppedDuringPoll.add(pendingMO);
pendingMO = null;
hangupPendingMO = false;
- if( pendingCallInECM) {
- pendingCallInECM = false;
+ if( pendingCallInEcm) {
+ pendingCallInEcm = false;
}
}
@@ -941,9 +976,9 @@
case EVENT_EXIT_ECM_RESPONSE_CDMA:
//no matter the result, we still do the same here
- if (pendingCallInECM) {
+ if (pendingCallInEcm) {
cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage());
- pendingCallInECM = false;
+ pendingCallInEcm = false;
}
phone.unsetOnEcbModeExitResponse(this);
break;
@@ -971,6 +1006,39 @@
}
}
+ /**
+ * Handle Ecm timer to be canceled or re-started
+ */
+ private void handleEcmTimer(int action) {
+ phone.handleTimerInEmergencyCallbackMode(action);
+ switch(action) {
+ case CDMAPhone.CANCEL_ECM_TIMER: mIsEcmTimerCanceled = true; break;
+ case CDMAPhone.RESTART_ECM_TIMER: mIsEcmTimerCanceled = false; break;
+ default:
+ Log.e(LOG_TAG, "handleEcmTimer, unsupported action " + action);
+ }
+ }
+
+ /**
+ * Disable data call when emergency call is connected
+ */
+ private void disableDataCallInEmergencyCall(String dialString) {
+ if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
+ phone.disableDataConnectivity();
+ mIsInEmergencyCall = true;
+ }
+ }
+
+ /**
+ * Check if current call is in emergency call
+ *
+ * @return true if it is in emergency call
+ * false if it is not in emergency call
+ */
+ boolean isInEmergencyCall() {
+ return mIsInEmergencyCall;
+ }
+
protected void log(String msg) {
Log.d(LOG_TAG, "[CdmaCallTracker] " + msg);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 38bc24d..2b78097 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -48,6 +48,7 @@
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyEventLog;
import java.util.ArrayList;
@@ -56,8 +57,7 @@
* {@hide}
*/
public final class CdmaDataConnectionTracker extends DataConnectionTracker {
- private static final String LOG_TAG = "CDMA";
- private static final boolean DBG = true;
+ protected final String LOG_TAG = "CDMA";
private CDMAPhone mCdmaPhone;
@@ -76,14 +76,9 @@
/** Currently active CdmaDataConnection */
private CdmaDataConnection mActiveDataConnection;
- /** Manage the behavior of data retry after failure */
- private final RetryManager mRetryMgr = new RetryManager();
-
- /** Defined cdma connection profiles */
- private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0;
- private static final int EXTERNAL_NETWORK_NUM_TYPES = 1;
-
- private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES];
+ private boolean mPendingRestartRadio = false;
+ private static final int TIME_DELAYED_TO_RESTART_RADIO =
+ SystemProperties.getInt("ro.cdma.timetoradiorestart", 20000);
/**
* Pool size of CdmaDataConnection objects.
@@ -103,6 +98,11 @@
private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1;
private static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
+ private static final String[] mSupportedApnTypes = {
+ Phone.APN_TYPE_DEFAULT,
+ Phone.APN_TYPE_MMS,
+ Phone.APN_TYPE_HIPRI };
+
// Possibly promoate to base class, the only difference is
// the INTENT_RECONNECT_ALARM action is a different string.
// Do consider technology changes if it is promoted.
@@ -163,6 +163,7 @@
p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null);
p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
+ p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null);
this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat"));
@@ -183,9 +184,12 @@
// and 2) whether the RIL will setup the baseband to auto-PS attach.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] =
+ dataEnabled[APN_DEFAULT_ID] =
!sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ enabledCount++;
+ }
+ noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
@@ -210,6 +214,7 @@
mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this);
mCdmaPhone.mSST.unregisterForRoamingOn(this);
mCdmaPhone.mSST.unregisterForRoamingOff(this);
+ phone.mCM.unregisterForCdmaOtaProvision(this);
phone.getContext().unregisterReceiver(this.mIntentReceiver);
destroyAllDataConnectionList();
@@ -219,7 +224,7 @@
if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized");
}
- void setState(State s) {
+ protected void setState(State s) {
if (DBG) log ("setState: " + s);
if (state != s) {
if (s == State.INITING) { // request Data connection context
@@ -236,39 +241,33 @@
state = s;
}
- public int enableApnType(String type) {
- // This request is mainly used to enable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to enableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_ALREADY_ACTIVE;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
- Log.w(LOG_TAG, "Phone.APN_TYPE_SUPL not enabled for CDMA");
- return Phone.APN_REQUEST_FAILED;
- } else {
- return Phone.APN_REQUEST_FAILED;
+ @Override
+ protected boolean isApnTypeActive(String type) {
+ return (isApnTypeAvailable(type) &&
+ mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
+ ServiceState.STATE_IN_SERVICE);
+ }
+
+ @Override
+ protected boolean isApnTypeAvailable(String type) {
+ for (String s : mSupportedApnTypes) {
+ if (TextUtils.equals(type, s)) {
+ return true;
+ }
}
+ return false;
}
- public int disableApnType(String type) {
- // This request is mainly used to disable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to disableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_REQUEST_STARTED;
- } else {
- return Phone.APN_REQUEST_FAILED;
+ protected String[] getActiveApnTypes() {
+ if (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
+ ServiceState.STATE_IN_SERVICE) {
+ return mSupportedApnTypes.clone();
}
+ return new String[0];
}
- private boolean isEnabled(int cdmaDataProfile) {
- return dataEnabled[cdmaDataProfile];
- }
-
- private void setEnabled(int cdmaDataProfile, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')');
- dataEnabled[cdmaDataProfile] = enable;
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]);
+ protected String getActiveApnString() {
+ return null;
}
/**
@@ -294,54 +293,6 @@
return true;
}
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * <p>This operation only affects the default connection
- * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
- * @return {@code true} if the operation succeeded
- */
- public boolean setDataEnabled(boolean enable) {
-
- boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID);
-
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true);
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- } else if (!enable) {
- setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false);
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- }
- return true;
- }
-
- /**
- * Report the current state of data connectivity (enabled or disabled)
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getDataEnabled() {
- return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
- }
-
- /**
- * Report on whether data connectivity is enabled
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) {
- if (isEnabled(i)) return true;
- }
- return false;
- }
-
private boolean isDataAllowed() {
boolean roaming = phone.getServiceState().getRoaming();
return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
@@ -371,7 +322,8 @@
&& (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
phone.getState() == Phone.State.IDLE )
&& isDataAllowed()
- && desiredPowerState) {
+ && desiredPowerState
+ && !mPendingRestartRadio) {
return setupData(reason);
@@ -387,7 +339,8 @@
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
" dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
- " desiredPowerState=" + desiredPowerState);
+ " desiredPowerState=" + desiredPowerState +
+ " PendingRestartRadio=" + mPendingRestartRadio);
}
return false;
}
@@ -498,16 +451,11 @@
}
protected void restartRadio() {
- Log.d(LOG_TAG, "************TURN OFF RADIO**************");
+ if (DBG) log("Cleanup connection and wait " +
+ (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio");
cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
- phone.mCM.setRadioPower(false, null);
- /* Note: no need to call setRadioPower(true). Assuming the desired
- * radio power state is still ON (as tracked by ServiceStateTracker),
- * ServiceStateTracker will call setRadioPower when it receives the
- * RADIO_STATE_CHANGED notification for the power off. And if the
- * desired power state has changed in the interim, we don't want to
- * override it with an unconditional power on.
- */
+ sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO);
+ mPendingRestartRadio = true;
}
private Runnable mPollNetStat = new Runnable() {
@@ -551,10 +499,10 @@
sentSinceLastRecv = 0;
newActivity = Activity.DATAIN;
} else if (sent == 0 && received == 0) {
- newActivity = Activity.NONE;
+ newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
} else {
sentSinceLastRecv = 0;
- newActivity = Activity.NONE;
+ newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
}
if (activity != newActivity) {
@@ -771,6 +719,20 @@
reason = (String) ar.userObj;
}
setState(State.IDLE);
+
+ // Since the pending request to turn off or restart radio will be processed here,
+ // remove the pending event to restart radio from the message queue.
+ if (mPendingRestartRadio) removeMessages(EVENT_RESTART_RADIO);
+
+ // Process the pending request to turn off radio in ServiceStateTracker first.
+ // If radio is turned off in ServiceStateTracker, ignore the pending event to restart radio.
+ CdmaServiceStateTracker ssTracker = mCdmaPhone.mSST;
+ if (ssTracker.processPendingRadioPowerOffAfterDataOff()) {
+ mPendingRestartRadio = false;
+ } else {
+ onRestartRadio();
+ }
+
phone.notifyDataConnection(reason);
if (retryAfterDisconnected(reason)) {
trySetupData(reason);
@@ -849,6 +811,37 @@
}
}
+ private void onCdmaOtaProvision(AsyncResult ar) {
+ if (ar.exception != null) {
+ int [] otaPrivision = (int [])ar.result;
+ if ((otaPrivision != null) && (otaPrivision.length > 1)) {
+ switch (otaPrivision[0]) {
+ case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED:
+ case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED:
+ mRetryMgr.resetRetryCount();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ private void onRestartRadio() {
+ if (mPendingRestartRadio) {
+ Log.d(LOG_TAG, "************TURN OFF RADIO**************");
+ phone.mCM.setRadioPower(false, null);
+ /* Note: no need to call setRadioPower(true). Assuming the desired
+ * radio power state is still ON (as tracked by ServiceStateTracker),
+ * ServiceStateTracker will call setRadioPower when it receives the
+ * RADIO_STATE_CHANGED notification for the power off. And if the
+ * desired power state has changed in the interim, we don't want to
+ * override it with an unconditional power on.
+ */
+ mPendingRestartRadio = false;
+ }
+ }
+
private void writeEventLogCdmaDataDrop() {
CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
int bsid = (loc != null) ? loc.getBaseStationId() : -1;
@@ -901,28 +894,28 @@
}
}
- String getInterfaceName() {
+ protected String getInterfaceName(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getInterface();
}
return null;
}
- protected String getIpAddress() {
+ protected String getIpAddress(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getIpAddress();
}
return null;
}
- String getGateway() {
+ protected String getGateway(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getGatewayAddress();
}
return null;
}
- protected String[] getDnsServers() {
+ protected String[] getDnsServers(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getDnsServers();
}
@@ -957,6 +950,15 @@
onDataStateChanged((AsyncResult) msg.obj);
break;
+ case EVENT_CDMA_OTA_PROVISION:
+ onCdmaOtaProvision((AsyncResult) msg.obj);
+ break;
+
+ case EVENT_RESTART_RADIO:
+ if (DBG) log("EVENT_RESTART_RADIO");
+ onRestartRadio();
+ break;
+
default:
// handle the message in the super class DataConnectionTracker
super.handleMessage(msg);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index b42cffd..b4de09b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -131,6 +131,8 @@
private boolean isEriTextLoaded = false;
private boolean isSubscriptionFromRuim = false;
+ private boolean mPendingRadioPowerOffAfterDataOff = false;
+
// Registration Denied Reason, General/Authentication Failure, used only for debugging purposes
private String mRegistrationDeniedReason;
@@ -520,6 +522,16 @@
}
break;
+ case EVENT_SET_RADIO_POWER_OFF:
+ synchronized(this) {
+ if (mPendingRadioPowerOffAfterDataOff) {
+ if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
+ cm.setRadioPower(false, null);
+ mPendingRadioPowerOffAfterDataOff = false;
+ }
+ }
+ break;
+
default:
Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
break;
@@ -548,20 +560,23 @@
msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
dcTracker.sendMessage(msg);
- // Poll data state up to 50 times, with a 100ms delay
- // totaling 5 sec.
- // TODO: change the 5 seconds wait from blocking to non-blocking.
- for (int i = 0; i < 50; i++) {
- DataConnectionTracker.State currentState = dcTracker.getState();
- if (currentState != DataConnectionTracker.State.CONNECTED
- && currentState != DataConnectionTracker.State.DISCONNECTING) {
- if (DBG) log("Data shutdown complete.");
- break;
+ synchronized(this) {
+ if (!mPendingRadioPowerOffAfterDataOff) {
+ DataConnectionTracker.State currentState = dcTracker.getState();
+ if (currentState != DataConnectionTracker.State.CONNECTED
+ && currentState != DataConnectionTracker.State.DISCONNECTING) {
+ if (DBG) log("Data disconnected, turn off radio right away.");
+ cm.setRadioPower(false, null);
+ }
+ else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 5000)) {
+ if (DBG) log("Wait 5 sec for data to be disconnected, then turn off radio.");
+ mPendingRadioPowerOffAfterDataOff = true;
+ } else {
+ Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
+ cm.setRadioPower(false, null);
+ }
}
- SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
}
- // If it's on and available and we want it off..
- cm.setRadioPower(false, null);
} // Otherwise, we're in the desired state
}
@@ -1582,4 +1597,22 @@
public boolean isMinInfoReady() {
return mIsMinInfoReady;
}
+
+ /**
+ * process the pending request to turn radio off after data is disconnected
+ *
+ * return true if there is pending request to process; false otherwise.
+ */
+ public boolean processPendingRadioPowerOffAfterDataOff() {
+ synchronized(this) {
+ if (mPendingRadioPowerOffAfterDataOff) {
+ if (DBG) log("Process pending request to turn radio off.");
+ removeMessages(EVENT_SET_RADIO_POWER_OFF);
+ cm.setRadioPower(false, null);
+ mPendingRadioPowerOffAfterDataOff = false;
+ return true;
+ }
+ return false;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 9c04305..1597427 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -29,6 +29,7 @@
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.util.HexDump;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -67,6 +68,7 @@
*/
public class SmsMessage extends SmsMessageBase {
static final String LOG_TAG = "CDMA";
+ private final static Boolean DBG_SMS = false;
/**
* Status of a previously submitted SMS.
@@ -541,6 +543,11 @@
return;
}
mBearerData = BearerData.decode(mEnvelope.bearerData);
+ if (DBG_SMS) {
+ Log.d(LOG_TAG, "MT raw BearerData = '" +
+ HexDump.toHexString(mEnvelope.bearerData) + "'");
+ Log.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData);
+ }
messageRef = mBearerData.messageId;
if (mBearerData.userData != null) {
userData = mBearerData.userData.payload;
@@ -644,14 +651,17 @@
bearerData.reportReq = false;
bearerData.userData = userData;
- bearerData.hasUserDataHeader = (userData.userDataHeader != null);
+
+ byte[] encodedBearerData = BearerData.encode(bearerData);
+ if (DBG_SMS) {
+ Log.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
+ Log.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
+ }
+ if (encodedBearerData == null) return null;
int teleservice = bearerData.hasUserDataHeader ?
SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
- byte[] encodedBearerData = BearerData.encode(bearerData);
- if (encodedBearerData == null) return null;
-
SmsEnvelope envelope = new SmsEnvelope();
envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
envelope.teleService = teleservice;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index fefeb12..721729d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -484,7 +484,7 @@
Gsm7bitCodingResult result = new Gsm7bitCodingResult();
result.data = new byte[fullData.length - 1];
System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
- result.septets = fullData[0];
+ result.septets = fullData[0] & 0x00FF;
return result;
} catch (com.android.internal.telephony.EncodeException ex) {
throw new CodingException("7bit GSM encode failed: " + ex);
@@ -498,6 +498,7 @@
int udhSeptets = ((udhBytes * 8) + 6) / 7;
Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ uData.msgEncodingSet = true;
uData.numFields = gcr.septets;
uData.payload = gcr.data;
uData.payload[0] = (byte)udhData.length;
@@ -512,6 +513,8 @@
int udhCodeUnits = (udhBytes + 1) / 2;
int udhPadding = udhBytes % 2;
int payloadCodeUnits = payload.length / 2;
+ uData.msgEncoding = UserData.ENCODING_UNICODE_16;
+ uData.msgEncodingSet = true;
uData.numFields = udhCodeUnits + payloadCodeUnits;
uData.payload = new byte[uData.numFields * 2];
uData.payload[0] = (byte)udhData.length;
@@ -606,14 +609,16 @@
* copies by passing outStream directly.
*/
encodeUserDataPayload(bData.userData);
+ bData.hasUserDataHeader = bData.userData.userDataHeader != null;
+
if (bData.userData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) {
throw new CodingException("encoded user data too large (" +
bData.userData.payload.length +
" > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
}
- /**
- * XXX/TODO: figure out what the right answer is WRT padding bits
+ /*
+ * TODO(cleanup): figure out what the right answer is WRT paddingBits field
*
* userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
* userData.paddingBits = 0; // XXX this seems better, but why?
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index 9b6e19d..d93852c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -154,7 +154,7 @@
builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset"));
builder.append(", msgType=" + msgType);
builder.append(", paddingBits=" + paddingBits);
- builder.append(", numFields=" + (int)numFields);
+ builder.append(", numFields=" + numFields);
builder.append(", userDataHeader=" + userDataHeader);
builder.append(", payload='" + HexDump.toHexString(payload) + "'");
builder.append(", payloadStr='" + payloadStr + "'");
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 94d4344..3c1308b 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -102,7 +102,6 @@
GsmCallTracker mCT;
GsmServiceStateTracker mSST;
GsmSMSDispatcher mSMS;
- GsmDataConnectionTracker mDataConnection;
SIMRecords mSIMRecords;
SimCard mSimCard;
StkService mStkService;
@@ -280,14 +279,6 @@
return "GSM";
}
- public String[] getActiveApnTypes() {
- return mDataConnection.getActiveApnTypes();
- }
-
- public String getActiveApn() {
- return mDataConnection.getActiveApnString();
- }
-
public SignalStrength getSignalStrength() {
return mSST.mSignalStrength;
}
@@ -1093,8 +1084,9 @@
}
/**
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
public void getPdpContextList(Message response) {
getDataCallList(response);
}
@@ -1104,8 +1096,9 @@
}
/**
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
public List<PdpConnection> getCurrentPdpList() {
ArrayList<DataConnection> connections = new ArrayList<DataConnection>();
ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>();
@@ -1145,38 +1138,10 @@
return mDataConnection.setDataEnabled(true);
}
- public int enableApnType(String type) {
- return mDataConnection.enableApnType(type);
- }
-
- public int disableApnType(String type) {
- return mDataConnection.disableApnType(type);
- }
-
public boolean disableDataConnectivity() {
return mDataConnection.setDataEnabled(false);
}
- public String getInterfaceName(String apnType) {
- return mDataConnection.getInterfaceName(apnType);
- }
-
- public String getIpAddress(String apnType) {
- return mDataConnection.getIpAddress(apnType);
- }
-
- public String getGateway(String apnType) {
- return mDataConnection.getGateway(apnType);
- }
-
- public String[] getDnsServers(String apnType) {
- return mDataConnection.getDnsServers(apnType);
- }
-
- public boolean isDataConnectivityEnabled() {
- return mDataConnection.getDataEnabled();
- }
-
/**
* The only circumstances under which we report that data connectivity is not
* possible are
@@ -1543,36 +1508,6 @@
}
}
}
- /**
- * simulateDataConnection
- *
- * simulates various data connection states. This messes with
- * DataConnectionTracker's internal states, but doesn't actually change
- * the underlying radio connection states.
- *
- * @param state Phone.DataState enum.
- */
- public void simulateDataConnection(Phone.DataState state) {
- DataConnectionTracker.State dcState;
-
- switch (state) {
- case CONNECTED:
- dcState = DataConnectionTracker.State.CONNECTED;
- break;
- case SUSPENDED:
- dcState = DataConnectionTracker.State.CONNECTED;
- break;
- case DISCONNECTED:
- dcState = DataConnectionTracker.State.FAILED;
- break;
- default:
- dcState = DataConnectionTracker.State.CONNECTING;
- break;
- }
-
- mDataConnection.setState(dcState);
- notifyDataConnection(null);
- }
/**
* Retrieves the PhoneSubInfo of the GSMPhone
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index bf60bfe..b9688f3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -63,8 +63,7 @@
* {@hide}
*/
public final class GsmDataConnectionTracker extends DataConnectionTracker {
- private static final String LOG_TAG = "GSM";
- private static final boolean DBG = true;
+ protected final String LOG_TAG = "GSM";
private GSMPhone mGsmPhone;
/**
@@ -96,8 +95,6 @@
private int mPdpResetCount = 0;
private boolean mIsScreenOn = true;
- private final RetryManager mRetryMgr = new RetryManager();
-
/** Delay between APN attempts */
protected static final int APN_DELAY_MILLIS = 5000;
@@ -121,31 +118,17 @@
private ApnSetting preferredApn = null;
+ /* Currently active APN */
+ protected ApnSetting mActiveApn;
+
/**
* pdpList holds all the PDP connection, i.e. IP Link in GPRS
*/
private ArrayList<DataConnection> pdpList;
- /** Currently requested APN type */
- private String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
-
- /** Currently active APN */
- private ApnSetting mActiveApn;
-
/** Currently active PdpConnection */
private PdpConnection mActivePdp;
- private static int APN_INVALID_ID = -1;
- private static int APN_DEFAULT_ID = 0;
- private static int APN_MMS_ID = 1;
- private static int APN_SUPL_ID = 2;
- private static int APN_DUN_ID = 3;
- private static int APN_HIPRI_ID = 4;
- private static int APN_NUM_TYPES = 5;
-
- private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
- private int enabledCount = 0;
-
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -295,7 +278,7 @@
if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized");
}
- void setState(State s) {
+ protected void setState(State s) {
if (DBG) log ("setState: " + s);
if (state != s) {
if (s == State.INITING) { // request PDP context
@@ -319,7 +302,7 @@
}
}
- String[] getActiveApnTypes() {
+ public String[] getActiveApnTypes() {
String[] result;
if (mActiveApn != null) {
result = mActiveApn.types;
@@ -338,87 +321,6 @@
return result;
}
- protected int apnTypeToId(String type) {
- if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
- return APN_DEFAULT_ID;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return APN_MMS_ID;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
- return APN_SUPL_ID;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
- return APN_DUN_ID;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
- return APN_HIPRI_ID;
- } else {
- return APN_INVALID_ID;
- }
- }
-
- /**
- * Ensure that we are connected to an APN of the specified type.
- * @param type the APN type (currently the only valid values
- * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
- * @return the result of the operation. Success is indicated by
- * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
- * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
- * will be sent by the ConnectivityManager when a connection to
- * the APN has been established.
- */
- protected int enableApnType(String type) {
- int id = apnTypeToId(type);
- if (id == APN_INVALID_ID) {
- return Phone.APN_REQUEST_FAILED;
- }
-
- // If already active, return
- if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
- + isApnTypeActive(type) + " and state = " + state);
- if (isApnTypeActive(type)) {
- if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
- else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
- }
-
- if (!isApnTypeAvailable(type)) {
- return Phone.APN_TYPE_NOT_AVAILABLE;
- }
-
- setEnabled(id, true);
- mRequestedApnType = type;
- sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
- return Phone.APN_REQUEST_STARTED;
- }
-
- /**
- * The APN of the specified type is no longer needed. Ensure that if
- * use of the default APN has not been explicitly disabled, we are connected
- * to the default APN.
- * @param type the APN type. The only valid values are currently
- * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
- * @return
- */
- protected int disableApnType(String type) {
- if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
- int id = apnTypeToId(type);
- if (id == APN_INVALID_ID) {
- return Phone.APN_REQUEST_FAILED;
- }
- if (isEnabled(id)) {
- setEnabled(id, false);
- if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (dataEnabled[APN_DEFAULT_ID]) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
/**
* The data connection is expected to be setup while device
* 1. has sim card
@@ -429,7 +331,7 @@
* @return false while no data connection if all above requirements are met.
*/
public boolean isDataConnectionAsDesired() {
- boolean roaming = phone.getServiceState().getRoaming();
+ boolean roaming = getDataRoaming();
if (mGsmPhone.mSIMRecords.getRecordsLoaded() &&
mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
@@ -441,12 +343,18 @@
return true;
}
- private boolean isApnTypeActive(String type) {
- // TODO: to support simultaneous, mActiveApn can be a List instead.
+ private boolean getDataRoaming() {
+ return mGsmPhone.mSST.getDataRoaming();
+ }
+
+ @Override
+ protected boolean isApnTypeActive(String type) {
+ // TODO: support simultaneous with List instead
return mActiveApn != null && mActiveApn.canHandleType(type);
}
- private boolean isApnTypeAvailable(String type) {
+ @Override
+ protected boolean isApnTypeAvailable(String type) {
if (allApns != null) {
for (ApnSetting apn : allApns) {
if (apn.canHandleType(type)) {
@@ -457,80 +365,6 @@
return false;
}
- private boolean isEnabled(int id) {
- if (id != APN_INVALID_ID) {
- return dataEnabled[id];
- }
- return false;
- }
-
- private void setEnabled(int id, boolean enable) {
- if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ')');
- if (dataEnabled[id] != enable) {
- dataEnabled[id] = enable;
-
- if (enable) {
- enabledCount++;
- } else {
- enabledCount--;
- }
-
- if (enabledCount == 0) {
- setPrivateDataEnabled(false);
- } else if (enabledCount == 1) {
- setPrivateDataEnabled(true);
- }
- }
- }
-
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * <p>This operation only affects the default APN, and if the same APN is
- * currently being used for MMS traffic, the teardown will not happen
- * even when {@code enable} is {@code false}.</p>
- * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
- * @return {@code true} if the operation succeeded
- */
- public boolean setDataEnabled(boolean enable) {
- if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")");
- setEnabled(APN_DEFAULT_ID, enable);
- return true;
- }
-
- private void setPrivateDataEnabled(boolean enable) {
- if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")");
- if (enable) {
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- } else {
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- }
- }
-
- /**
- * Report the current state of data connectivity (enabled or disabled) for
- * the default APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID];
- }
-
- /**
- * Report on whether data connectivity is enabled for any APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- return (enabledCount != 0);
- }
-
/**
* Formerly this method was ArrayList<PdpConnection> getAllPdps()
*/
@@ -540,7 +374,7 @@
}
private boolean isDataAllowed() {
- boolean roaming = phone.getServiceState().getRoaming();
+ boolean roaming = getDataRoaming();
return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
}
@@ -587,7 +421,7 @@
}
int gprsState = mGsmPhone.mSST.getCurrentGprsState();
- boolean roaming = phone.getServiceState().getRoaming();
+ boolean roaming = getDataRoaming();
boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState();
if ((state == State.IDLE || state == State.SCANNING)
@@ -746,7 +580,7 @@
return true;
}
- String getInterfaceName(String apnType) {
+ protected String getInterfaceName(String apnType) {
if (mActivePdp != null
&& (apnType == null || mActiveApn.canHandleType(apnType))) {
return mActivePdp.getInterface();
@@ -762,7 +596,7 @@
return null;
}
- String getGateway(String apnType) {
+ public String getGateway(String apnType) {
if (mActivePdp != null
&& (apnType == null || mActiveApn.canHandleType(apnType))) {
return mActivePdp.getGatewayAddress();
@@ -1244,16 +1078,38 @@
trySetupData(reason);
}
+ /**
+ * Check the data roaming consistency since this can be triggered by
+ * voice roaming flag of ServiceState in setDataOnRoamingEnabled()
+ *
+ * TODO make this triggered by data roaming state only
+ */
+ @Override
protected void onRoamingOff() {
- trySetupData(Phone.REASON_ROAMING_OFF);
+ if (!getDataRoaming()) { //data roaming is off
+ trySetupData(Phone.REASON_ROAMING_OFF);
+ } else { // Inconsistent! data roaming is on
+ sendMessage(obtainMessage(EVENT_ROAMING_ON));
+ }
}
+ /**
+ * Check the data roaming consistency since this can be triggered by
+ * voice roaming flag of ServiceState in setDataOnRoamingEnabled()
+ *
+ * TODO make this triggered by data roaming state only
+ */
+ @Override
protected void onRoamingOn() {
- if (getDataOnRoamingEnabled()) {
- trySetupData(Phone.REASON_ROAMING_ON);
- } else {
- if (DBG) log("Tear down data connection on roaming.");
- cleanUpConnection(true, Phone.REASON_ROAMING_ON);
+ if (getDataRoaming()) { // data roaming is on
+ if (getDataOnRoamingEnabled()) {
+ trySetupData(Phone.REASON_ROAMING_ON);
+ } else {
+ if (DBG) log("Tear down data connection on roaming.");
+ cleanUpConnection(true, Phone.REASON_ROAMING_ON);
+ }
+ } else { // Inconsistent! data roaming is off
+ sendMessage(obtainMessage(EVENT_ROAMING_OFF));
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 4178115..e7406e2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -88,6 +88,9 @@
private int newNetworkType = 0;
/* gsm roaming status solely based on TS 27.007 7.2 CREG */
private boolean mGsmRoaming = false;
+ /* data roaming status solely based on TS 27.007 10.1.19 CGREG */
+ private boolean mDataRoaming = false;
+ private boolean newDataRoaming = false;
private RegistrantList gprsAttachedRegistrants = new RegistrantList();
private RegistrantList gprsDetachedRegistrants = new RegistrantList();
@@ -311,6 +314,10 @@
psRestrictDisabledRegistrants.remove(h);
}
+ /*protected*/ boolean getDataRoaming() {
+ return mDataRoaming;
+ }
+
//***** Called from GSMPhone
public void
getLacAndCid(Message onComplete) {
@@ -668,7 +675,9 @@
}
}
newGPRSState = regCodeToServiceState(regState);
+ newDataRoaming = regCodeIsRoaming(regState);
newNetworkType = type;
+ newSS.setRadioTechnology(type);
break;
case EVENT_POLL_STATE_OPERATOR:
@@ -695,6 +704,11 @@
if (pollingContext[0] == 0) {
newSS.setRoaming(isRoamingBetweenOperators(mGsmRoaming, newSS));
+ // when both roaming indicators are true but not roaming between
+ // operators, roaming should set to false.
+ if (newDataRoaming && mGsmRoaming && !newSS.getRoaming()) {
+ newDataRoaming = false;
+ }
pollStateDone();
}
@@ -724,6 +738,7 @@
newCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
+ newDataRoaming = false;
pollStateDone();
break;
@@ -733,6 +748,7 @@
newCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
+ newDataRoaming = false;
pollStateDone();
break;
@@ -747,6 +763,8 @@
newCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
+ newDataRoaming = false;
+ mDataRoaming = false;
//NOTE: pollStateDone() is not needed in this case
break;
@@ -793,6 +811,15 @@
case DATA_ACCESS_UMTS:
ret = "UMTS";
break;
+ case DATA_ACCESS_HSDPA:
+ ret = "HSDPA";
+ break;
+ case DATA_ACCESS_HSUPA:
+ ret = "HSUPA";
+ break;
+ case DATA_ACCESS_HSPA:
+ ret = "HSPA";
+ break;
default:
Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type));
break;
@@ -831,9 +858,9 @@
boolean hasChanged = !newSS.equals(ss);
- boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
+ boolean hasRoamingOn = !mDataRoaming && newDataRoaming;
- boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
+ boolean hasRoamingOff = mDataRoaming && !newDataRoaming;
boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
@@ -850,6 +877,7 @@
gprsState = newGPRSState;
networkType = newNetworkType;
+ mDataRoaming = newDataRoaming;
newSS.setStateOutOfService(); // clean slate for next time
@@ -1270,7 +1298,7 @@
* that could support voice and data simultaniously.
*/
boolean isConcurrentVoiceAndData() {
- return (networkType == DATA_ACCESS_UMTS);
+ return (networkType >= DATA_ACCESS_UMTS);
}
/**
diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java
index 00440b43..358b7e9 100644
--- a/test-runner/android/test/AndroidTestRunner.java
+++ b/test-runner/android/test/AndroidTestRunner.java
@@ -158,7 +158,7 @@
mTestResult.addListener(testListener);
}
- Context testContext = mInstrumentation.getContext();
+ Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
for (TestCase testCase : mTestCases) {
setContextIfAndroidTestCase(testCase, mContext, testContext);
setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
@@ -180,14 +180,23 @@
private void setInstrumentationIfInstrumentationTestCase(
Test test, Instrumentation instrumentation) {
if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
- ((InstrumentationTestCase) test).injectInsrumentation(instrumentation);
+ ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
}
}
- public void setInstrumentaiton(Instrumentation instrumentation) {
+ public void setInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
+ /**
+ * @deprecated Incorrect spelling,
+ * use {@link #setInstrumentation(android.app.Instrumentation)} instead.
+ */
+ @Deprecated
+ public void setInstrumentaiton(Instrumentation instrumentation) {
+ setInstrumentation(instrumentation);
+ }
+
@Override
protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
return mContext.getClassLoader().loadClass(suiteClassName);
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index 6658fb0..23f0ed4 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -329,7 +329,7 @@
mTestRunner = getAndroidTestRunner();
mTestRunner.setContext(getTargetContext());
- mTestRunner.setInstrumentaiton(this);
+ mTestRunner.setInstrumentation(this);
mTestRunner.setSkipExecution(logOnly);
mTestRunner.setTest(testSuiteBuilder.build());
mTestCount = mTestRunner.getTestCases().size();
diff --git a/test-runner/android/test/ProviderTestCase.java b/test-runner/android/test/ProviderTestCase.java
index 445b4eb..668e9f7 100644
--- a/test-runner/android/test/ProviderTestCase.java
+++ b/test-runner/android/test/ProviderTestCase.java
@@ -15,6 +15,7 @@
* @deprecated this class extends InstrumentationTestCase but should extend AndroidTestCase. Use
* ProviderTestCase2, which corrects this problem, instead.
*/
+@Deprecated
public abstract class ProviderTestCase<T extends ContentProvider>
extends InstrumentationTestCase {
diff --git a/test-runner/android/test/TouchUtils.java b/test-runner/android/test/TouchUtils.java
index 52d2ee8..962b2f9 100644
--- a/test-runner/android/test/TouchUtils.java
+++ b/test-runner/android/test/TouchUtils.java
@@ -565,6 +565,7 @@
* {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
* configuring the Activity under test
*/
+ @Deprecated
public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
int deltaY) {
int[] xy = new int[2];
diff --git a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
index 6b8e1f0..1e4f161 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
@@ -28,7 +28,6 @@
import java.util.Arrays;
import java.util.Comparator;
-import java.util.Map;
public class AccountManagerServiceTest extends AndroidTestCase {
@Override
@@ -48,9 +47,9 @@
if (object1 == object2) return 0;
if (object1 == null) return 1;
if (object2 == null) return -1;
- int result = object1.mType.compareTo(object2.mType);
+ int result = object1.type.compareTo(object2.type);
if (result != 0) return result;
- return object1.mName.compareTo(object2.mName);
+ return object1.name.compareTo(object2.name);
}
}
@@ -62,16 +61,14 @@
Account a12 = new Account("account1", "type2");
Account a22 = new Account("account2", "type2");
Account a32 = new Account("account3", "type2");
- assertTrue(ams.addAccount(a11, "p11", null));
- assertTrue(ams.addAccount(a12, "p12", null));
- assertTrue(ams.addAccount(a21, "p21", null));
- assertTrue(ams.addAccount(a22, "p22", null));
- assertTrue(ams.addAccount(a31, "p31", null));
- assertTrue(ams.addAccount(a32, "p32", null));
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
+ ams.addAccount(a21, "p21", null);
+ ams.addAccount(a22, "p22", null);
+ ams.addAccount(a31, "p31", null);
+ ams.addAccount(a32, "p32", null);
- assertFalse("duplicate account insertion should fail", ams.addAccount(a32, "p", null));
-
- Account[] accounts = ams.getAccounts();
+ Account[] accounts = ams.getAccounts(null);
Arrays.sort(accounts, new AccountSorter());
assertEquals(6, accounts.length);
assertEquals(a11, accounts[0]);
@@ -88,7 +85,7 @@
assertEquals(a21, accounts[1]);
assertEquals(a31, accounts[2]);
- ams.removeAccount(a21);
+ ams.removeAccount(null, a21);
accounts = ams.getAccountsByType("type1" );
Arrays.sort(accounts, new AccountSorter());
@@ -101,8 +98,8 @@
AccountManagerService ams = new AccountManagerService(getContext());
Account a11 = new Account("account1", "type1");
Account a12 = new Account("account1", "type2");
- assertTrue(ams.addAccount(a11, "p11", null));
- assertTrue(ams.addAccount(a12, "p12", null));
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
assertEquals("p11", ams.getPassword(a11));
assertEquals("p12", ams.getPassword(a12));
@@ -125,8 +122,8 @@
u12.putString("a", "a_a12");
u12.putString("b", "b_a12");
u12.putString("c", "c_a12");
- assertTrue(ams.addAccount(a11, "p11", u11));
- assertTrue(ams.addAccount(a12, "p12", u12));
+ ams.addAccount(a11, "p11", u11);
+ ams.addAccount(a12, "p12", u12);
assertEquals("a_a11", ams.getUserData(a11, "a"));
assertEquals("b_a11", ams.getUserData(a11, "b"));
@@ -149,8 +146,8 @@
AccountManagerService ams = new AccountManagerService(getContext());
Account a11 = new Account("account1", "type1");
Account a12 = new Account("account1", "type2");
- assertTrue(ams.addAccount(a11, "p11", null));
- assertTrue(ams.addAccount(a12, "p12", null));
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
ams.setAuthToken(a11, "att1", "a11_att1");
ams.setAuthToken(a11, "att2", "a11_att2");
@@ -167,7 +164,7 @@
assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
ams.setAuthToken(a11, "att3", "a11_att3b");
- ams.invalidateAuthToken(a12.mType, "a12_att2");
+ ams.invalidateAuthToken(a12.type, "a12_att2");
assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
index af5562ad..7589ba8 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
@@ -19,11 +19,6 @@
import android.content.ContentValues;
import android.pim.vcard.ContactStruct;
import android.pim.vcard.EntryHandler;
-import android.pim.vcard.VCardBuilder;
-import android.pim.vcard.VCardBuilderCollection;
-import android.pim.vcard.VCardConfig;
-import android.pim.vcard.VCardDataBuilder;
-import android.pim.vcard.VCardParser;
import android.pim.vcard.VCardParser_V21;
import android.pim.vcard.VCardParser_V30;
import android.pim.vcard.exception.VCardException;
@@ -38,20 +33,21 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
public class VCardTests extends AndroidTestCase {
// TODO: Use EntityIterator, which is added in Eclair.
private static class EntryHolder implements EntryHandler {
public List<ContactStruct> contacts = new ArrayList<ContactStruct>();
+ public void onParsingStart() {
+ }
public void onEntryCreated(ContactStruct contactStruct) {
contacts.add(contactStruct);
}
- public void onFinal() {
+ public void onParsingEnd() {
}
}
-
+ /*
static void verify(ContactStruct expected, ContactStruct actual) {
if (!equalsString(expected.getName(), actual.getName())) {
fail(String.format("Names do not equal: \"%s\" != \"%s\"",
@@ -128,7 +124,7 @@
}
}
}
- }
+ }*/
private class PropertyNodesVerifier {
private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap;
@@ -189,6 +185,7 @@
}
}
+ /*
public void testV21SimpleCase1_1() throws IOException, VCardException {
VCardParser parser = new VCardParser_V21();
VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
@@ -260,7 +257,7 @@
verify(new ContactStruct("Ando Roid", null,
null, null, null, null, null, null),
actual);
- }
+ }*/
public void testV21BackslashCase() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
diff --git a/tests/BrowserTestPlugin/Android.mk b/tests/BrowserTestPlugin/Android.mk
new file mode 100644
index 0000000..968d9e6
--- /dev/null
+++ b/tests/BrowserTestPlugin/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+#
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build application
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BrowserTestPlugin
+
+LOCAL_JNI_SHARED_LIBRARIES := libtestplugin
+
+include $(BUILD_PACKAGE)
+
+# ============================================================
+
+# Also build all of the sub-targets under this one: the shared library.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/BrowserTestPlugin/AndroidManifest.xml b/tests/BrowserTestPlugin/AndroidManifest.xml
new file mode 100644
index 0000000..f071ab6
--- /dev/null
+++ b/tests/BrowserTestPlugin/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testplugin"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-permission android:name="android.webkit.permission.PLUGIN"/>
+
+ <uses-sdk android:minSdkVersion="3" />
+
+ <application android:icon="@drawable/browser_test_plugin"
+ android:label="Browser Test Plugin">
+ <service android:name="TestPlugin">
+ <intent-filter>
+ <action android:name="android.webkit.PLUGIN" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2 b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2
diff --git a/tests/BrowserTestPlugin/NOTICE b/tests/BrowserTestPlugin/NOTICE
new file mode 100644
index 0000000..9df2554
--- /dev/null
+++ b/tests/BrowserTestPlugin/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/tests/BrowserTestPlugin/jni/Android.mk b/tests/BrowserTestPlugin/jni/Android.mk
new file mode 100644
index 0000000..95a21e9
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/Android.mk
@@ -0,0 +1,49 @@
+##
+##
+## Copyright 2009, The Android Open Source Project
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ main.cpp \
+ PluginObject.cpp \
+ event/EventPlugin.cpp \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/event \
+ external/webkit/WebCore/bridge \
+ external/webkit/WebCore/plugins \
+ external/webkit/WebCore/platform/android/JavaVM \
+ external/webkit/WebKit/android/plugins
+
+LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE := libtestplugin
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.cpp b/tests/BrowserTestPlugin/jni/PluginObject.cpp
new file mode 100644
index 0000000..68fca60
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/PluginObject.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms. If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in
+ this original Apple software (the "Apple Software"), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software. Neither the name, trademarks, service marks
+ or logos of Apple Computer, Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "main.h"
+#include "PluginObject.h"
+
+static void pluginInvalidate(NPObject *obj);
+static bool pluginHasProperty(NPObject *obj, NPIdentifier name);
+static bool pluginHasMethod(NPObject *obj, NPIdentifier name);
+static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant);
+static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant);
+static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result);
+static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+static NPObject *pluginAllocate(NPP npp, NPClass *theClass);
+static void pluginDeallocate(NPObject *obj);
+static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name);
+static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count);
+
+
+
+static NPClass pluginClass = {
+ NP_CLASS_STRUCT_VERSION,
+ pluginAllocate,
+ pluginDeallocate,
+ pluginInvalidate,
+ pluginHasMethod,
+ pluginInvoke,
+ pluginInvokeDefault,
+ pluginHasProperty,
+ pluginGetProperty,
+ pluginSetProperty,
+ pluginRemoveProperty,
+ pluginEnumerate
+};
+
+NPClass *getPluginClass(void)
+{
+ return &pluginClass;
+}
+
+static bool identifiersInitialized = false;
+
+#define ID_TESTFILE_PROPERTY 0
+#define NUM_PROPERTY_IDENTIFIERS 1
+
+static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
+static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
+ "testfile"
+};
+
+#define ID_GETTESTFILE_METHOD 0
+#define NUM_METHOD_IDENTIFIERS 1
+
+static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
+static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
+ "getTestFile"
+};
+
+static void initializeIdentifiers(void)
+{
+ browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
+ browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
+}
+
+static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
+{
+ int i;
+ for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
+ if (name == pluginPropertyIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
+{
+ int i;
+ for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
+ if (name == pluginMethodIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant)
+{
+ PluginObject *plugin = (PluginObject *)obj;
+ if (name == pluginPropertyIdentifiers[ID_TESTFILE_PROPERTY]) {
+ BOOLEAN_TO_NPVARIANT(true, *variant);
+ return true;
+ }
+ return false;
+}
+
+static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant)
+{
+ return false;
+}
+
+static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+ PluginObject *plugin = (PluginObject *)obj;
+ if (name == pluginMethodIdentifiers[ID_GETTESTFILE_METHOD]) {
+ return true;
+ }
+ return false;
+}
+
+static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+ return false;
+}
+
+static void pluginInvalidate(NPObject *obj)
+{
+ // Release any remaining references to JavaScript objects.
+}
+
+static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
+{
+ PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject));
+ newInstance->header._class = theClass;
+ newInstance->header.referenceCount = 1;
+
+ if (!identifiersInitialized) {
+ identifiersInitialized = true;
+ initializeIdentifiers();
+ }
+
+ newInstance->npp = npp;
+
+ return &newInstance->header;
+}
+
+static void pluginDeallocate(NPObject *obj)
+{
+ free(obj);
+}
+
+static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name)
+{
+ return false;
+}
+
+static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+ return false;
+}
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.h b/tests/BrowserTestPlugin/jni/PluginObject.h
new file mode 100644
index 0000000..a058d4a
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/PluginObject.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms. If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in
+ this original Apple software (the "Apple Software"), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software. Neither the name, trademarks, service marks
+ or logos of Apple Computer, Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginObject__DEFINED
+#define PluginObject__DEFINED
+
+#include "main.h"
+
+class SubPlugin {
+public:
+ SubPlugin(NPP inst) : m_inst(inst) {}
+ virtual ~SubPlugin() {}
+ virtual int16 handleEvent(const ANPEvent* evt) = 0;
+
+ NPP inst() const { return m_inst; }
+
+private:
+ NPP m_inst;
+};
+
+typedef struct PluginObject {
+ NPObject header;
+ NPP npp;
+ NPWindow* window;
+
+ SubPlugin* subPlugin;
+
+} PluginObject;
+
+NPClass *getPluginClass(void);
+
+#endif // PluginObject__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
new file mode 100644
index 0000000..1263204
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "EventPlugin.h"
+#include "android_npapi.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+extern NPNetscapeFuncs* browser;
+extern ANPCanvasInterfaceV0 gCanvasI;
+extern ANPLogInterfaceV0 gLogI;
+extern ANPPaintInterfaceV0 gPaintI;
+extern ANPSurfaceInterfaceV0 gSurfaceI;
+extern ANPTypefaceInterfaceV0 gTypefaceI;
+
+///////////////////////////////////////////////////////////////////////////////
+
+EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) {
+
+ // initialize the drawing surface
+ m_surfaceReady = false;
+ m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false);
+ if(!m_surface)
+ gLogI.log(inst, kError_ANPLogType, "----%p Unable to create Raster surface", inst);
+}
+
+EventPlugin::~EventPlugin() {
+ gSurfaceI.deleteSurface(m_surface);
+}
+
+void EventPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) {
+
+ gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)", inst(), surfaceWidth, surfaceHeight);
+
+ // get the plugin's dimensions according to the DOM
+ PluginObject *obj = (PluginObject*) inst()->pdata;
+ const int W = obj->window->width;
+ const int H = obj->window->height;
+
+ // compute the current zoom level
+ const float zoomFactorW = static_cast<float>(surfaceWidth) / W;
+ const float zoomFactorH = static_cast<float>(surfaceHeight) / H;
+
+ // check to make sure the zoom level is uniform
+ if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH)
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p zoom is out of sync (%f,%f)",
+ inst(), zoomFactorW, zoomFactorH);
+
+ // scale the variables based on the zoom level
+ const int fontSize = (int)(zoomFactorW * 16);
+ const int leftMargin = (int)(zoomFactorW * 10);
+
+ // lock the surface
+ ANPBitmap bitmap;
+ if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) {
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst());
+ return;
+ }
+
+ // create a canvas
+ ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
+ gCanvasI.drawColor(canvas, 0xFFFFFFFF);
+
+ // configure the paint
+ ANPPaint* paint = gPaintI.newPaint();
+ gPaintI.setFlags(paint, gPaintI.getFlags(paint) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(paint, 0xFF0000FF);
+ gPaintI.setTextSize(paint, fontSize);
+
+ // configure the font
+ ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
+ gPaintI.setTypeface(paint, tf);
+ gTypefaceI.unref(tf);
+
+ // retrieve the font metrics
+ ANPFontMetrics fm;
+ gPaintI.getFontMetrics(paint, &fm);
+
+ // write text on the canvas
+ const char c[] = "Browser Test Plugin";
+ gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint);
+
+ // clean up variables and unlock the surface
+ gPaintI.deletePaint(paint);
+ gCanvasI.deleteCanvas(canvas);
+ gSurfaceI.unlock(m_surface);
+}
+
+void EventPlugin::printToDiv(const char* text, int length) {
+ // Get the plugin's DOM object
+ NPObject* windowObject = NULL;
+ browser->getvalue(inst(), NPNVWindowNPObject, &windowObject);
+
+ if (!windowObject)
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", inst());
+
+ // create a string (JS code) that is stored in memory allocated by the browser
+ const char* jsBegin = "var outputDiv = document.getElementById('eventOutput'); outputDiv.innerHTML += ' ";
+ const char* jsEnd = "';";
+
+ // allocate memory and configure pointers
+ int totalLength = strlen(jsBegin) + length + strlen(jsEnd);
+ char* beginMem = (char*)browser->memalloc(totalLength);
+ char* middleMem = beginMem + strlen(jsBegin);
+ char* endMem = middleMem + length;
+
+ // copy into the allocated memory
+ memcpy(beginMem, jsBegin, strlen(jsBegin));
+ memcpy(middleMem, text, length);
+ memcpy(endMem, jsEnd, strlen(jsEnd));
+
+ gLogI.log(inst(), kError_ANPLogType, "text: %.*s\n", totalLength, (char*)beginMem);
+
+ // execute the javascript in the plugin's DOM object
+ NPString script = { (char*)beginMem, totalLength };
+ NPVariant scriptVariant;
+ if (!browser->evaluate(inst(), windowObject, &script, &scriptVariant))
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to eval the JS.", inst());
+
+ // free the memory allocated within the browser
+ browser->memfree(beginMem);
+}
+
+int16 EventPlugin::handleEvent(const ANPEvent* evt) {
+ switch (evt->eventType) {
+ case kDraw_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst());
+ break;
+ case kSurface_ANPEventType:
+ switch (evt->data.surface.action) {
+ case kCreated_ANPSurfaceAction:
+ m_surfaceReady = true;
+ return 1;
+ case kDestroyed_ANPSurfaceAction:
+ m_surfaceReady = false;
+ return 1;
+ case kChanged_ANPSurfaceAction:
+ drawPlugin(evt->data.surface.data.changed.width,
+ evt->data.surface.data.changed.height);
+ return 1;
+ }
+ break;
+ case kLifecycle_ANPEventType:
+ switch (evt->data.lifecycle.action) {
+ case kOnLoad_ANPLifecycleAction: {
+ char msg[] = "lifecycle-onLoad";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ case kGainFocus_ANPLifecycleAction: {
+ char msg[] = "lifecycle-gainFocus";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ case kLoseFocus_ANPLifecycleAction: {
+ char msg[] = "lifecycle-loseFocus";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ }
+ return 1;
+ case kTouch_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request touch events", inst());
+ break;
+ case kKey_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request key events", inst());
+ break;
+ default:
+ break;
+ }
+ return 0; // unknown or unhandled event
+}
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
new file mode 100644
index 0000000..73dd6ea
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginObject.h"
+
+#ifndef eventPlugin__DEFINED
+#define eventPlugin__DEFINED
+
+class EventPlugin : public SubPlugin {
+public:
+ EventPlugin(NPP inst);
+ virtual ~EventPlugin();
+ virtual int16 handleEvent(const ANPEvent* evt);
+
+private:
+ void drawPlugin(int surfaceWidth, int surfaceHeight);
+ void printToDiv(const char* text, int length);
+
+ bool m_surfaceReady;
+ ANPSurface* m_surface;
+};
+
+#endif // eventPlugin__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp
new file mode 100644
index 0000000..056ec4d
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/main.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "android_npapi.h"
+#include "main.h"
+#include "PluginObject.h"
+#include "EventPlugin.h"
+
+NPNetscapeFuncs* browser;
+#define EXPORT __attribute__((visibility("default")))
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData* saved);
+NPError NPP_Destroy(NPP instance, NPSavedData** save);
+NPError NPP_SetWindow(NPP instance, NPWindow* window);
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
+int32 NPP_WriteReady(NPP instance, NPStream* stream);
+int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
+ void* buffer);
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
+void NPP_Print(NPP instance, NPPrint* platformPrint);
+int16 NPP_HandleEvent(NPP instance, void* event);
+void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
+ void* notifyData);
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+
+extern "C" {
+EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context);
+EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value);
+EXPORT const char* NP_GetMIMEDescription(void);
+EXPORT void NP_Shutdown(void);
+};
+
+ANPAudioTrackInterfaceV0 gSoundI;
+ANPBitmapInterfaceV0 gBitmapI;
+ANPCanvasInterfaceV0 gCanvasI;
+ANPLogInterfaceV0 gLogI;
+ANPPaintInterfaceV0 gPaintI;
+ANPPathInterfaceV0 gPathI;
+ANPSurfaceInterfaceV0 gSurfaceI;
+ANPSystemInterfaceV0 gSystemI;
+ANPTypefaceInterfaceV0 gTypefaceI;
+ANPWindowInterfaceV0 gWindowI;
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
+
+NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context)
+{
+ // Make sure we have a function table equal or larger than we are built against.
+ if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // Copy the function table (structure)
+ browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
+ memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
+
+ // Build the plugin function table
+ pluginFuncs->version = 11;
+ pluginFuncs->size = sizeof(pluginFuncs);
+ pluginFuncs->newp = NPP_New;
+ pluginFuncs->destroy = NPP_Destroy;
+ pluginFuncs->setwindow = NPP_SetWindow;
+ pluginFuncs->newstream = NPP_NewStream;
+ pluginFuncs->destroystream = NPP_DestroyStream;
+ pluginFuncs->asfile = NPP_StreamAsFile;
+ pluginFuncs->writeready = NPP_WriteReady;
+ pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
+ pluginFuncs->print = NPP_Print;
+ pluginFuncs->event = NPP_HandleEvent;
+ pluginFuncs->urlnotify = NPP_URLNotify;
+ pluginFuncs->getvalue = NPP_GetValue;
+ pluginFuncs->setvalue = NPP_SetValue;
+
+ static const struct {
+ NPNVariable v;
+ uint32_t size;
+ ANPInterface* i;
+ } gPairs[] = {
+ { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
+ { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI },
+ { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
+ { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
+ { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
+ { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
+ { kSurfaceInterfaceV0_ANPGetValue, sizeof(gSurfaceI), &gSurfaceI },
+ { kSystemInterfaceV0_ANPGetValue, sizeof(gSystemI), &gSystemI },
+ { kTypefaceInterfaceV0_ANPGetValue, sizeof(gTypefaceI), &gTypefaceI },
+ { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI },
+ };
+ for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
+ gPairs[i].i->inSize = gPairs[i].size;
+ NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
+ if (err) {
+ return err;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void NP_Shutdown(void)
+{
+
+}
+
+const char *NP_GetMIMEDescription(void)
+{
+ return "application/x-browsertestplugin:btp:Android Browser Test Plugin";
+}
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData* saved)
+{
+
+
+ gLogI.log(instance, kDebug_ANPLogType, "creating plugin");
+
+ PluginObject *obj = NULL;
+
+ // Scripting functions appeared in NPAPI version 14
+ if (browser->version >= 14) {
+ instance->pdata = browser->createobject (instance, getPluginClass());
+ obj = static_cast<PluginObject*>(instance->pdata);
+ bzero(obj, sizeof(*obj));
+ } else {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // select the drawing model
+ ANPDrawingModel model = kSurface_ANPDrawingModel;
+
+ // notify the plugin API of the drawing model we wish to use. This must be
+ // done prior to creating certain subPlugin objects (e.g. surfaceViews)
+ NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
+ reinterpret_cast<void*>(model));
+ if (err) {
+ gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err);
+ return err;
+ }
+
+ // create the sub-plugin
+ obj->subPlugin = new EventPlugin(instance);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save)
+{
+ PluginObject *obj = (PluginObject*) instance->pdata;
+ delete obj->subPlugin;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window)
+{
+ PluginObject *obj = (PluginObject*) instance->pdata;
+
+ // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
+ if (obj != NULL) {
+ obj->window = window;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
+{
+ *stype = NP_ASFILEONLY;
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
+{
+ return NPERR_NO_ERROR;
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream* stream)
+{
+ return 0;
+}
+
+int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
+{
+ return 0;
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
+{
+}
+
+void NPP_Print(NPP instance, NPPrint* platformPrint)
+{
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event)
+{
+ PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
+ const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
+
+ if(!obj->subPlugin) {
+ gLogI.log(instance, kError_ANPLogType, "the sub-plugin is null.");
+ return 0; // unknown or unhandled event
+ }
+ else {
+ return obj->subPlugin->handleEvent(evt);
+ }
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+}
+
+EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
+
+ if (variable == NPPVpluginNameString) {
+ const char **str = (const char **)value;
+ *str = "Browser Test Plugin";
+ return NPERR_NO_ERROR;
+ }
+
+ if (variable == NPPVpluginDescriptionString) {
+ const char **str = (const char **)value;
+ *str = "Description of Browser Test Plugin";
+ return NPERR_NO_ERROR;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+ if (variable == NPPVpluginScriptableNPObject) {
+ void **v = (void **)value;
+ PluginObject *obj = (PluginObject*) instance->pdata;
+
+ if (obj)
+ browser->retainobject((NPObject*)obj);
+
+ *v = obj;
+ return NPERR_NO_ERROR;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+ return NPERR_GENERIC_ERROR;
+}
+
diff --git a/tests/BrowserTestPlugin/jni/main.h b/tests/BrowserTestPlugin/jni/main.h
new file mode 100644
index 0000000..e6e8c73
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/main.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <npapi.h>
+#include <npfunctions.h>
+#include <npruntime.h>
+#include "android_npapi.h"
+
+extern NPNetscapeFuncs* browser;
diff --git a/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png
new file mode 100755
index 0000000..47c79d1
--- /dev/null
+++ b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png
Binary files differ
diff --git a/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java
new file mode 100644
index 0000000..94a18fd
--- /dev/null
+++ b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java
@@ -0,0 +1,15 @@
+package com.android.testplugin;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class TestPlugin extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tests/CoreTests/android/core/RecurrenceSetTest.java b/tests/CoreTests/android/core/RecurrenceSetTest.java
new file mode 100644
index 0000000..cee324c
--- /dev/null
+++ b/tests/CoreTests/android/core/RecurrenceSetTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.core;
+
+import android.content.ContentValues;
+import android.pim.ICalendar;
+import android.pim.RecurrenceSet;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.provider.Calendar;
+import junit.framework.TestCase;
+
+/**
+ * Test some pim.RecurrenceSet functionality.
+ */
+public class RecurrenceSetTest extends TestCase {
+
+ // Test a recurrence
+ @SmallTest
+ public void testRecurrenceSet0() throws Exception {
+ String recurrence = "DTSTART;TZID=America/New_York:20080221T070000\n"
+ + "DTEND;TZID=America/New_York:20080221T190000\n"
+ + "RRULE:FREQ=DAILY;UNTIL=20080222T000000Z\n"
+ + "EXDATE:20080222T120000Z";
+ verifyPopulateContentValues(recurrence, "FREQ=DAILY;UNTIL=20080222T000000Z", null,
+ null, "20080222T120000Z", 1203595200000L, "America/New_York", "P43200S", 0);
+ }
+
+ // Test 1 day all-day event
+ @SmallTest
+ public void testRecurrenceSet1() throws Exception {
+ String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090822\n"
+ + "RRULE:FREQ=YEARLY;WKST=SU";
+ verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
+ null, null, 1250812800000L, null, "P1D", 1);
+ }
+
+ // Test 2 day all-day event
+ @SmallTest
+ public void testRecurrenceSet2() throws Exception {
+ String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090823\n"
+ + "RRULE:FREQ=YEARLY;WKST=SU";
+ verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
+ null, null, 1250812800000L, null, "P2D", 1);
+ }
+
+ // run populateContentValues and verify the results
+ private void verifyPopulateContentValues(String recurrence, String rrule, String rdate,
+ String exrule, String exdate, long dtstart, String tzid, String duration, int allDay)
+ throws ICalendar.FormatException {
+ ICalendar.Component recurrenceComponent =
+ new ICalendar.Component("DUMMY", null /* parent */);
+ ICalendar.parseComponent(recurrenceComponent, recurrence);
+ ContentValues values = new ContentValues();
+ RecurrenceSet.populateContentValues(recurrenceComponent, values);
+ Log.d("KS", "values " + values);
+
+ assertEquals(rrule, values.get(android.provider.Calendar.Events.RRULE));
+ assertEquals(rdate, values.get(android.provider.Calendar.Events.RDATE));
+ assertEquals(exrule, values.get(android.provider.Calendar.Events.EXRULE));
+ assertEquals(exdate, values.get(android.provider.Calendar.Events.EXDATE));
+ assertEquals(dtstart, (long) values.getAsLong(Calendar.Events.DTSTART));
+ assertEquals(tzid, values.get(android.provider.Calendar.Events.EVENT_TIMEZONE));
+ assertEquals(duration, values.get(android.provider.Calendar.Events.DURATION));
+ assertEquals(allDay,
+ (int) values.getAsInteger(android.provider.Calendar.Events.ALL_DAY));
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 466b555..7426d33 100644
--- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -338,7 +338,7 @@
@SmallTest
public void testCheckAndProcessPlusCode() {
- assertEquals("8475797000",
+ assertEquals("0118475797000",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000"));
assertEquals("18475797000",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000"));
@@ -350,18 +350,18 @@
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800"));
assertEquals("8475797000,18475231753",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753"));
- assertEquals("8475797000,18475231753",
+ assertEquals("0118475797000,18475231753",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753"));
- assertEquals("8475797000;8475231753",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8475231753"));
+ assertEquals("8475797000;0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8469312345"));
assertEquals("8475797000,0111234567",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+1234567"));
assertEquals("847597000;01111875767000",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847597000;+11875767000"));
- assertEquals("8475797000,,8475231753",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8475231753"));
- assertEquals("8475797000;,8475231753",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8475231753"));
+ assertEquals("8475797000,,0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8469312345"));
+ assertEquals("8475797000;,0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8469312345"));
assertEquals("8475797000,;18475231753",
PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753"));
assertEquals("8475797000;,01111875767000",
@@ -391,17 +391,20 @@
@SmallTest
public void testCheckAndProcessPlusCodeByNumberFormat() {
- assertEquals("+8475797000",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+8475797000",
- PhoneNumberUtils.FORMAT_JAPAN));
- assertEquals("+0384756700",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+0384756700",
- PhoneNumberUtils.FORMAT_JAPAN));
- assertEquals("+1234567",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+1234567",
- PhoneNumberUtils.FORMAT_UNKNOWN));
- assertEquals("+23456700000",
- PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+23456700000",
- PhoneNumberUtils.FORMAT_UNKNOWN));
+ assertEquals("18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_NANP));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_JAPAN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_UNKNOWN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_JAPAN,PhoneNumberUtils.FORMAT_JAPAN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_UNKNOWN,PhoneNumberUtils.FORMAT_UNKNOWN));
}
}
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index 49165d0..c056de5 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -22,7 +22,7 @@
use --refresh-test-list option *once* to re-generate test list on the card.
Some other options are:
- --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
+ --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
--time-out-ms (default is 8000 millis) for each test
--adb-options="-e" passes option string to adb
--results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
@@ -51,11 +51,11 @@
def DumpRenderTreeFinished(adb_cmd):
""" Check if DumpRenderTree finished running tests
-
+
Args:
output: adb_cmd string
"""
-
+
# pull /sdcard/android/running_test.txt, if the content is "#DONE", it's done
shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
@@ -69,7 +69,7 @@
"""
old_file = open(old_results, "r")
new_file = open(new_results, "r")
- diff_file = open(diff_results, "a")
+ diff_file = open(diff_results, "a")
# Read lines from each file
ndict = new_file.readlines()
@@ -122,7 +122,7 @@
"""
logging.info("Comparing results to " + ref_dir)
- diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
+ diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
if os.path.exists(diff_result):
os.remove(diff_result)
@@ -136,7 +136,7 @@
def main(options, args):
"""Run the tests. Will call sys.exit when complete.
-
+
Args:
options: a dictionary of command line options
args: a list of sub directories or files to test
@@ -198,7 +198,7 @@
shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
-
+
logging.info(crashed_test + " CRASHED");
crashed_tests.append(crashed_test);
@@ -226,14 +226,15 @@
result_files = ["/sdcard/layout_tests_passed.txt",
"/sdcard/layout_tests_failed.txt",
"/sdcard/layout_tests_nontext.txt"]
- for file in result_files:
+ for file in result_files:
shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
logging.debug(adb_output)
-
+
# Create the crash list.
fp = open(results_dir + "/layout_tests_crashed.txt", "w");
- fp.writelines('\n'.join(crashed_tests))
+ for crashed_test in crashed_tests:
+ fp.writelines(crashed_test + '\n')
fp.close()
# Count the number of tests in each category.
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index 97a8b25..f33b01d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -18,6 +18,7 @@
import android.os.Handler;
import android.os.Message;
+import android.webkit.MockGeolocation;
import android.webkit.WebStorage;
import java.util.HashMap;
@@ -60,6 +61,7 @@
private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
+ private static final int SET_GEOLOCATION_PERMISSION = 43;
CallbackProxy(EventSender eventSender,
LayoutTestController layoutTestController) {
@@ -201,6 +203,11 @@
case LAYOUT_SET_CAN_OPEN_WINDOWS:
mLayoutTestController.setCanOpenWindows();
break;
+
+ case SET_GEOLOCATION_PERMISSION:
+ mLayoutTestController.setGeolocationPermission(
+ msg.arg1 == 1 ? true : false);
+ break;
}
}
@@ -325,7 +332,7 @@
}
public void setWindowIsKey(boolean b) {
- obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget();
+ obtainMessage(LAYOUT_SET_WINDOW_KEY, b ? 1 : 0, 0).sendToTarget();
}
public void testRepaint() {
@@ -352,4 +359,19 @@
obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
}
+ public void setMockGeolocationPosition(double latitude,
+ double longitude,
+ double accuracy) {
+ MockGeolocation.getInstance().setPosition(latitude,
+ longitude,
+ accuracy);
+ }
+
+ public void setMockGeolocationError(int code, String message) {
+ MockGeolocation.getInstance().setError(code, message);
+ }
+
+ public void setGeolocationPermission(boolean allow) {
+ obtainMessage(SET_GEOLOCATION_PERMISSION, allow ? 1 : 0, 0).sendToTarget();
+ }
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index ede5197..8fea967 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -79,7 +79,8 @@
"profiler", // profiler is not supported
"svg", // svg is not supported
"platform", // platform specific
- "http" // requires local http(s) server
+ "http", // requires local http(s) server
+ "fast/workers",
};
static final String [] ignoreTestList = {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index e1d802a..f535ed7 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -62,4 +62,7 @@
// For storage tests
public void dumpDatabaseCallbacks();
public void setCanOpenWindows();
+
+ // For Geolocation tests
+ public void setGeolocationPermission(boolean allow);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index e060388..e342efb 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -28,6 +28,7 @@
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup;
+import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
@@ -425,6 +426,14 @@
mCanOpenWindows = true;
}
+ /**
+ * Sets the Geolocation permission state to be used for all future requests.
+ */
+ public void setGeolocationPermission(boolean allow) {
+ mGeolocationPermissionSet = true;
+ mGeolocationPermission = allow;
+ }
+
private final WebViewClient mViewClient = new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
@@ -543,7 +552,8 @@
@Override
public void onExceededDatabaseQuota(String url_str,
- String databaseIdentifier, long currentQuota, long totalUsedQuota,
+ String databaseIdentifier, long currentQuota,
+ long estimatedSize, long totalUsedQuota,
WebStorage.QuotaUpdater callback) {
if (mDumpDatabaseCallbacks) {
if (mDatabaseCallbackStrings == null) {
@@ -575,6 +585,18 @@
callback.updateQuota(currentQuota + 1024 * 1024 * 5);
}
+ /**
+ * Instructs the client to show a prompt to ask the user to set the
+ * Geolocation permission state for the specified origin.
+ */
+ @Override
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ if (mGeolocationPermissionSet) {
+ callback.invoke(origin, mGeolocationPermission, false);
+ }
+ }
+
@Override
public void addMessageToConsole(String message, int lineNumber,
String sourceID) {
@@ -687,4 +709,7 @@
static final String RESULT_FILE = "ResultFile";
static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
static final String UI_AUTO_TEST = "UiAutoTest";
+
+ private boolean mGeolocationPermissionSet;
+ private boolean mGeolocationPermission;
}
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index 42c1e78..a8af7f8 100644
--- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -74,8 +74,8 @@
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
if (syncAccount != null) {
- values.put("_sync_account", syncAccount.mName);
- values.put("_sync_account_type", syncAccount.mType);
+ values.put("_sync_account", syncAccount.name);
+ values.put("_sync_account_type", syncAccount.type);
}
values.put("_sync_local_id", syncLocalId);
values.put("_sync_dirty", 0);
@@ -88,8 +88,8 @@
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
if (syncAccount != null) {
- values.put("_sync_account", syncAccount.mName);
- values.put("_sync_account_type", syncAccount.mType);
+ values.put("_sync_account", syncAccount.name);
+ values.put("_sync_account_type", syncAccount.type);
}
if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
return values;
diff --git a/tests/backup/backup_stress_test.sh b/tests/backup/backup_stress_test.sh
new file mode 100755
index 0000000..8155507
--- /dev/null
+++ b/tests/backup/backup_stress_test.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# 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.
+
+iterations=150
+failures=0
+i=0
+LOGDIR="$HOME/backup_tests"
+LOGFILE="$LOGDIR/backup_stress.`date +%s`.log"
+export BUGREPORT_DIR="$LOGDIR/bugreports"
+
+# make sure that we have a place to put logs and bugreports
+mkdir -p $LOGDIR $BUGREPORT_DIR
+
+echo "logfile is $LOGFILE"
+
+(while (sleep 10); do
+ failed=0
+
+ echo
+ echo "Iteration $i at `date`"
+ echo
+
+ ./test_backup.sh "$@" 2>&1
+
+ sleep 10
+ echo "Restore at `date`"
+ echo
+
+ ./test_restore.sh "$@" 2>&1 || failed=1
+
+ if [ "$failed" -ne 0 ]; then
+ failures=$(($failures+1))
+ # Long and verbose so it sticks out
+ echo "FAILED iteration $i of $iterations; $failures failures so far"
+ echo "FAILED iteration $i of $iterations; $failures failures so far" > /dev/stderr
+ else
+ printf "Iteration %d:\tPASS; remaining: %d\n" $i $(($iterations - $i - 1))
+ printf "Iteration %d:\tPASS; remaining: %d\n" $i $(($iterations - $i - 1)) > /dev/stderr
+ fi
+
+ echo "End $i at `date`"
+
+ i=$(($i+1))
+ if [ $i -eq $iterations ]; then
+ echo "DONE: $iterations iterations with $failures failures."
+ echo "DONE: $iterations iterations with $failures failures." > /dev/stderr
+ [ "$failures" -eq 0 ] && exit 0
+ exit 1
+ fi
+done) > "$LOGFILE"
+
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
index 4506c16..46b46e4 100755
--- a/tests/backup/test_restore.sh
+++ b/tests/backup/test_restore.sh
@@ -18,7 +18,7 @@
#export DRY_RUN="echo"
source test_backup_common.sh
-BUGREPORT_DIR="$HOME/backup/bugreports"
+[ -z "$BUGREPORT_DIR" ] && BUGREPORT_DIR="$HOME/backup/bugreports"
function check_file
{
@@ -107,3 +107,5 @@
echo "Last 3 timestamps in 3.txt:"
a shell cat /data/data/com.android.backuptest/files/3.txt | tail -n 3
+exit $need_bug
+
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 5724349..32efa4e 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -482,6 +482,8 @@
const sp<AaptFile>& file,
const String8& resType);
+ void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
+
ssize_t slurpFromArgs(Bundle* bundle);
virtual ssize_t slurpFullTree(Bundle* bundle,
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index c0ae592..d8215e7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -323,6 +323,7 @@
LABEL_ATTR = 0x01010001,
ICON_ATTR = 0x01010002,
MIN_SDK_VERSION_ATTR = 0x0101020c,
+ MAX_SDK_VERSION_ATTR = 0x01010271,
REQ_TOUCH_SCREEN_ATTR = 0x01010227,
REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
REQ_HARD_KEYBOARD_ATTR = 0x01010229,
@@ -502,8 +503,23 @@
bool withinActivity = false;
bool isMainActivity = false;
bool isLauncherActivity = false;
+ bool isSearchable = false;
bool withinApplication = false;
bool withinReceiver = false;
+ bool withinService = false;
+ bool withinIntentFilter = false;
+ bool hasMainActivity = false;
+ bool hasOtherActivities = false;
+ bool hasOtherReceivers = false;
+ bool hasOtherServices = false;
+ bool hasWallpaperService = false;
+ bool hasImeService = false;
+ bool hasWidgetReceivers = false;
+ bool hasIntentFilter = false;
+ bool actMainActivity = false;
+ bool actWidgetReceivers = false;
+ bool actImeService = false;
+ bool actWallpaperService = false;
int targetSdk = 0;
int smallScreen = 1;
int normalScreen = 1;
@@ -513,9 +529,48 @@
String8 activityLabel;
String8 activityIcon;
String8 receiverName;
+ String8 serviceName;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
+ if (depth < 2) {
+ withinApplication = false;
+ } else if (depth < 3) {
+ if (withinActivity && isMainActivity && isLauncherActivity) {
+ const char *aName = getComponentName(pkg, activityName);
+ if (aName != NULL) {
+ printf("launchable activity name='%s'", aName);
+ }
+ printf("label='%s' icon='%s'\n",
+ activityLabel.string(),
+ activityIcon.string());
+ }
+ if (!hasIntentFilter) {
+ hasOtherActivities |= withinActivity;
+ hasOtherReceivers |= withinReceiver;
+ hasOtherServices |= withinService;
+ }
+ withinActivity = false;
+ withinService = false;
+ withinReceiver = false;
+ hasIntentFilter = false;
+ isMainActivity = isLauncherActivity = false;
+ } else if (depth < 4) {
+ if (withinIntentFilter) {
+ if (withinActivity) {
+ hasMainActivity |= actMainActivity;
+ hasOtherActivities |= !actMainActivity;
+ } else if (withinReceiver) {
+ hasWidgetReceivers |= actWidgetReceivers;
+ hasOtherReceivers |= !actWidgetReceivers;
+ } else if (withinService) {
+ hasImeService |= actImeService;
+ hasWallpaperService |= actWallpaperService;
+ hasOtherServices |= (!actImeService && !actWallpaperService);
+ }
+ }
+ withinIntentFilter = false;
+ }
continue;
}
if (code != ResXMLTree::START_TAG) {
@@ -523,7 +578,7 @@
}
depth++;
String8 tag(tree.getElementName(&len));
- //printf("Depth %d tag %s\n", depth, tag.string());
+ //printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
@@ -587,6 +642,10 @@
targetSdk = code;
printf("sdkVersion:'%d'\n", code);
}
+ code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
+ if (code != -1) {
+ printf("maxSdkVersion:'%d'\n", code);
+ }
code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
if (error != "") {
error = "";
@@ -651,6 +710,8 @@
} else if (depth == 3 && withinApplication) {
withinActivity = false;
withinReceiver = false;
+ withinService = false;
+ hasIntentFilter = false;
if(tag == "activity") {
withinActivity = true;
activityName = getAttribute(tree, NAME_ATTR, &error);
@@ -685,76 +746,88 @@
fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
goto bail;
}
+ } else if (tag == "service") {
+ withinService = true;
+ serviceName = getAttribute(tree, NAME_ATTR, &error);
+
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string());
+ goto bail;
+ }
}
- } else if (depth == 5) {
- if (withinActivity) {
- if (tag == "action") {
- //printf("LOG: action tag\n");
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
- goto bail;
- }
+ } else if ((depth == 4) && (tag == "intent-filter")) {
+ hasIntentFilter = true;
+ withinIntentFilter = true;
+ actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
+ } else if ((depth == 5) && withinIntentFilter){
+ String8 action;
+ if (tag == "action") {
+ action = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (withinActivity) {
if (action == "android.intent.action.MAIN") {
isMainActivity = true;
- //printf("LOG: isMainActivity==true\n");
+ actMainActivity = true;
}
- } else if (tag == "category") {
- String8 category = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
- goto bail;
+ } else if (withinReceiver) {
+ if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
+ actWidgetReceivers = true;
}
+ } else if (withinService) {
+ if (action == "android.view.InputMethod") {
+ actImeService = true;
+ } else if (action == "android.service.wallpaper.WallpaperService") {
+ actWallpaperService = true;
+ }
+ }
+ if (action == "android.intent.action.SEARCH") {
+ isSearchable = true;
+ }
+ }
+
+ if (tag == "category") {
+ String8 category = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (withinActivity) {
if (category == "android.intent.category.LAUNCHER") {
isLauncherActivity = true;
- //printf("LOG: isLauncherActivity==true\n");
- }
- }
- } else if (withinReceiver) {
- if (tag == "action") {
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
- goto bail;
- }
- if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
- const char *rName = getComponentName(pkg, receiverName);
- if (rName != NULL) {
- printf("gadget-receiver:'%s/%s'\n", pkg.string(), rName);
- }
}
}
}
}
-
- if (depth < 2) {
- withinApplication = false;
- }
- if (depth < 3) {
- //if (withinActivity) printf("LOG: withinActivity==false\n");
- withinActivity = false;
- withinReceiver = false;
- }
-
- if (depth < 5) {
- //if (isMainActivity) printf("LOG: isMainActivity==false\n");
- //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n");
- isMainActivity = false;
- isLauncherActivity = false;
- }
-
- if (withinActivity && isMainActivity && isLauncherActivity) {
- printf("launchable activity:");
- const char *aName = getComponentName(pkg, activityName);
- if (aName != NULL) {
- printf(" name='%s'", aName);
- }
- printf("label='%s' icon='%s'\n",
- activityLabel.string(),
- activityIcon.string());
- }
}
-
+
+ if (hasMainActivity) {
+ printf("main\n");
+ }
+ if (hasWidgetReceivers) {
+ printf("app-widget\n");
+ }
+ if (hasImeService) {
+ printf("ime\n");
+ }
+ if (hasWallpaperService) {
+ printf("wallpaper\n");
+ }
+ if (hasOtherActivities) {
+ printf("other-activities\n");
+ }
+ if (isSearchable) {
+ printf("search\n");
+ }
+ if (hasOtherReceivers) {
+ printf("other-receivers\n");
+ }
+ if (hasOtherServices) {
+ printf("other-services\n");
+ }
+
// Determine default values for any unspecified screen sizes,
// based on the target SDK of the package. As of 4 (donut)
// the screen size support was introduced, so all default to
@@ -773,7 +846,7 @@
if (normalScreen != 0) printf(" 'normal'");
if (largeScreen != 0) printf(" 'large'");
printf("\n");
-
+
printf("locales:");
Vector<String8> locales;
res.getLocales(&locales);
@@ -786,7 +859,7 @@
printf(" '%s'", localeStr);
}
printf("\n");
-
+
Vector<ResTable_config> configs;
res.getConfigurations(&configs);
SortedVector<int> densities;
@@ -796,14 +869,14 @@
if (dens == 0) dens = 160;
densities.add(dens);
}
-
+
printf("densities:");
const size_t ND = densities.size();
for (size_t i=0; i<ND; i++) {
printf(" '%d'", densities[i]);
}
printf("\n");
-
+
AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
if (dir != NULL) {
if (dir->getFileCount() > 0) {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 9d2ed10..e8410cd 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -272,15 +272,16 @@
ResourceDirIterator it(set, String8("drawable"));
Vector<sp<AaptFile> > newNameFiles;
Vector<String8> newNamePaths;
+ bool hasErrors = false;
ssize_t res;
while ((res=it.next()) == NO_ERROR) {
res = preProcessImage(bundle, assets, it.getFile(), NULL);
- if (res != NO_ERROR) {
- return res;
+ if (res < NO_ERROR) {
+ hasErrors = true;
}
}
- return NO_ERROR;
+ return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
status_t postProcessImages(const sp<AaptAssets>& assets,
@@ -288,15 +289,16 @@
const sp<ResourceTypeSet>& set)
{
ResourceDirIterator it(set, String8("drawable"));
+ bool hasErrors = false;
ssize_t res;
while ((res=it.next()) == NO_ERROR) {
res = postProcessImage(assets, table, it.getFile());
- if (res != NO_ERROR) {
- return res;
+ if (res < NO_ERROR) {
+ hasErrors = true;
}
}
- return res < NO_ERROR ? res : (status_t)NO_ERROR;
+ return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
static void collect_files(const sp<AaptDir>& dir,
@@ -472,11 +474,22 @@
// didn't find a match fall through and add it..
}
baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
+ assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex));
}
} else {
// this group doesn't exist (a file that's only in the overlay)
baseSet->add(overlaySet->keyAt(overlayIndex),
overlaySet->valueAt(overlayIndex));
+ // make sure all flavors are defined in the resources.
+ sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex);
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles =
+ overlayGroup->getFiles();
+ size_t overlayGroupSize = overlayFiles.size();
+ for (size_t overlayGroupIndex = 0;
+ overlayGroupIndex<overlayGroupSize;
+ overlayGroupIndex++) {
+ assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex));
+ }
}
}
// this overlay didn't have resources for this type
@@ -1225,10 +1238,16 @@
NA = idents.size();
+ bool deprecated = false;
+
String16 comment = symbols->getComment(realClassName);
fprintf(fp, "%s/** ", indentStr);
if (comment.size() > 0) {
- fprintf(fp, "%s\n", String8(comment).string());
+ String8 cmt(comment);
+ fprintf(fp, "%s\n", cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else {
fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string());
}
@@ -1304,6 +1323,10 @@
}
fprintf(fp, "%s */\n", getIndentSpace(indent));
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", indentStr);
+ }
+
fprintf(fp,
"%spublic static final int[] %s = {\n"
"%s",
@@ -1352,11 +1375,17 @@
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
-
+
+ bool deprecated = false;
+
fprintf(fp, "%s/**\n", indentStr);
if (comment.size() > 0) {
+ String8 cmt(comment);
fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr);
- fprintf(fp, "%s %s\n", indentStr, String8(comment).string());
+ fprintf(fp, "%s %s\n", indentStr, cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else {
fprintf(fp,
"%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
@@ -1368,7 +1397,11 @@
indentStr, nclassName.string());
}
if (typeComment.size() > 0) {
- fprintf(fp, "\n\n%s %s\n", indentStr, String8(typeComment).string());
+ String8 cmt(typeComment);
+ fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
}
if (comment.size() > 0) {
if (pub) {
@@ -1386,6 +1419,9 @@
fprintf(fp, "%s @attr name %s:%s\n", indentStr,
"android", String8(name).string());
fprintf(fp, "%s*/\n", indentStr);
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", indentStr);
+ }
fprintf(fp,
"%spublic static final int %s_%s = %d;\n",
indentStr, nclassName.string(),
@@ -1427,11 +1463,16 @@
}
String16 comment(sym.comment);
bool haveComment = false;
+ bool deprecated = false;
if (comment.size() > 0) {
haveComment = true;
+ String8 cmt(comment);
fprintf(fp,
"%s/** %s\n",
- getIndentSpace(indent), String8(comment).string());
+ getIndentSpace(indent), cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
@@ -1439,20 +1480,25 @@
}
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
+ String8 cmt(typeComment);
if (!haveComment) {
haveComment = true;
fprintf(fp,
- "%s/** %s\n",
- getIndentSpace(indent), String8(typeComment).string());
+ "%s/** %s\n", getIndentSpace(indent), cmt.string());
} else {
fprintf(fp,
- "%s %s\n",
- getIndentSpace(indent), String8(typeComment).string());
+ "%s %s\n", getIndentSpace(indent), cmt.string());
+ }
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
}
}
if (haveComment) {
fprintf(fp,"%s */\n", getIndentSpace(indent));
}
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
+ }
fprintf(fp, "%spublic static final int %s=0x%08x;\n",
getIndentSpace(indent),
String8(name).string(), (int)sym.int32Val);
@@ -1471,17 +1517,25 @@
return UNKNOWN_ERROR;
}
String16 comment(sym.comment);
+ bool deprecated = false;
if (comment.size() > 0) {
+ String8 cmt(comment);
fprintf(fp,
"%s/** %s\n"
"%s */\n",
- getIndentSpace(indent), String8(comment).string(),
+ getIndentSpace(indent), cmt.string(),
getIndentSpace(indent));
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
String8(sym.name).string());
}
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
+ }
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
getIndentSpace(indent),
String8(name).string(), sym.stringVal.string());
diff --git a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
index df1876d..c562650 100644
--- a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
@@ -24,35 +24,40 @@
* <p/>
* <p/>{@link #getApiLevel()} gives the ability to know which methods are available.
* <p/>
+ * Changes in API level 4:
+ * <ul>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, boolean, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * </ul>
* Changes in API level 3:
* <ul>
- * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * <li> deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
* </ul>
* Changes in API level 2:
* <ul>
- * <li>{@link #getApiLevel()}</li>
- * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>new API Level method: {@link #getApiLevel()}</li>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
* <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, Map, Map, IProjectCallback, ILayoutLog)}</li>
* </ul>
*/
public interface ILayoutBridge {
-
- final int API_CURRENT = 3;
+
+ final int API_CURRENT = 4;
/**
* Returns the API level of the layout library.
* While no methods will ever be removed, some may become deprecated, and some new ones
* will appear.
* <p/>If calling this method throws an {@link AbstractMethodError}, then the API level
- * should be considered to be 1.
+ * should be considered to be 1.
*/
int getApiLevel();
/**
* Initializes the Bridge object.
* @param fontOsLocation the location of the fonts.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
+ * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
* @return true if success.
* @since 1
*/
@@ -65,6 +70,43 @@
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param screenWidth the screen width
* @param screenHeight the screen height
+ * @param renderFullSize if true, the rendering will render the full size needed by the
+ * layout. This size is never smaller than <var>screenWidth</var> x <var>screenHeight</var>.
+ * @param density the density factor for the screen.
+ * @param xdpi the screen actual dpi in X
+ * @param ydpi the screen actual dpi in Y
+ * @param themeName The name of the theme to use.
+ * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
+ * @param projectResources the resources of the project. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the
+ * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * and the value is the resource value.
+ * @param frameworkResources the framework resources. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the map
+ * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * value is the resource value.
+ * @param projectCallback The {@link IProjectCallback} object to get information from
+ * the project.
+ * @param logger the object responsible for displaying warning/errors to the user.
+ * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @since 4
+ */
+ ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback projectCallback, ILayoutLog logger);
+
+ /**
+ * Computes and renders a layout
+ * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
+ * layout file.
+ * @param projectKey An Object identifying the project. This is used for the cache mechanism.
+ * @param screenWidth the screen width
+ * @param screenHeight the screen height
* @param density the density factor for the screen.
* @param xdpi the screen actual dpi in X
* @param ydpi the screen actual dpi in Y
@@ -84,6 +126,7 @@
* @return an {@link ILayoutResult} object that contains the result of the layout.
* @since 3
*/
+ @Deprecated
ILayoutResult computeLayout(IXmlPullParser layoutDescription,
Object projectKey,
int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
@@ -155,7 +198,7 @@
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback projectCallback, ILayoutLog logger);
-
+
/**
* Clears the resource cache for a specific project.
* <p/>This cache contains bitmaps and nine patches that are loaded from the disk and reused
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
index 6bc01b1..7dde634 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
@@ -16,7 +16,6 @@
package android.graphics;
-import com.android.layoutlib.bridge.BridgeCanvas;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -25,15 +24,15 @@
import javax.imageio.ImageIO;
public final class Bitmap extends _Original_Bitmap {
-
+
private BufferedImage mImage;
public Bitmap(File input) throws IOException {
super(1, true, null);
-
+
mImage = ImageIO.read(input);
}
-
+
Bitmap(BufferedImage image) {
super(1, true, null);
mImage = image;
@@ -42,9 +41,9 @@
public BufferedImage getImage() {
return mImage;
}
-
+
// ----- overriden methods
-
+
public enum Config {
// these native values must match up with the enum in SkBitmap.h
ALPHA_8 (2),
@@ -56,27 +55,26 @@
this.nativeInt = ni;
}
final int nativeInt;
-
+
/* package */ static Config nativeToConfig(int ni) {
return sConfigs[ni];
}
-
+
private static Config sConfigs[] = {
null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
};
}
-
@Override
public int getWidth() {
return mImage.getWidth();
}
-
+
@Override
public int getHeight() {
return mImage.getHeight();
}
-
+
/**
* Returns an immutable bitmap from the source bitmap. The new bitmap may
* be the same object as source, or a copy may have been made.
@@ -100,7 +98,7 @@
int width, int height) {
return new Bitmap(source.mImage.getSubimage(x, y, width, height));
}
-
+
/**
* Returns an immutable bitmap from subset of the source bitmap,
* transformed by the optional matrix.
@@ -158,7 +156,7 @@
neww = Math.round(deviceR.width());
newh = Math.round(deviceR.height());
- BridgeCanvas canvas = new BridgeCanvas(neww, newh);
+ Canvas canvas = new Canvas(neww, newh);
canvas.translate(-deviceR.left, -deviceR.top);
canvas.concat(m);
@@ -169,10 +167,10 @@
}
canvas.drawBitmap(source, srcR, dstR, paint);
-
+
return new Bitmap(canvas.getImage());
}
-
+
/**
* Returns a mutable bitmap with the specified width and height.
*
@@ -184,7 +182,7 @@
public static Bitmap createBitmap(int width, int height, Config config) {
return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
}
-
+
/**
* Returns a immutable bitmap with the specified width and height, with each
* pixel value set to the corresponding value in the colors array.
@@ -215,7 +213,7 @@
|| (lastScanline + width > length)) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
// TODO: create an immutable bitmap...
throw new UnsupportedOperationException();
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeCanvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
similarity index 89%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeCanvas.java
rename to tools/layoutlib/bridge/src/android/graphics/Canvas.java
index 4710691..3fa1d1d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeCanvas.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
@@ -14,24 +14,16 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package android.graphics;
import com.android.layoutlib.api.ILayoutLog;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.DrawFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.graphics.Shader;
import android.graphics.Xfermode;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
@@ -43,6 +35,7 @@
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Stack;
@@ -51,36 +44,59 @@
/**
* Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
*/
-public class BridgeCanvas extends Canvas {
-
+public class Canvas extends _Original_Canvas {
+
private BufferedImage mBufferedImage;
private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
private final ILayoutLog mLogger;
- public BridgeCanvas(int width, int height, ILayoutLog logger) {
+ public Canvas() {
+ mLogger = null;
+ // the mBufferedImage will be taken from a bitmap in #setBitmap()
+ }
+
+ public Canvas(Bitmap bitmap) {
+ mLogger = null;
+ mBufferedImage = bitmap.getImage();
+ mGraphicsStack.push(mBufferedImage.createGraphics());
+ }
+
+ public Canvas(int nativeCanvas) {
+ mLogger = null;
+ throw new UnsupportedOperationException("Can't create Canvas(int)");
+ }
+
+ public Canvas(javax.microedition.khronos.opengles.GL gl) {
+ mLogger = null;
+ throw new UnsupportedOperationException("Can't create Canvas(javax.microedition.khronos.opengles.GL)");
+ }
+
+ // custom constructors for our use.
+ public Canvas(int width, int height, ILayoutLog logger) {
mLogger = logger;
mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
mGraphicsStack.push(mBufferedImage.createGraphics());
}
-
- public BridgeCanvas(int width, int height) {
+
+ public Canvas(int width, int height) {
this(width, height, null /* logger*/);
}
-
+
+ // custom mehtods
public BufferedImage getImage() {
return mBufferedImage;
}
-
- Graphics2D getGraphics2d() {
+
+ public Graphics2D getGraphics2d() {
return mGraphicsStack.peek();
}
-
- void dispose() {
+
+ public void dispose() {
while (mGraphicsStack.size() > 0) {
mGraphicsStack.pop().dispose();
}
}
-
+
/**
* Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
* <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
@@ -91,11 +107,11 @@
g.setColor(new Color(paint.getColor()));
int alpha = paint.getAlpha();
float falpha = alpha / 255.f;
-
+
Xfermode xfermode = paint.getXfermode();
if (xfermode instanceof PorterDuffXfermode) {
PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
-
+
setModeInGraphics(mode, g, falpha);
} else {
if (mLogger != null && xfermode != null) {
@@ -105,7 +121,7 @@
}
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
}
-
+
Shader shader = paint.getShader();
if (shader instanceof LinearGradient) {
g.setPaint(((LinearGradient)shader).getPaint());
@@ -116,10 +132,10 @@
shader.getClass().getCanonicalName()));
}
}
-
+
return g;
}
-
+
private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
switch (mode) {
case CLEAR:
@@ -168,14 +184,43 @@
break;
}
}
-
+
+
// --------------------
-
+ // OVERRIDEN ENUMS
+ // This is needed since we rename Canvas into _Original_Canvas
+ // --------------------
+
+ public enum EdgeType {
+ BW(0), //!< treat edges by just rounding to nearest pixel boundary
+ AA(1); //!< treat edges by rounding-out, since they may be antialiased
+
+ EdgeType(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+
+ // --------------------
+ // OVERRIDEN METHODS
+ // --------------------
+
@Override
public void finalize() throws Throwable {
// pass
}
-
+
+ /* (non-Javadoc)
+ * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
+ */
+ @Override
+ public void setBitmap(Bitmap bitmap) {
+ mBufferedImage = bitmap.getImage();
+ mGraphicsStack.push(mBufferedImage.createGraphics());
+ }
+
+
/* (non-Javadoc)
* @see android.graphics.Canvas#translate(float, float)
*/
@@ -183,7 +228,7 @@
public void translate(float dx, float dy) {
getGraphics2d().translate(dx, dy);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#save()
*/
@@ -191,7 +236,7 @@
public int save() {
Graphics2D g = (Graphics2D)getGraphics2d().create();
mGraphicsStack.push(g);
-
+
return mGraphicsStack.size() - 1;
}
@@ -203,7 +248,7 @@
// For now we ignore saveFlags
return save();
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#restore()
*/
@@ -221,7 +266,7 @@
mGraphicsStack.pop();
}
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#getSaveCount()
*/
@@ -229,8 +274,8 @@
public int getSaveCount() {
return mGraphicsStack.size() - 1;
}
-
-
+
+
/* (non-Javadoc)
* @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
*/
@@ -288,23 +333,36 @@
public boolean clipRect(RectF rect) {
return clipRect(rect.left, rect.top, rect.right, rect.bottom);
}
-
- @Override
+
public boolean quickReject(RectF rect, EdgeType type) {
return false;
}
@Override
+ public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
public boolean quickReject(Path path, EdgeType type) {
return false;
}
@Override
+ public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
public boolean quickReject(float left, float top, float right, float bottom,
EdgeType type) {
return false;
}
+ @Override
+ public boolean quickReject(float left, float top, float right, float bottom,
+ _Original_Canvas.EdgeType type) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
/**
* Retrieve the clip bounds, returning true if they are non-empty.
*
@@ -324,31 +382,31 @@
}
return false;
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
*/
@Override
public void drawColor(int color, PorterDuff.Mode mode) {
Graphics2D g = getGraphics2d();
-
+
// save old color
Color c = g.getColor();
-
+
Composite composite = g.getComposite();
-
+
// get the alpha from the color
int alpha = color >>> 24;
float falpha = alpha / 255.f;
-
+
setModeInGraphics(mode, g, falpha);
-
+
g.setColor(new Color(color));
-
+
getGraphics2d().fillRect(0, 0, getWidth(), getHeight());
-
+
g.setComposite(composite);
-
+
// restore color
g.setColor(c);
}
@@ -360,7 +418,7 @@
public void drawColor(int color) {
drawColor(color, PorterDuff.Mode.SRC_OVER);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawARGB(int, int, int, int)
*/
@@ -368,7 +426,7 @@
public void drawARGB(int a, int r, int g, int b) {
drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawRGB(int, int, int)
*/
@@ -377,7 +435,7 @@
drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#getWidth()
*/
@@ -385,7 +443,7 @@
public int getWidth() {
return mBufferedImage.getWidth();
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#getHeight()
*/
@@ -401,7 +459,7 @@
public void drawPaint(Paint paint) {
drawColor(paint.getColor());
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
*/
@@ -417,7 +475,32 @@
*/
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- throw new UnsupportedOperationException();
+ boolean needsRestore = false;
+ if (matrix.isIdentity() == false) {
+ // create a new graphics and apply the matrix to it
+ save(); // this creates a new Graphics2D, and stores it for children call to use
+ needsRestore = true;
+ Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
+
+ // get the Graphics2D current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform from the matrix
+ AffineTransform matrixTx = matrix.getTransform();
+
+ // combine them so that the matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
+ }
+
+ // draw the bitmap
+ drawBitmap(bitmap, 0, 0, paint);
+
+ if (needsRestore) {
+ // remove the new graphics
+ restore();
+ }
}
/* (non-Javadoc)
@@ -456,39 +539,42 @@
int height, boolean hasAlpha, Paint paint) {
throw new UnsupportedOperationException();
}
-
+
private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
int dtop, int dright, int dbottom, Paint paint) {
BufferedImage image = bitmap.getImage();
-
+
Graphics2D g = getGraphics2d();
-
+
Composite c = null;
-
- if (paint.isFilterBitmap()) {
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+
+ if (paint != null) {
+ if (paint.isFilterBitmap()) {
+ g = (Graphics2D)g.create();
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ if (paint.getAlpha() != 0xFF) {
+ c = g.getComposite();
+ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
+ paint.getAlpha()/255.f));
+ }
}
-
- if (paint.getAlpha() != 0xFF) {
- c = g.getComposite();
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- paint.getAlpha()/255.f));
- }
-
+
g.drawImage(image, dleft, dtop, dright, dbottom,
sleft, stop, sright, sbottom, null);
- if (paint.isFilterBitmap()) {
- g.dispose();
- }
-
- if (c != null) {
- g.setComposite(c);
+ if (paint != null) {
+ if (paint.isFilterBitmap()) {
+ g.dispose();
+ }
+ if (c != null) {
+ g.setComposite(c);
+ }
}
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#rotate(float, float, float)
*/
@@ -509,7 +595,7 @@
public void rotate(float degrees) {
getGraphics2d().rotate(Math.toRadians(degrees));
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#scale(float, float, float, float)
*/
@@ -528,19 +614,19 @@
public void scale(float sx, float sy) {
getGraphics2d().scale(sx, sy);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
*/
@Override
public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
Graphics2D g = getGraphics2d();
-
+
g = (Graphics2D)g.create();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
+
g.setFont(paint.getFont());
-
+
// set the color. because this only handles RGB we have to handle the alpha separately
g.setColor(new Color(paint.getColor()));
int alpha = paint.getAlpha();
@@ -557,9 +643,9 @@
x -= m;
}
}
-
+
g.drawChars(text, index, count, (int)x, (int)y);
-
+
g.dispose();
}
@@ -586,7 +672,7 @@
public void drawText(String text, int start, int end, float x, float y, Paint paint) {
drawText(text.toCharArray(), start, end - start, x, y, paint);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
*/
@@ -594,7 +680,7 @@
public void drawRect(RectF rect, Paint paint) {
doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
*/
@@ -614,11 +700,11 @@
private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
// get current graphisc
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
Style style = paint.getStyle();
-
+
// draw
if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
g.fillRect(left, top, width, height);
@@ -639,16 +725,16 @@
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
// get current graphisc
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
Style style = paint.getStyle();
-
+
// draw
-
+
int arcWidth = (int)(rx * 2);
int arcHeight = (int)(ry * 2);
-
+
if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
arcWidth, arcHeight);
@@ -671,7 +757,7 @@
public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
// get current graphisc
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
@@ -679,7 +765,7 @@
// dispose Graphics2D object
g.dispose();
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
*/
@@ -687,7 +773,7 @@
public void drawLines(float[] pts, int offset, int count, Paint paint) {
// get current graphisc
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
for (int i = 0 ; i < count ; i += 4) {
@@ -706,7 +792,7 @@
public void drawLines(float[] pts, Paint paint) {
drawLines(pts, 0, pts.length, paint);
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
*/
@@ -714,11 +800,11 @@
public void drawCircle(float cx, float cy, float radius, Paint paint) {
// get current graphisc
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
Style style = paint.getStyle();
-
+
int size = (int)(radius * 2);
// draw
@@ -741,11 +827,11 @@
public void drawOval(RectF oval, Paint paint) {
// get current graphics
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
Style style = paint.getStyle();
-
+
// draw
if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
@@ -758,7 +844,7 @@
// dispose Graphics2D object
g.dispose();
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
*/
@@ -766,11 +852,11 @@
public void drawPath(Path path, Paint paint) {
// get current graphics
Graphics2D g = getGraphics2d();
-
+
g = getNewGraphics(paint, g);
Style style = paint.getStyle();
-
+
// draw
if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
g.fill(path.getAwtShape());
@@ -783,7 +869,7 @@
// dispose Graphics2D object
g.dispose();
}
-
+
/* (non-Javadoc)
* @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
*/
@@ -795,10 +881,10 @@
// get the new current graphics
Graphics2D g = getGraphics2d();
-
+
// and apply the matrix
g.setTransform(matrix.getTransform());
-
+
if (mLogger != null && matrix.hasPerspective()) {
mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
}
@@ -1059,15 +1145,6 @@
}
/* (non-Javadoc)
- * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
- */
- @Override
- public void setBitmap(Bitmap bitmap) {
- // TODO Auto-generated method stub
- super.setBitmap(bitmap);
- }
-
- /* (non-Javadoc)
* @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
*/
@Override
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
index 18c0e17..3974e08 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
@@ -17,6 +17,7 @@
package android.graphics;
import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
/**
@@ -747,7 +748,24 @@
* inverted, ignore inverse and return false.
*/
public boolean invert(Matrix inverse) {
- throw new UnsupportedOperationException("STUB NEEDED");
+ if (inverse == null) {
+ return false;
+ }
+
+ try {
+ AffineTransform affineTransform = getTransform();
+ AffineTransform inverseTransform = affineTransform.createInverse();
+ inverse.mValues[0] = (float)inverseTransform.getScaleX();
+ inverse.mValues[1] = (float)inverseTransform.getShearX();
+ inverse.mValues[2] = (float)inverseTransform.getTranslateX();
+ inverse.mValues[3] = (float)inverseTransform.getScaleX();
+ inverse.mValues[4] = (float)inverseTransform.getShearY();
+ inverse.mValues[5] = (float)inverseTransform.getTranslateY();
+
+ return true;
+ } catch (NoninvertibleTransformException e) {
+ return false;
+ }
}
@Override
@@ -770,7 +788,19 @@
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
int pointCount) {
checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
- throw new UnsupportedOperationException("STUB NEEDED");
+
+ for (int i = 0 ; i < pointCount ; i++) {
+ // just in case we are doing in place, we better put this in temp vars
+ float x = mValues[0] * src[i + srcIndex] +
+ mValues[1] * src[i + srcIndex + 1] +
+ mValues[2];
+ float y = mValues[3] * src[i + srcIndex] +
+ mValues[4] * src[i + srcIndex + 1] +
+ mValues[5];
+
+ dst[i + dstIndex] = x;
+ dst[i + dstIndex + 1] = y;
+ }
}
/**
@@ -858,7 +888,26 @@
if (dst == null || src == null) {
throw new NullPointerException();
}
- throw new UnsupportedOperationException("STUB NEEDED");
+
+ // array with 4 corners
+ float[] corners = new float[] {
+ src.left, src.top,
+ src.right, src.top,
+ src.right, src.bottom,
+ src.left, src.bottom,
+ };
+
+ // apply the transform to them.
+ mapPoints(corners);
+
+ // now put the result in the rect. We take the min/max of Xs and min/max of Ys
+ dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
+ dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
+
+ dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
+ dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
+
+ return rectStaysRect();
}
/**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 8d44ac08..55fe4ac 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -31,6 +31,7 @@
import com.android.tools.layoutlib.create.OverrideMethod;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Typeface;
@@ -311,6 +312,7 @@
}
/*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
@@ -320,6 +322,23 @@
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback customViewLoader, ILayoutLog logger) {
+ return computeLayout(layoutDescription, projectKey,
+ screenWidth, screenHeight, false /* renderFullSize */,
+ density, xdpi, ydpi, themeName, isProjectTheme,
+ projectResources, frameworkResources, customViewLoader, logger);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ */
+ public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
if (logger == null) {
logger = sDefaultLogger;
}
@@ -358,7 +377,7 @@
windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
windowBackground = context.resolveResValue(windowBackground);
- screenOffset = getScreenOffset(currentTheme, context);
+ screenOffset = getScreenOffset(frameworkResources, currentTheme, context);
}
// we need to make sure the Looper has been initialized for this thread.
@@ -392,17 +411,40 @@
root.setBackgroundDrawable(d);
}
- int w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
- int h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.EXACTLY);
-
// measure the views
+ int w_spec, h_spec;
+
+ if (renderFullSize) {
+ // measure the full size needed by the layout.
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ view.measure(w_spec, h_spec);
+
+ int neededWidth = root.getChildAt(0).getMeasuredWidth();
+ if (neededWidth > screenWidth) {
+ screenWidth = neededWidth;
+ }
+
+ int neededHeight = root.getChildAt(0).getMeasuredHeight();
+ if (neededHeight > screenHeight - screenOffset) {
+ screenHeight = neededHeight + screenOffset;
+ }
+ }
+
+ // remeasure with only the size we need
+ // This must always be done before the call to layout
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.EXACTLY);
view.measure(w_spec, h_spec);
+
+ // now do the layout.
view.layout(0, screenOffset, screenWidth, screenHeight);
- // draw them
- BridgeCanvas canvas = new BridgeCanvas(screenWidth, screenHeight - screenOffset,
- logger);
+ // draw the views
+ Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
root.draw(canvas);
canvas.dispose();
@@ -673,9 +715,13 @@
/**
* Returns the top screen offset. This depends on whether the current theme defines the user
* of the title and status bars.
+ * @param frameworkResources The framework resources
+ * @param currentTheme The current theme
+ * @param context The context
* @return the pixel height offset
*/
- private int getScreenOffset(IStyleResourceValue currentTheme, BridgeContext context) {
+ private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources,
+ IStyleResourceValue currentTheme, BridgeContext context) {
int offset = 0;
// get the title bar flag from the current theme.
@@ -687,22 +733,25 @@
// if there's a value and it's true (default is false)
if (value == null || value.getValue() == null ||
XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
+ // default size of the window title bar
+ int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
+
// get value from the theme.
value = context.findItemInStyle(currentTheme, "windowTitleSize");
// resolve it
value = context.resolveResValue(value);
- // default value
- offset = DEFAULT_TITLE_BAR_HEIGHT;
-
- // get the real value;
if (value != null) {
+ // get the numerical value, if available
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
- offset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ // compute the pixel value based on the display metrics
+ defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
}
}
+
+ offset += defaultOffset;
}
// get the fullscreen flag from the current theme.
@@ -713,8 +762,25 @@
if (value == null || value.getValue() == null ||
XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
- // FIXME: Right now this is hard-coded in the platform, but once there's a constant, we'll need to use it.
- offset += DEFAULT_STATUS_BAR_HEIGHT;
+
+ // default value
+ int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
+
+ // get the real value, first the list of Dimensions from the framework map
+ Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
+
+ // now get the value
+ value = dimens.get("status_bar_height");
+ if (value != null) {
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ }
+ }
+
+ // add the computed offset.
+ offset += defaultOffset;
}
return offset;
@@ -993,7 +1059,7 @@
public void setWallpaperPosition(IBinder window, float x, float y) {
// pass for now.
}
-
+
public IBinder asBinder() {
// pass for now.
return null;
@@ -1021,12 +1087,12 @@
}
@SuppressWarnings("unused")
- public void dispatchPointer(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
@SuppressWarnings("unused")
- public void dispatchTrackball(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index b426247..b5b7ceb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -45,11 +45,12 @@
public final static String PREFIX_RESOURCE_REF = "@";
public final static String PREFIX_ANDROID_THEME_REF = "?android:";
public final static String PREFIX_THEME_REF = "?";
-
+
public final static String PREFIX_ANDROID = "android:";
-
+
public final static String RES_STYLE = "style";
public final static String RES_ATTR = "attr";
+ public final static String RES_DIMEN = "dimen";
public final static String RES_DRAWABLE = "drawable";
public final static String RES_COLOR = "color";
public final static String RES_LAYOUT = "layout";
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
index 8a040e41..2b0100b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
@@ -497,6 +497,24 @@
}
@Override
+ public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
+ getValue(id, value, true);
+
+ File f = new File(value.string.toString());
+ if (f.isFile()) {
+ try {
+ return new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ NotFoundException exception = new NotFoundException();
+ exception.initCause(e);
+ throw exception;
+ }
+ }
+
+ throw new NotFoundException();
+ }
+
+ @Override
public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
throw new UnsupportedOperationException();
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
index 5f0852e..abbf2f0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
@@ -30,17 +30,17 @@
NinePatchDrawable(NinePatch ninePatch) {
m9Patch = ninePatch;
}
-
+
@Override
public int getMinimumWidth() {
return m9Patch.getWidth();
}
-
+
@Override
public int getMinimumHeight() {
return m9Patch.getHeight();
}
-
+
/**
* Return the intrinsic width of the underlying drawable object. Returns
* -1 if it has no intrinsic width, such as with a solid color.
@@ -58,7 +58,7 @@
public int getIntrinsicHeight() {
return m9Patch.getHeight();
}
-
+
/**
* Return in padding the insets suggested by this Drawable for placing
* content inside the drawable's bounds. Positive values move toward the
@@ -76,24 +76,18 @@
padding.bottom = padd[3];
return true;
}
-
+
@Override
public void draw(Canvas canvas) {
- if (canvas instanceof BridgeCanvas) {
- BridgeCanvas bridgeCanvas = (BridgeCanvas)canvas;
-
- Rect r = getBounds();
- m9Patch.draw(bridgeCanvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
-
- return;
- }
+ Rect r = getBounds();
+ m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
- throw new UnsupportedOperationException();
+ return;
}
-
+
// ----------- Not implemented methods ---------------
-
+
@Override
public int getOpacity() {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index c07baff..47184f1 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -54,18 +54,19 @@
},
new String[] { // classes to rename (so that we can replace them in layoutlib)
// original-platform-class-name ======> renamed-class-name
+ "android.graphics.Bitmap", "android.graphics._Original_Bitmap",
+ "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
+ "android.graphics.Canvas", "android.graphics._Original_Canvas",
+ "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
+ "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
"android.graphics.Matrix", "android.graphics._Original_Matrix",
"android.graphics.Paint", "android.graphics._Original_Paint",
- "android.graphics.Typeface", "android.graphics._Original_Typeface",
- "android.graphics.Bitmap", "android.graphics._Original_Bitmap",
"android.graphics.Path", "android.graphics._Original_Path",
"android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode",
- "android.graphics.Shader", "android.graphics._Original_Shader",
- "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
- "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
- "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
"android.graphics.RadialGradient", "android.graphics._Original_RadialGradient",
+ "android.graphics.Shader", "android.graphics._Original_Shader",
"android.graphics.SweepGradient", "android.graphics._Original_SweepGradient",
+ "android.graphics.Typeface", "android.graphics._Original_Typeface",
"android.os.ServiceManager", "android.os._Original_ServiceManager",
"android.util.FloatMath", "android.util._Original_FloatMath",
"android.view.SurfaceView", "android.view._Original_SurfaceView",
diff --git a/tools/preload/20090811.compiled b/tools/preload/20090811.compiled
index dd61487..6dbeca0 100644
--- a/tools/preload/20090811.compiled
+++ b/tools/preload/20090811.compiled
Binary files differ
diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk
index e6fa103..f325870 100644
--- a/tools/preload/Android.mk
+++ b/tools/preload/Android.mk
@@ -3,13 +3,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- ClassRank.java \
Compile.java \
LoadedClass.java \
MemoryUsage.java \
Operation.java \
Policy.java \
PrintCsv.java \
+ PrintHtmlDiff.java \
PrintPsTree.java \
Proc.java \
Record.java \
diff --git a/tools/preload/ClassRank.java b/tools/preload/ClassRank.java
deleted file mode 100644
index c562d5c..0000000
--- a/tools/preload/ClassRank.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-import java.util.Comparator;
-
-/**
- * Ranks classes for preloading based on how long their operations took
- * and how early the operations happened. Higher ranked classes come first.
- */
-class ClassRank implements Comparator<Operation> {
-
- /**
- * Increase this number to add more weight to classes which were loaded
- * earlier.
- */
- static final int SEQUENCE_WEIGHT = 500; // 0.5ms
-
- static final int BUCKET_SIZE = 5;
-
- public int compare(Operation a, Operation b) {
- // Higher ranked operations should come first.
- int result = rankOf(b) - rankOf(a);
- if (result != 0) {
- return result;
- }
-
- // Make sure we don't drop one of two classes w/ the same rank.
- // If a load and an initialization have the same rank, it's OK
- // to treat the operations equally.
- return a.loadedClass.name.compareTo(b.loadedClass.name);
- }
-
- /** Ranks the given operation. */
- private static int rankOf(Operation o) {
- return o.medianExclusiveTimeMicros()
- + SEQUENCE_WEIGHT / (o.index / BUCKET_SIZE + 1);
- }
-}
-
-
diff --git a/tools/preload/LoadedClass.java b/tools/preload/LoadedClass.java
index 9ef17f5..86e5dfc 100644
--- a/tools/preload/LoadedClass.java
+++ b/tools/preload/LoadedClass.java
@@ -51,7 +51,7 @@
}
void measureMemoryUsage() {
-// this.memoryUsage = MemoryUsage.forClass(name);
+ this.memoryUsage = MemoryUsage.forClass(name);
}
int mlt = -1;
@@ -76,6 +76,10 @@
return mit = calculateMedian(initializations);
}
+ int medianTimeMicros() {
+ return medianInitTimeMicros() + medianLoadTimeMicros();
+ }
+
/** Calculates the median duration for a list of operations. */
private static int calculateMedian(List<Operation> operations) {
int size = operations.size();
@@ -99,18 +103,18 @@
}
}
- /** Returns names of apps that loaded this class. */
- Set<String> applicationNames() {
- Set<String> appNames = new HashSet<String>();
- addProcessNames(loads, appNames);
- addProcessNames(initializations, appNames);
- return appNames;
+ /** Returns names of processes that loaded this class. */
+ Set<String> processNames() {
+ Set<String> names = new HashSet<String>();
+ addProcessNames(loads, names);
+ addProcessNames(initializations, names);
+ return names;
}
- private void addProcessNames(List<Operation> ops, Set<String> appNames) {
+ private void addProcessNames(List<Operation> ops, Set<String> names) {
for (Operation operation : ops) {
- if (operation.process.isApplication()) {
- appNames.add(operation.process.name);
+ if (operation.process.fromZygote()) {
+ names.add(operation.process.name);
}
}
}
@@ -123,31 +127,4 @@
public String toString() {
return name;
}
-
- /**
- * Returns true if this class's initialization causes the given class to
- * initialize.
- */
- public boolean initializes(LoadedClass clazz, Set<LoadedClass> visited) {
- // Avoid infinite recursion.
- if (!visited.add(this)) {
- return false;
- }
-
- if (clazz == this) {
- return true;
- }
-
- for (Operation initialization : initializations) {
- if (initialization.loadedClass.initializes(clazz, visited)) {
- return true;
- }
- }
-
- return false;
- }
-
- public boolean isPreloadable() {
- return systemClass && Policy.isPreloadableClass(name);
- }
}
diff --git a/tools/preload/MemoryUsage.java b/tools/preload/MemoryUsage.java
index e5dfb2a..bc21b6f 100644
--- a/tools/preload/MemoryUsage.java
+++ b/tools/preload/MemoryUsage.java
@@ -34,8 +34,8 @@
static final MemoryUsage NOT_AVAILABLE = new MemoryUsage();
static int errorCount = 0;
- static final int MAXIMUM_ERRORS = 10; // give up after this many fails
+ // These values are in 1kB increments (not 4kB like you'd expect).
final int nativeSharedPages;
final int javaSharedPages;
final int otherSharedPages;
@@ -123,15 +123,24 @@
return allocSize - freedSize;
}
+ int totalHeap() {
+ return javaHeapSize() + (int) nativeHeapSize;
+ }
+
int javaPagesInK() {
- return (javaSharedPages + javaPrivatePages) * 4;
+ return javaSharedPages + javaPrivatePages;
}
int nativePagesInK() {
- return (nativeSharedPages + nativePrivatePages) * 4;
+ return nativeSharedPages + nativePrivatePages;
}
int otherPagesInK() {
- return (otherSharedPages + otherPrivatePages) * 4;
+ return otherSharedPages + otherPrivatePages;
+ }
+
+ int totalPages() {
+ return javaSharedPages + javaPrivatePages + nativeSharedPages +
+ nativePrivatePages + otherSharedPages + otherPrivatePages;
}
/**
@@ -163,13 +172,6 @@
* Measures memory usage for the given class.
*/
static MemoryUsage forClass(String className) {
-
- // This is a coarse approximation for determining that no device is connected,
- // or that the communication protocol has changed, but we'll keep going and stop whining.
- if (errorCount >= MAXIMUM_ERRORS) {
- return NOT_AVAILABLE;
- }
-
MeasureWithTimeout measurer = new MeasureWithTimeout(className);
new Thread(measurer).start();
@@ -280,4 +282,17 @@
e.printStackTrace();
}
}
+
+ /** Measures memory usage information and stores it in the model. */
+ public static void main(String[] args) throws IOException,
+ ClassNotFoundException {
+ Root root = Root.fromFile(args[0]);
+ root.baseline = baseline();
+ for (LoadedClass loadedClass : root.loadedClasses.values()) {
+ if (loadedClass.systemClass) {
+ loadedClass.measureMemoryUsage();
+ }
+ }
+ root.toFile(args[0]);
+ }
}
diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java
index ade889e3..7a190ac 100644
--- a/tools/preload/Policy.java
+++ b/tools/preload/Policy.java
@@ -19,10 +19,10 @@
import java.util.Set;
/**
- * This is not instantiated - we just provide data for other classes to use
+ * Policy that governs which classes are preloaded.
*/
public class Policy {
-
+
/**
* No constructor - use static methods only
*/
@@ -31,18 +31,24 @@
/**
* This location (in the build system) of the preloaded-classes file.
*/
- private static final String PRELOADED_CLASS_FILE
+ static final String PRELOADED_CLASS_FILE
= "frameworks/base/preloaded-classes";
/**
* Long running services. These are restricted in their contribution to the
* preloader because their launch time is less critical.
*/
+ // TODO: Generate this automatically from package manager.
private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
- "system_server",
- "com.google.process.content",
- "android.process.media",
- "com.google.process.gapps"
+ "system_server",
+ "com.google.process.content",
+ "android.process.media",
+ "com.android.phone",
+ "com.google.android.apps.maps.FriendService",
+ "com.google.android.apps.maps.LocationFriendService",
+ "com.google.android.googleapps",
+ "com.google.process.gapps",
+ "android.tts"
));
/**
@@ -63,24 +69,15 @@
));
/**
- * Returns the path/file name of the preloaded classes file that will be written
- * by WritePreloadedClassFile.
- */
- public static String getPreloadedClassFileName() {
- return PRELOADED_CLASS_FILE;
- }
-
- /**
- * Reports if the given process name is a "long running" process or service
+ * Returns true if the given process name is a "long running" process or
+ * service.
*/
public static boolean isService(String processName) {
return SERVICES.contains(processName);
}
-
- /**
- * Reports if the given class should never be preloaded
- */
- public static boolean isPreloadableClass(String className) {
- return !EXCLUDED_CLASSES.contains(className);
+
+ /**Reports if the given class should be preloaded. */
+ public static boolean isPreloadable(LoadedClass clazz) {
+ return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name);
}
}
diff --git a/tools/preload/PrintCsv.java b/tools/preload/PrintCsv.java
index 62f4271..1820830 100644
--- a/tools/preload/PrintCsv.java
+++ b/tools/preload/PrintCsv.java
@@ -18,9 +18,12 @@
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.BufferedInputStream;
+import java.io.Writer;
+import java.io.PrintStream;
import java.util.Set;
import java.util.HashSet;
import java.util.TreeSet;
+import java.util.Iterator;
/**
* Prints raw information in CSV format.
@@ -36,71 +39,89 @@
Root root = Root.fromFile(args[0]);
- System.out.println("Name"
- + ",Preloaded"
- + ",Median Load Time (us)"
- + ",Median Init Time (us)"
- + ",Process Names"
- + ",Load Count"
- + ",Init Count");
-// + ",Managed Heap (B)"
-// + ",Native Heap (B)"
-// + ",Managed Pages (kB)"
-// + ",Native Pages (kB)"
-// + ",Other Pages (kB)");
+ printHeaders(System.out);
- MemoryUsage baseline = root.baseline;
+ MemoryUsage baseline = MemoryUsage.baseline();
for (LoadedClass loadedClass : root.loadedClasses.values()) {
if (!loadedClass.systemClass) {
continue;
}
- System.out.print(loadedClass.name);
- System.out.print(',');
- System.out.print(loadedClass.preloaded);
- System.out.print(',');
- System.out.print(loadedClass.medianLoadTimeMicros());
- System.out.print(',');
- System.out.print(loadedClass.medianInitTimeMicros());
- System.out.print(',');
- System.out.print('"');
-
- Set<String> procNames = new TreeSet<String>();
- for (Operation op : loadedClass.loads)
- procNames.add(op.process.name);
- for (Operation op : loadedClass.initializations)
- procNames.add(op.process.name);
- for (String name : procNames) {
- System.out.print(name + "\n");
- }
-
- System.out.print('"');
- System.out.print(',');
- System.out.print(loadedClass.loads.size());
- System.out.print(',');
- System.out.print(loadedClass.initializations.size());
-/*
- if (loadedClass.memoryUsage.isAvailable()) {
- MemoryUsage subtracted
- = loadedClass.memoryUsage.subtract(baseline);
-
- System.out.print(',');
- System.out.print(subtracted.javaHeapSize());
- System.out.print(',');
- System.out.print(subtracted.nativeHeapSize);
- System.out.print(',');
- System.out.print(subtracted.javaPagesInK());
- System.out.print(',');
- System.out.print(subtracted.nativePagesInK());
- System.out.print(',');
- System.out.print(subtracted.otherPagesInK());
-
- } else {
- System.out.print(",n/a,n/a,n/a,n/a,n/a");
- }
-*/
- System.out.println();
+ printRow(System.out, baseline, loadedClass);
}
}
+
+ static void printHeaders(PrintStream out) {
+ out.println("Name"
+ + ",Preloaded"
+ + ",Median Load Time (us)"
+ + ",Median Init Time (us)"
+ + ",Process Names"
+ + ",Load Count"
+ + ",Init Count"
+ + ",Managed Heap (B)"
+ + ",Native Heap (B)"
+ + ",Managed Pages (kB)"
+ + ",Native Pages (kB)"
+ + ",Other Pages (kB)");
+ }
+
+ static void printRow(PrintStream out, MemoryUsage baseline,
+ LoadedClass loadedClass) {
+ out.print(loadedClass.name);
+ out.print(',');
+ out.print(loadedClass.preloaded);
+ out.print(',');
+ out.print(loadedClass.medianLoadTimeMicros());
+ out.print(',');
+ out.print(loadedClass.medianInitTimeMicros());
+ out.print(',');
+ out.print('"');
+
+ Set<String> procNames = new TreeSet<String>();
+ for (Operation op : loadedClass.loads)
+ procNames.add(op.process.name);
+ for (Operation op : loadedClass.initializations)
+ procNames.add(op.process.name);
+
+ if (procNames.size() <= 3) {
+ for (String name : procNames) {
+ out.print(name + "\n");
+ }
+ } else {
+ Iterator<String> i = procNames.iterator();
+ out.print(i.next() + "\n");
+ out.print(i.next() + "\n");
+ out.print("...and " + (procNames.size() - 2)
+ + " others.");
+ }
+
+ out.print('"');
+ out.print(',');
+ out.print(loadedClass.loads.size());
+ out.print(',');
+ out.print(loadedClass.initializations.size());
+
+ if (loadedClass.memoryUsage.isAvailable()) {
+ MemoryUsage subtracted
+ = loadedClass.memoryUsage.subtract(baseline);
+
+ out.print(',');
+ out.print(subtracted.javaHeapSize());
+ out.print(',');
+ out.print(subtracted.nativeHeapSize);
+ out.print(',');
+ out.print(subtracted.javaPagesInK());
+ out.print(',');
+ out.print(subtracted.nativePagesInK());
+ out.print(',');
+ out.print(subtracted.otherPagesInK());
+
+ } else {
+ out.print(",n/a,n/a,n/a,n/a,n/a");
+ }
+
+ out.println();
+ }
}
diff --git a/tools/preload/PrintHtmlDiff.java b/tools/preload/PrintHtmlDiff.java
new file mode 100644
index 0000000..b101c85
--- /dev/null
+++ b/tools/preload/PrintHtmlDiff.java
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.PrintStream;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Prints HTML containing removed and added files.
+ */
+public class PrintHtmlDiff {
+
+ private static final String OLD_PRELOADED_CLASSES
+ = "old-preloaded-classes";
+
+ public static void main(String[] args) throws IOException,
+ ClassNotFoundException {
+ Root root = Root.fromFile(args[0]);
+
+ BufferedReader oldClasses = new BufferedReader(
+ new FileReader(OLD_PRELOADED_CLASSES));
+
+ // Classes loaded implicitly by the zygote.
+ Set<LoadedClass> zygote = new HashSet<LoadedClass>();
+ for (Proc proc : root.processes.values()) {
+ if (proc.name.equals("zygote")) {
+ for (Operation op : proc.operations) {
+ zygote.add(op.loadedClass);
+ }
+ break;
+ }
+ }
+
+ Set<LoadedClass> removed = new TreeSet<LoadedClass>();
+ Set<LoadedClass> added = new TreeSet<LoadedClass>();
+
+ for (LoadedClass loadedClass : root.loadedClasses.values()) {
+ if (loadedClass.preloaded && !zygote.contains(loadedClass)) {
+ added.add(loadedClass);
+ }
+ }
+
+ String line;
+ while ((line = oldClasses.readLine()) != null) {
+ line = line.trim();
+ LoadedClass clazz = root.loadedClasses.get(line);
+ if (clazz != null) {
+ added.remove(clazz);
+ if (!clazz.preloaded) removed.add(clazz);
+ }
+ }
+
+ PrintStream out = System.out;
+
+ out.println("<html><body>");
+ out.println("<style>");
+ out.println("a, th, td, h2 { font-family: arial }");
+ out.println("th, td { font-size: small }");
+ out.println("</style>");
+ out.println("<script src=\"sorttable.js\"></script>");
+ out.println("<p><a href=\"#removed\">Removed</a>");
+ out.println("<a name=\"added\"/><h2>Added</h2>");
+ printTable(out, root.baseline, added);
+ out.println("<a name=\"removed\"/><h2>Removed</h2>");
+ printTable(out, root.baseline, removed);
+ out.println("</body></html>");
+ }
+
+ static void printTable(PrintStream out, MemoryUsage baseline,
+ Iterable<LoadedClass> classes) {
+ out.println("<table border=\"1\" cellpadding=\"5\""
+ + " class=\"sortable\">");
+
+ out.println("<thead><tr>");
+ out.println("<th>Name</th>");
+ out.println("<th>Load Time (us)</th>");
+ out.println("<th>Loaded By</th>");
+ out.println("<th>Heap (B)</th>");
+ out.println("<th>Pages</th>");
+ out.println("</tr></thead>");
+
+ for (LoadedClass clazz : classes) {
+ out.println("<tr>");
+ out.println("<td>" + clazz.name + "</td>");
+ out.println("<td>" + clazz.medianTimeMicros() + "</td>");
+
+ out.println("<td>");
+ Set<String> procNames = new TreeSet<String>();
+ for (Operation op : clazz.loads) procNames.add(op.process.name);
+ for (Operation op : clazz.initializations) {
+ procNames.add(op.process.name);
+ }
+ if (procNames.size() <= 3) {
+ for (String name : procNames) {
+ out.print(name + "<br/>");
+ }
+ } else {
+ Iterator<String> i = procNames.iterator();
+ out.print(i.next() + "<br/>");
+ out.print(i.next() + "<br/>");
+ out.print("...and " + (procNames.size() - 2)
+ + " others.");
+ }
+ out.println("</td>");
+
+ if (clazz.memoryUsage.isAvailable()) {
+ MemoryUsage subtracted
+ = clazz.memoryUsage.subtract(baseline);
+
+ out.println("<td>" + (subtracted.javaHeapSize()
+ + subtracted.nativeHeapSize) + "</td>");
+ out.println("<td>" + subtracted.totalPages() + "</td>");
+ } else {
+ for (int i = 0; i < 2; i++) {
+ out.println("<td>n/a</td>");
+ }
+ }
+
+ out.println("</tr>");
+ }
+
+ out.println("</table>");
+ }
+}
diff --git a/tools/preload/Proc.java b/tools/preload/Proc.java
index 66e04dc..2105021 100644
--- a/tools/preload/Proc.java
+++ b/tools/preload/Proc.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
-import java.util.Collections;
import java.io.Serializable;
/**
@@ -30,11 +28,6 @@
private static final long serialVersionUID = 0;
- /**
- * Default percentage of time to cut off of app class loading times.
- */
- static final int PERCENTAGE_TO_PRELOAD = 75;
-
/** Parent process. */
final Proc parent;
@@ -80,72 +73,11 @@
}
/**
- * Returns the percentage of time we should cut by preloading for this
- * app.
+ * Returns true if this process comes from the zygote.
*/
- int percentageToPreload() {
- return PERCENTAGE_TO_PRELOAD;
- }
-
- /**
- * Returns a list of classes which should be preloaded.
- */
- List<LoadedClass> highestRankedClasses() {
- if (!isApplication() || Policy.isService(this.name)) {
- return Collections.emptyList();
- }
-
- // Sort by rank.
- Operation[] ranked = new Operation[operations.size()];
- ranked = operations.toArray(ranked);
- Arrays.sort(ranked, new ClassRank());
-
- // The percentage of time to save by preloading.
- int timeToSave = totalTimeMicros() * percentageToPreload() / 100;
- int timeSaved = 0;
-
- int count = 0;
- List<LoadedClass> highest = new ArrayList<LoadedClass>();
- for (Operation operation : ranked) {
- if (timeSaved >= timeToSave || count++ > 100) {
- break;
- }
-
- if (!Policy.isPreloadableClass(operation.loadedClass.name)) {
- continue;
- }
-
- if (!operation.loadedClass.systemClass) {
- continue;
- }
-
- highest.add(operation.loadedClass);
- timeSaved += operation.medianExclusiveTimeMicros();
- }
-
- return highest;
- }
-
- /**
- * Total time spent class loading and initializing.
- */
- int totalTimeMicros() {
- int totalTime = 0;
- for (Operation operation : operations) {
- totalTime += operation.medianExclusiveTimeMicros();
- }
- return totalTime;
- }
-
- /**
- * Returns true if this process is an app.
- */
- public boolean isApplication() {
- if (name.equals("com.android.development")) {
- return false;
- }
-
- return parent != null && parent.name.equals("zygote");
+ public boolean fromZygote() {
+ return parent != null && parent.name.equals("zygote")
+ && !name.equals("com.android.development");
}
/**
diff --git a/tools/preload/Root.java b/tools/preload/Root.java
index 949f9b7..0bc29bf 100644
--- a/tools/preload/Root.java
+++ b/tools/preload/Root.java
@@ -46,7 +46,7 @@
final Map<String, LoadedClass> loadedClasses
= new HashMap<String, LoadedClass>();
- final MemoryUsage baseline = MemoryUsage.baseline();
+ MemoryUsage baseline = MemoryUsage.baseline();
/**
* Records class loads and initializations.
diff --git a/tools/preload/WritePreloadedClassFile.java b/tools/preload/WritePreloadedClassFile.java
index b209af0..96c539b 100644
--- a/tools/preload/WritePreloadedClassFile.java
+++ b/tools/preload/WritePreloadedClassFile.java
@@ -24,12 +24,18 @@
import java.util.TreeSet;
/**
- * Writes /frameworks/base/preloaded-classes. Also updates LoadedClass.preloaded
- * fields and writes over compiled log file.
+ * Writes /frameworks/base/preloaded-classes. Also updates
+ * {@link LoadedClass#preloaded} fields and writes over compiled log file.
*/
public class WritePreloadedClassFile {
- public static void main(String[] args) throws IOException, ClassNotFoundException {
+ /**
+ * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us.
+ */
+ static final int MIN_LOAD_TIME_MICROS = 1250;
+
+ public static void main(String[] args) throws IOException,
+ ClassNotFoundException {
if (args.length != 1) {
System.err.println("Usage: WritePreloadedClassFile [compiled log]");
System.exit(-1);
@@ -44,48 +50,64 @@
// Open preloaded-classes file for output.
Writer out = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream(Policy.getPreloadedClassFileName()),
+ new FileOutputStream(Policy.PRELOADED_CLASS_FILE),
Charset.forName("US-ASCII")));
- out.write("# Classes which are preloaded by com.android.internal.os.ZygoteInit.\n");
- out.write("# Automatically generated by /frameworks/base/tools/preload.\n");
- out.write("# percent=" + Proc.PERCENTAGE_TO_PRELOAD
- + ", weight=" + ClassRank.SEQUENCE_WEIGHT
- + ", bucket_size=" + ClassRank.BUCKET_SIZE
- + "\n");
+ out.write("# Classes which are preloaded by"
+ + " com.android.internal.os.ZygoteInit.\n");
+ out.write("# Automatically generated by frameworks/base/tools/preload/"
+ + WritePreloadedClassFile.class.getSimpleName() + ".java.\n");
+ out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n");
+ /*
+ * The set of classes to preload. We preload a class if:
+ *
+ * a) it's loaded in the bootclasspath (i.e., is a system class)
+ * b) it takes > MIN_LOAD_TIME_MICROS us to load, and
+ * c) it's loaded by more than one process, or it's loaded by an
+ * application (i.e., not a long running service)
+ */
Set<LoadedClass> toPreload = new TreeSet<LoadedClass>();
- // Preload all classes that were loaded by at least 2 apps, if both
- // apps run at the same time, they'll share memory.
+ // Preload classes that were loaded by at least 2 processes. Hopefully,
+ // the memory associated with these classes will be shared.
for (LoadedClass loadedClass : root.loadedClasses.values()) {
- if (!loadedClass.isPreloadable()) {
- continue;
- }
-
- Set<String> appNames = loadedClass.applicationNames();
-
- if (appNames.size() > 3) {
+ Set<String> names = loadedClass.processNames();
+ if (shouldPreload(loadedClass) && names.size() > 1) {
toPreload.add(loadedClass);
}
}
- // Try to make individual apps start faster by preloading slowest
- // classes.
+ int initialSize = toPreload.size();
+ System.out.println(initialSize
+ + " classses were loaded by more than one app.");
+
+ // Preload eligable classes from applications (not long-running
+ // services).
for (Proc proc : root.processes.values()) {
- toPreload.addAll(proc.highestRankedClasses());
+ if (proc.fromZygote() && !Policy.isService(proc.name)) {
+ for (Operation operation : proc.operations) {
+ LoadedClass loadedClass = operation.loadedClass;
+ if (shouldPreload(loadedClass)) {
+ toPreload.add(loadedClass);
+ }
+ }
+ }
}
- System.out.println(toPreload.size() + " classes will be preloaded.");
+ System.out.println("Added " + (toPreload.size() - initialSize)
+ + " more to speed up applications.");
- // Make classes that were already loaded by the zygote explicit.
+ System.out.println(toPreload.size()
+ + " total classes will be preloaded.");
+
+ // Make classes that were implicitly loaded by the zygote explicit.
// This adds minimal overhead but avoid confusion about classes not
// appearing in the list.
- addAllClassesFor("zygote", root, toPreload);
+ addAllClassesFrom("zygote", root, toPreload);
for (LoadedClass loadedClass : toPreload) {
- out.write(loadedClass.name);
- out.write('\n');
+ out.write(loadedClass.name + "\n");
}
out.close();
@@ -97,18 +119,26 @@
root.toFile(rootFile);
}
- private static void addAllClassesFor(String packageName, Root root,
- Set<LoadedClass> toPreload) {
+ private static void addAllClassesFrom(String processName, Root root,
+ Set<LoadedClass> toPreload) {
for (Proc proc : root.processes.values()) {
- if (proc.name.equals(packageName)) {
+ if (proc.name.equals(processName)) {
for (Operation operation : proc.operations) {
- // TODO: I'm not sure how the zygote loaded classes that
- // aren't supposed to be preloadable...
- if (operation.loadedClass.isPreloadable()) {
+ boolean preloadable
+ = Policy.isPreloadable(operation.loadedClass);
+ if (preloadable) {
toPreload.add(operation.loadedClass);
}
}
}
}
}
+
+ /**
+ * Returns true if the class should be preloaded.
+ */
+ private static boolean shouldPreload(LoadedClass clazz) {
+ return Policy.isPreloadable(clazz)
+ && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS;
+ }
}
diff --git a/tools/preload/loadclass/LoadClass.java b/tools/preload/loadclass/LoadClass.java
index 471cc84..a71b6a8 100644
--- a/tools/preload/loadclass/LoadClass.java
+++ b/tools/preload/loadclass/LoadClass.java
@@ -35,7 +35,11 @@
if (args.length > 0) {
try {
+ long start = System.currentTimeMillis();
Class.forName(args[0]);
+ long elapsed = System.currentTimeMillis() - start;
+ Log.i("LoadClass", "Loaded " + args[0] + " in " + elapsed
+ + "ms.");
} catch (ClassNotFoundException e) {
Log.w("LoadClass", e);
return;
diff --git a/tools/preload/preload.ipr b/tools/preload/preload.ipr
index f78bf76..0c9621c 100644
--- a/tools/preload/preload.ipr
+++ b/tools/preload/preload.ipr
@@ -25,7 +25,28 @@
<option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
</component>
<component name="CodeStyleSettingsManager">
- <option name="PER_PROJECT_SETTINGS" />
+ <option name="PER_PROJECT_SETTINGS">
+ <value>
+ <ADDITIONAL_INDENT_OPTIONS fileType="java">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="xml">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ </value>
+ </option>
<option name="USE_PER_PROJECT_SETTINGS" value="false" />
</component>
<component name="CompilerConfiguration">
@@ -405,6 +426,7 @@
</component>
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Perforce" />
+ <mapping directory="/Volumes/Android/donut/frameworks/base" vcs="Git" />
</component>
<component name="VssConfiguration">
<option name="CLIENT_PATH" value="" />
diff --git a/tools/preload/sorttable.js b/tools/preload/sorttable.js
new file mode 100644
index 0000000..25bccb2
--- /dev/null
+++ b/tools/preload/sorttable.js
@@ -0,0 +1,493 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ makeSortable: function(table) {
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backwards compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ // work through each column and calculate its type
+ headrow = table.tHead.rows[0].cells;
+ for (var i=0; i<headrow.length; i++) {
+ // manually override the type with a sorttable_type attribute
+ if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) { override = mtch[1]; }
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
+ }
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = i;
+ headrow[i].sorttable_tbody = table.tBodies[0];
+ dean_addEvent(headrow[i],"click", function(e) {
+
+ if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted',
+ 'sorttable_sorted_reverse');
+ this.removeChild(document.getElementById('sorttable_sortfwdind'));
+ sortrevind = document.createElement('span');
+ sortrevind.id = "sorttable_sortrevind";
+ sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴';
+ this.appendChild(sortrevind);
+ return;
+ }
+ if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted_reverse',
+ 'sorttable_sorted');
+ this.removeChild(document.getElementById('sorttable_sortrevind'));
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾';
+ this.appendChild(sortfwdind);
+ return;
+ }
+
+ // remove sorttable_sorted classes
+ theadrow = this.parentNode;
+ forEach(theadrow.childNodes, function(cell) {
+ if (cell.nodeType == 1) { // an element
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ });
+ sortfwdind = document.getElementById('sorttable_sortfwdind');
+ if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
+ sortrevind = document.getElementById('sorttable_sortrevind');
+ if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
+
+ this.className += ' sorttable_sorted';
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾';
+ this.appendChild(sortfwdind);
+
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ row_array = [];
+ col = this.sorttable_columnindex;
+ rows = this.sorttable_tbody.rows;
+ for (var j=0; j<rows.length; j++) {
+ row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
+ }
+ /* If you want a stable sort, uncomment the following line */
+ //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+ /* and comment out this one */
+ row_array.sort(this.sorttable_sortfunction);
+
+ tb = this.sorttable_tbody;
+ for (var j=0; j<row_array.length; j++) {
+ tb.appendChild(row_array[j][1]);
+ }
+
+ delete row_array;
+ });
+ }
+ }
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.tBodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ reverse: function(tbody) {
+ // reverse the rows in a tbody
+ newrows = [];
+ for (var i=0; i<tbody.rows.length; i++) {
+ newrows[newrows.length] = tbody.rows[i];
+ }
+ for (var i=newrows.length-1; i>=0; i--) {
+ tbody.appendChild(newrows[i]);
+ }
+ delete newrows;
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a[0] and b[0] */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+ sort_alpha: function(a,b) {
+ if (a[0]==b[0]) return 0;
+ if (a[0]<b[0]) return -1;
+ return 1;
+ },
+ sort_ddmm: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+ sort_mmdd: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+ var script = document.getElementById("__ie_onload");
+ script.onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ sorttable.init(); // call the onload handler
+ }
+ };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
+
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d8a03a9..27755ed9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -960,7 +960,7 @@
*
* If this MulticastLock is not reference-counted, the first call to
* {@code release} (after the radio was multicast locked using
- * {@linke #acquire}) will unlock the multicast, and subsequent calls
+ * {@link #acquire}) will unlock the multicast, and subsequent calls
* will be ignored.
*
* Note that if any other Wifi Multicast Locks are still outstanding
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 083cda3..fa24a98 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -39,6 +39,7 @@
import android.util.Config;
import android.app.Notification;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothA2dp;
import android.content.ContentResolver;
@@ -49,6 +50,7 @@
import java.util.List;
import java.util.ArrayList;
+import java.util.Set;
import java.net.UnknownHostException;
/**
@@ -645,10 +647,10 @@
private void checkIsBluetoothPlaying() {
boolean isBluetoothPlaying = false;
- List<String> connected = mBluetoothA2dp.listConnectedSinks();
+ Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
- for (String address : connected) {
- if (mBluetoothA2dp.getSinkState(address) == BluetoothA2dp.STATE_PLAYING) {
+ for (BluetoothDevice device : connected) {
+ if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
isBluetoothPlaying = true;
break;
}